pax_global_header00006660000000000000000000000064150710263660014520gustar00rootroot0000000000000052 comment=fdd88d6f077a2da6e33c81b56dbe3967224917f4 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/000077500000000000000000000000001507102636600204025ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.codespell_ignore_lines000066400000000000000000000000771507102636600251160ustar00rootroot00000000000000 * (fr) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.flake8000066400000000000000000000010671507102636600215610ustar00rootroot00000000000000[flake8] per-file-ignores = iotas/application.py:E402 iotas/category_list_model.py:E402 iotas/editor.py:E402 iotas/editor_text_view.py:E402 iotas/focus_mode_helper.py:E402 iotas/markdown_render_view.py:E402 iotas/nextcloud_sync_worker.py:E402 iotas/preferences_dialog.py:E402 iotas/text_utils.py:E402 tests/test_exporter.py:E402 max-line-length = 100 extend-ignore = # See https://github.com/PyCQA/pycodestyle/issues/373 E203, exclude = third-party/, .git, build/, __pycache__/, _build/, .venv, iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.gitignore000066400000000000000000000001201507102636600223630ustar00rootroot00000000000000/build /.flatpak-builder __pycache__ /.mypy_cache *.o /**/*.swp /*~ /.*.sw[nop] iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.gitlab-ci.yml000066400000000000000000000021061507102636600230350ustar00rootroot00000000000000include: - project: "GNOME/citemplates" file: "flatpak/flatpak_ci_initiative.yml" - component: gitlab.gnome.org/GNOME/citemplates/release-service@master inputs: dist-job-name: "flatpak" tarball-artifact-path: "${TARBALL_ARTIFACT_PATH}" variables: FLATPAK_MODULE: "iotas" TARBALL_ARTIFACT_PATH: ".flatpak-builder/build/${FLATPAK_MODULE}/_flatpak_build/meson-dist/${CI_PROJECT_NAME}-${CI_COMMIT_TAG}.tar.xz" flake8: image: python:3.11 script: - pip install flake8 - flake8 black: image: python:3.11 script: - pip install black - black --check --diff . codespell: image: python:3.11 script: - pip install codespell tomli - codespell mypy: image: python:3.11 script: - pip install mypy types-requests - mypy flatpak: extends: ".flatpak" variables: MANIFEST_PATH: "build-aux/flatpak/org.gnome.World.Iotas.Devel.json" MESON_ARGS: "-Dprofile=Devel" RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo" APP_ID: "org.gnome.World.Iotas" BUNDLE: "org.gnome.World.Iotas.Devel.flatpak" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.gitlab/000077500000000000000000000000001507102636600217225ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.gitlab/issue_templates/000077500000000000000000000000001507102636600251305ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.gitlab/issue_templates/Bug.md000066400000000000000000000012331507102636600261660ustar00rootroot00000000000000 ### Describe the problem ### Steps to reproduce ### Environment - Iotas version: - Package source: - Desktop environment: - Distribution: ### Logs iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.gitlab/issue_templates/Default.md000066400000000000000000000003211507102636600270320ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/.gitlab/issue_templates/Feature Request.md000066400000000000000000000007611507102636600304620ustar00rootroot00000000000000 ### Feature summary iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/CHANGELOG.md000066400000000000000000001022211507102636600222110ustar00rootroot00000000000000# Changelog All notable changes will be documented in this file, the format for which is based on [Keep a Changelog](https://keepachangelog.com/). Higher level changes are tracked in the [AppStream](https://gitlab.gnome.org/World/iotas/-/blob/main/data/org.gnome.World.Iotas.metainfo.xml.in.in). ## [0.12.1] - 2025-10-06 ### Fixed - A crash exporting into the flatpak sandbox (#239) ## [0.12.0] - 2025-10-02 ### Added - Displaying in markdown render and exports images attached on the server (#132) - Ability to start sync onboarding from the data section of the preferences (#232) ### Changed - Keyboard shortcut dialog updated to Adw.ShortcutsDialog - Stopped regeneration of excerpt while editing - Consolidated to single CSS file using media queries for dark style and high contrast - Switched to automatic resource for CSS - Changed to source font names from Adw.StyleManager - Brazilian Portuguese translation update by Juliano de Souza Camargo (@JulianoSC) - British English translation updated by Bruce Cowan (@suborbitalpigeon) - Chinese translation update by Luming Zh (@flywater) - Georgian translation update by Ekaterine Papava (papava.e@gtu.ge) - Occitan translation update by Quentin Pagès (@Mejans) - Russian translation update by Artur S0 (arturios05@bk.ru) - Slovenian translation update by Martin Srebotnjak (@filmsi) - Swedish translation update by Anders Jonsson (@ajonsson) - Turkish translation update by Sabri Ünal (@yakushabb) - Ukrainian translation update by Yuri Chornoivan (@yurchor) ### Fixed - Some ellipses not using the proper character by Philipp Kiemle (@daPhipz) ## [0.11.5] - 2025-09-16 ### Added - An in-memory list of recent known ETags is added for each note in an attempt to avoid the false conflicts potentially caused by infrastructure between Iotas and the API ignoring the Cache-Control header (#223) - Hungarian translation by Balázs Meskó (@meskobalazs) ### Changed - Switched to GNOME platform v49 - Romanian translation update by Antonio Marin (@libre) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Any changes made in editor in the last second before exit not being stored - Scroll and expanded state of list search results regularly discarded. Now when possible the scroll position and older notes will be shown across updates, eg. returning from editor, receiving updates etc. - Duplicate notes in list resulting from a filter cutoffs bug. Could occur on the first day of the month which is also the first day of the week. - Sync request queueing mechanism ## [0.11.4] - 2025-08-25 ### Added - Romanian translation by Antonio Marin (@libre) ### Fixed - False sync conflicts during first session after onboarding to Nextcloud sync (#223) - Unit tests not working on clean systems / non Flatpak builds by Arnaud Ferraris (@a-wai) ## [0.11.3] - 2025-08-21 ### Added - Toast notification when note currently being edited is deleted on the server. This adds to the existing behaviour which bumps out to the index. ### Changed - Switched editor background background colours to use the Adwaita variables instead of local definitions - Switched Header bar background colours when the window is in the background to use the Adwaita variable (`headervar-backdrop-color`) for light and a mix between that and Adwaita variable `dark-5` for dark - Added unit tests for WebkitPdfExporter and related refactoring - Updated button text to dismiss notification to "Dismiss" (from "Ok") - Simplified running `pytest` - Brazilian Portuguese translation update by Juliano de Souza Camargo (@JulianoSC) - Chinese translation update by Luming Zh (@flywater) - Georgian translation update by Ekaterine Papava (papava.e@gtu.ge) - German translation update by Philipp Kiemle (@daPhipz) - Hebrew translation update by Yaron Shahrabani (@yaron) - Occitan translation update by Quentin Pagès (@Mejans) - Russian translation update by Artur S0 (arturios05@bk.ru) - Russian translation update by David Sultaniiazov (@x1z53) - Slovenian translation update by Martin Srebotnjak (@filmsi) - Swedish translation update by Anders Jonsson (@ajonsson) - Turkish translation update by Sabri Ünal (@yakushabb) - Ukrainian translation update by Yuri Chornoivan (@yurchor) ### Fixed - Keyboard shortcuts `Ctrl + Delete` and `Ctrl + Backspace` in the index for filter resetting were blocking standard text entry shortcuts in eg. the search and category input. Shift has been added to the existing shortcuts. (#220) - High CPU usage after first render when using extended preference to make each note open directly to the formatted view (#176) - Modifier keys in muddled order in keyboard shortcuts help ## [0.11.2] - 2025-07-23 ### Fixed - Sync crash caused by loose assertion (#231) ## [0.11.1] - 2025-05-20 ### Added - Desktop action for "New Note" by Balló György (@City-busz) - D-Bus activatability by Balló György (@City-busz) - Initial unit tests. Low coverage and some are very light on. Steps in the right direction. - Hebrew translation by Yaron Shahrabani (@yaron) ### Changed - Improved error handling in shell search by Balló György (@City-busz) - Simplified action handling by Balló György (@City-busz) - Code quality linting pass with stronger typing enforcement via mypy - CSS deprecations for libadwaita v1.7 - Refactoring for improved testability - Basque translation update by Asier Saratsua Garmendia (@asiersarasua) - Finnish translation update by Jiri Grönroos (@artnay) - Slovenian translation update by Martin Srebotnjak (@filmsi) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Wrong note could be used when jumping to previous note with `Ctrl + L` - Short lived contextual header bars (eg. rename, search, etc) have their right side title buttons hidden but not their left by Balló György (@City-busz) - Link at the start of the first line in a note not being correctly identified for the formatting toolbar/shortcut and ctrl-click to open link in the editor - Race condition failure when starting search from CLI for the shell provider by Balló György (@City-busz) - Preceding markup underscores not being stripped from excerpt ## [0.11.0] - 2025-03-24 ### Added - Ability to jump to other sections of the note being edited via an outline (#188) - Works in both editor and render - Outline generated on demand, no ongoing note structure overhead - Indentation levels are adaptive based on heading levels used in note - Can type to filter (then use `Alt + Enter` to open first match) - Attempts to use locale RTL detection to switch indentation to right side - Accessible via `Ctrl + J` and menu (j for jump) - Shortcut help to open previous note - Basque translation by Asier Saratsua Garmendia (@asiersarasua) - Bulgarian translation by Twlvnn Kraftwerk (@twlvnn) - Finnish translation by Jiri Grönroos (@artnay) - Georgian translation by Ekaterine Papava (papava.e@gtu.ge) - Slovenian translation by Martin Srebotnjak (@filmsi) - Swedish translation by Anders Jonsson (@ajonsson) - Ukrainian translation by Yuri Chornoivan (@yurchor) ### Changed - Clearer wording for onboarding help (#189) - Consistency / HIG tweak to menu strings - Use provided timestamp when launching from shell search results - The editor closes if the note is remotely deleted - Brazilian Portuguese translation update by Alvaro Burns (@alvaroburns) - Chinese translation update by Luming Zh (@flywater) - German translation update by Jürgen Benvenuti (@gastornis) - Italian translation update by Davide Ferracin (@phaerrax) - Occitan translation update by Quentin Pagès (@Mejans) ### Fixed - Can't overwrite previous HTML exports ## [0.10.3] - 2025-03-17 ### Fixed - A PDF export crash for non-English locales (#198) ## [0.10.2] - 2025-02-27 ### Added - `Cache-Control` header to explicitly request no caching in an attempt to reduce false conflict issues (#186) ## [0.10.1] - 2025-02-19 ### Added - Ability to switch to the previous note - Attempts to retain cursor and scroll position - Accessible via `Ctrl + L` ### Changed - Select exported file in file manager after export ### Fixed - Cursor glitching when sitting in top or bottom margin when header bar auto hiding enabled - Keyboard focus issue opening link dialog - Keyboard focus issues after inserting table - Handling of systems with no dictionaries by Balló György (@City-busz) ## [0.10.0] - 2025-01-23 ### Added - Confirmation dialogs for destructive actions - Opening links via ctrl-click in the editor - Shortcuts to move editor focus. `Alt + H` focuses the header bar, `Alt + F` the formatting bar and `Alt + E` the text view. ### Changed - When not pinned the note list sidebar now behaves as an overlay - Both the header and formatting bars in the editor are now overlays. This avoids having the note text move when the header bar hides. - Using `Alt + ←` in the editor now moves the current word/selection left. This brings consistency with the other alt + arrow key shortcuts for moving text. `ESC` can be used to return to the note list. - Switch editor headerbars to overlays. Avoids buffer text moving during show/hide. - Switch note list sidebar to an overlay (when not pinned) - Switch from revealer notifications to toasts - Use `AdwButtonRow` for export dialog format selection - Refresh sync onboarding dialog with recent widgets - Align editor header bars with libadwaita style - Improve high contrast appearance for the editor and markdown render. The default syntax theme (Monochrome) provides the best high contrast experience. - Note list focus ring no longer consistently shown after keyboard navigation use - Disable editor font size and line length incremental change toasts - Improve accessibility on a number of buttons, by adding tooltips or switching to text buttons - String updates out of GNOME Circle review - Use build in `StrEnum` if available by Arnaud Ferraris (@a-wai) - Switch to target Python v3.11+ - Brazilian Portuguese translation update by Filipe Motta (@Tuba2) - Chinese translation update by Luming Zh (@flywater) - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Occitan translation update by Quentin Pagès (@Mejans) ### Fixed - Preference combo rows not rendering in standard style ## [0.9.5] - 2024-11-15 ### Changed - Include charset header with HTML export when writing UTF8 (#178) ## [0.9.4] - 2024-10-29 ### Fixed - The formatting toolbar hiding the keyboard on mobile by Guido Günther (@guidog) ## [0.9.3] - 2024-10-15 ### Changed - Switch strikethrough shortcut to `Ctrl + Shift + X` - Occitan translation update by Quentin Pagès (@Mejans) ## [0.9.2] - 2024-10-07 ### Added - Logic that attempts to reduce false sync conflicts on flaky connections (#170) - Support for * and + as checkbox list markers ### Fixed - Text such as what_is_a_code_span invoking italics in the editor (#74) ## [0.9.1] - 2024-09-25 ### Changed - Faster note list context switching. Switching between categories, switching in and out of search, and searching itself are all faster. - When inserting a new item in the middle of a simple ordered list the numbers for the remainder of the list are now incremented - A longer timeout is now used for potentially larger syncs: initial import, when there hasn't been a sync in over two weeks and when the prune timestamp is reset - Increase the total note count threshold above which notes are time filtered in the note list (ie. into "older notes") - Increase initial window size ### Fixed - Sidebar selection lost after item selected (when not configured pinned) ## [0.9.0] - 2024-09-18 ### Added - Markdown formatting assistance via a toolbar and keyboard shortcuts - Typing as a trigger for the (optional) editor toolbars hiding - Margin below cursor for when appending at the bottom of the editor - Add atomic undo actions for editor actions: extending lists, tab indenting and checkbox toggling (from render) - Strikethrough markup highlighting in the editor - Excerpt generator updated to show list bullet points ### Changed - Improve editor toolbar hiding upon typing (more reliable and less delay) - Menu theme switcher brought in sync with current styling - Update a set of strings to header capitalisation - Update editor headerbar style - Stronger high contrast demarcation between header bar and editor - Switch to v47 SDK - Migrate to `AdwSpinner` - Switch to target Python v3.9+ - Brazilian Portuguese translation update by Filipe Motta (@Tuba2) - Chinese translation update by Luming Zh (@flywater) - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) ### Fixed - Assisted edits not having atomic undo actions (eg. indenting multiple lines) - Inability to click in the editor directly under header bar - Note list not scrolled to top changing categories - Editor margins and body having a slightly different background colour - Rare crash exiting note ## [0.8.2] - 2024-08-08 ### Changed - Make `Ctrl + F` refocus entry while searching in the editor - Occitan translation update by Quentin Pagès (@Mejans) ### Fixed - Issue editing note contents while searching ## [0.8.1] - 2024-08-07 ### Changed - Minor refactoring towards testability ### Fixed - New notes flagging an extra sync after closing (#161) - Button to show earlier notes in the note list can appear after adding a first note (#163) - Math TeX equations not appearing in HTML exports - Poor handling of a note conflict corner case ## [0.8.0] - 2024-06-06 ### Added - Ability to backup from CLI without closing open window (#151) - `Ctrl + W` shortcut to close window - `F10` shortcut to show menu - Detection and communication of server app likely not installed (#153) - Placeholder text in the editor search entry by Sabri Ünal (@yakushabb) - Chinese translation by Luming Zh (@flywater) ### Changed - Attempt to avoid flash of previous markdown render (#31) - Switch to proper approach (`ngettext`) for countable strings by Sabri Ünal (@yakushabb) - Brazilian Portuguese translation update by Filipe Motta (@Tuba2) - Czech translation update by Jiri Eischmann (@Sesivany) - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Italian translation update by Daniele Verducci (@penguin86) - Occitan translation update by Quentin Pagès (@Mejans) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Generic SSL errors not communicated during onboarding - Being able to open multiple preferences dialogs via keyboard - Directing users to browser too early, potentially resulting in them searching in their browser when eg. a URL typo had occurred - Updating sync interval from setting - Duplicate keyboard shortcut help items ## [0.2.14] - 2024-05-03 ### Changed - Brazilian Portuguese translation update by Filipe Motta (@Tuba2) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Note list crash in search (#149) - Some strings not marked translatable by Sabri Ünal (@yakushabb) ## [0.2.13] - 2024-04-19 ### Added - Explicit timeouts on network requests, configurable via `gsettings` with conservative ten second default - Extended preference and `Ctrl + Shift + L` shortcut to toggle editor line length limit ### Changed - Improve editor line length limiting model - Align render view margins more closely with editor - German translation update by Jürgen Benvenuti (@gastornis) - Occitan translation update by Quentin Pagès (@Mejans) ### Fixed - Ordering issue in the shell search provider (#144) - Crash reauthenticating against Nextcloud (#146) - Shell search provider not exiting when idle (#105) - Jumps in the editor margin values ## [0.2.12] - 2024-04-02 ### Added - Ability to display bottom section of restricted note list via scroll overshoot and touch dragging ### Changed - Considerably faster search in the note list (via FTS search index and only loading top of results for large sets) - Editor search and replace paper cuts - Restore automatically navigating to the first editor search match - Updated Nextcloud onboarding button styles for consistency with eg. export dialog - Brazilian Portuguese translation update by Filipe Motta (@Tuba2) - Czech translation update by Jiri Eischmann (@Sesivany) - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Italian translation update by Daniele Verducci (@penguin86) - Occitan translation update by Quentin Pagès (@Mejans) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) ### Fixed - Ordering issue in the editor when replacing multiple times - Current match being lost in the editor when opening replace - Pressing enter not doing anything useful while searching in the editor - Jumping between search matches in the editor not always scrolling all the way to the match - Scroll position for the first markdown render in the session - Editor minimum width slightly too wide for mobile - Opening new notes in render view when _Open In Formatted View_ extended preference enabled (#142) - `Ctrl + F` while searching in the editor interrupting current search - Replace in the editor not being sequential - Showing replace in the editor losing current search match - Able to make selection in both the editor buffer and search entry simultaneously - Older notes automatically being shown after sync onboarding - Bug with shortcut handling when already searching - Crash in exporter exception handler - AppStream no longer supporting `translatable=no` flagging of strings by Sabri Ünal (@yakushabb) ## [0.2.11] - 2024-03-20 ### Changed - Allow typing while keyboard navigating the note list to append the current search term (once focus has moved away from the search entry) - Improve unsynced changes marker in the editor - Stop note list row title moving laterally for local changes marker - Set links to break on words in render view, attempting to avoid overflow - Attempt to retain cursor position when note being edited is updated from sync - Remove extra spacing at start of note list row by Nokse (@nokse22) - Update icon for sync changes notification - Update to libadwaita v1.5, migrate to `AdwDialog` ### Fixed - Selections being left in the note list sections using tab (#92) - Flickering codeblocks in render view (#138) - Need to relaunch to toggle render view availability - Using preferences from the editor (via keyboard shortcut) ## [0.2.10] - 2024-03-13 ### Fixed - Text cursor placement issue resulting from problematic workaround (#139) ## [0.2.9] - 2024-03-09 ### Added - Exporting to PDF, ODT, HTML (and markdown). In preview, feedback encouraged. - Focus mode (#129) - Italian translation by Daniele Verducci (@penguin86) ### Changed - Improve cold launch startup performance - Make render view loading screen display earlier - Update keyboard shortcuts help - Brazilian Portuguese translation update by Filipe Motta (@Tuba2) - Czech translation update by Jiri Eischmann (@Sesivany) - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Occitan translation update by Quentin Pagès (@Mejans) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) ### Fixed - Alerts being created as a result of attempting to work around a toolkit issue (#135) - Note list keyboard focus could be lost (#134) ## [0.2.8] - 2024-02-23 ### Added - Search and replace in the editor (#119) - Search within markdown render - Automatic editor headerbar hiding - Basic extending of ordered lists (#109) - Sidebar scaling for the desktop - Feedback while loading render engine - Ability to create a note from within another note via `Ctrl + N`, bringing any selection along as the new note's content - `Alt + Enter` keyboard shortcut to open first search result in the note list - Czech translation by Jiri Eischmann (@Sesivany) - Occitan translation by Quentin Pagès (@Mejans) ### Changed - Sync notifications in the note list are now only shown when there are changes - Update and switch symbolic icons by David Lapshin (@daudix) - Port preferences rows to `AdwSwitchRow` by Hari Rana (@TheEvilSkeleton) - A build system future proofing tweak by Hari Rana (@TheEvilSkeleton) - Remove header bar hiding keyboard shortcut - Don't show revealer notification in the note list for every sync, only changes - Use libadwaita defined colours for editor background, remove custom light and dark CSS - Add `word-completion` input hint to the editor text view, which should help for mobile keyboards - Brazilian Portuguese translation update by Filipe Motta (@Tuba2) - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - The shell search provider not closing when idle (#105) - Wrong state sometimes retained clearing editor search - WebKit process not terminated closing the note from render (when configured not to be held in memory) ## [0.2.7] - 2024-01-18 ### Changed - New unique identifier aligning with move into GNOME World - Brazilian Portuguese translation by Filipe Motta (@Tuba2) - German translation update by Jürgen Benvenuti (@gastornis) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) - Turkish translation update by Sabri Ünal (@yakushabb) ## [0.2.6] - 2023-10-31 ### Changed - `Ctrl + F` when already looking at note list search results will focus entry box and select all text - Improve error handling during Nextcloud Notes sign in ### Fixed - Editor not scrolling for newlines (#104) ## [0.2.5] - 2023-10-12 ### Added - Searching of notes from GNOME Shell - Adjustment of font size between fixed and proportional for the markdown render ### Changed - Resync the editor margin background colours with Adwaita (#98) - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Sublists having insufficient vertical space in rendered view ## [0.2.4] - 2023-09-21 ### Added - The ability to automatically expand the sidebar on desktop (optional, enabled by default) - An experiment which, after opting in, provides an extended set of preferences ### Changed - Improvements for keyboard navigation in the sidebar - Notifications are now shown for settings changed via keyboard shortcuts in the editor - For the rendered markdown: - The system document font is now used (#91) - Images no longer have to finish downloading before the view is shown - Images wider than the window are now scaled to fit (#93) - Whether notes are opened in edit or view mode can be now be configured (using an extended preference) (#86) - Using the system monospace font can be configured (using an extended preference) - Switch to SDK v45 (and libadwaita v1.4 widgets) - Bump the default window size - German translation update by Jürgen Benvenuti (@gastornis) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - An issue where the first search in a session could be very slow - Two cases which could result in false sync conflicts - A bug where _Load Older Notes_ would be shown in the note list for tiny collections (#95) ## [0.2.3] - 2023-09-04 ### Added - Editor line length adjustment via `Ctrl + ↑` and `Ctrl + ↓` (#79) - Editor font size adjustment via `Ctrl + -` / `Ctrl + 0` / `Ctrl + +` - Clearing note list context via `Ctrl + Delete` and `Ctrl + Backspace` - Markdown list indentation via `Tab` and `Shift + Tab` ### Changed - Improve editor search match visibility and show a match count (#41) - Tune server sign in flow including URI schema being pre-populated into address input box (#51) - Sync onboarding dialog now displayed until initial sync finishes - Integrate initial transfer from server in batches - Tweak link styling in the markdown render - Trim unneeded files from `GResource` file by Arnaud Ferraris (@a-wai) - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) ### Fixed - Broken keyboard navigation upwards from "older notes" listbox - Markdown list continuation interacting with copy/paste and undo/redo - Older notes always being populated to note list after initial sync - Markdown list continuation bug resulting in double markers ## [0.2.2] - 2023-08-01 ### Added - Optional and experimental maths equation support into markdown rendering (#5) ### Changed - More graceful handling of Nextcloud Notes sync issues (#69) - Tidy context-click menu in the markdown render (#75) - German translation update by Jürgen Benvenuti (@gastornis) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) ### Fixed - A crash entering search under specific conditions ## [0.2.1] - 2023-07-16 ### Fixed - Crash adding a note after selecting a category in the sidebar (#73) ## [0.2.0] - 2023-07-15 ### Added - Ability to return to note list via mouse back button ### Changed - Sizeable internal cleanup and translation improvement - Rename "The Rest" to "Older Notes" - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Category ordering in the sidebar and category selection - CRLF line breaks not displaying correctly in the note list excerpts (#68) - Crash long pressing a word on mobile with spell checking disabled (#70) - Disabling spellcheck ignored until restart - Version setting in backend schema update mechanism ## [0.1.16] - 2023-05-08 ### Added - Support for the read-only property from Nextcloud Notes - Support to use the file extension preference from the server for backups - Some styling for tables in the markdown render - Nextcloud Notes API version check ### Changed - Server offline indicator becomes a banner - Improve naming of action to toggle rendered markdown view - French translation update by Irénée Thirion (@rene-coty) - Turkish translation update by Sabri Ünal (@yakushabb) ## [0.1.15] - 2023-05-03 ### Fixed - Markdown render task list display issues (including checked status in subtasks and extra spacing) ## [0.1.14] - 2023-04-30 ### Added - Accessing spelling suggestions via long touch on mobile - Improved inline code block appearance in lists ### Changed - Default to retaining WebKitGTK in memory between uses - Switch to SDK v44 ### Fixed - Rendering of block level elements in task list items (#60) - Long lines in code blocks overflowing their container in the rendered markdown ## [0.1.13] - 2023-04-11 ### Fixed - Crash deleting note from editor ## [0.1.12] - 2023-04-05 ### Added - Ability to select notes from the list then delete, favourite or change category - Type to search in the note list (#49) - Button to clear category, in category header bar ### Changed - Don't update note last modified timestamp for category changes - Note list keyboard focus tweaks to prevent unexpected scrolling - French translation update by Irénée Thirion (@rene-coty) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) ### Fixed - Sync not starting after manual unlocking of keyring (#54) - Launching a second instance, from eg. the CLI, breaking the first (#53) - Note list selected row borders not matching their section borders on mobile - Cancelling note list category change via revert button - Sidebar top level categories sometimes incorrectly being identified as sub-categories ## [0.1.11] - 2023-03-28 ### Added - Tree view for sidebar when sub-categories are in use - Category labels in the note list - Basic support for servers using self-signed certificates ### Changed - Improve keyboard navigation in the sidebar - Improve filtering in category dropdown (no longer only matching from the start) - Substitute markdown check marks with special characters in note excerpts - Account for header markdown when removing title from note excerpt - Switch base language to American English and add British English translation - Remove workaround when displaying the note list popup on touch devices - Rename "All" to "All notes" (in sidebar and window title) - Trim note list category label style options and consolidate label colour - Reorder preferences to help dropdowns display on mobile - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Notes losing the category they're created in, when logged in - Swipe back to note list interfering with cursor manipulation on touch devices - Crash on platforms not providing the FreeDesktop.org setting via D-Bus - Refresh menu item visible when not logged in ## [0.1.10] - 2023-03-09 ### Added - Initial support for categories (with more coming soon) (#2) - Backup and restoration (via the CLI, for when not signed into Nextcloud) - Reintegration of titles and categories sanitised by the server - Local sanitisation of titles ### Changed - Improve preferences layout - French translation update by Irénée Thirion (@rene-coty) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Icon background black under KDE (#44) - Nextcloud signout showing when sync not established ## [0.1.9] - 2023-02-15 ### Added - Searching within notes - A simple fullscreen mode (keyboard-only access for now) - The ability to hide the headerbar in the editor for a minimised view (keyboard-only access for now) - Preference to toggle use of monospace font - Dutch translation by Heimen Stoffels (@Vistaus) ### Changed - French translation update by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) - Turkish translation update by Sabri Ünal (@yakushabb) ### Fixed - Cursor not always placed at the beginning of the loaded note ## [0.1.8] - 2023-02-02 ### Added - Animated transition between mobile and desktop layouts in the note list by Adrien Plazas (@aplazas) - French translation by Irénée Thirion (@rene-coty) - German translation update by Jürgen Benvenuti (@gastornis) ### Changed - Update about dialog to `AdwAboutWindow` ### Fixed - Note list horizontal margin not retained at transition point between mobile and desktop layouts by Adrien Plazas (@aplazas) - Wrong transition type between note list and editor ## [0.1.7] - 2022-11-10 ### Added - Font family for editor synced to system monospace font - Spanish translation update by Óscar Fernández Díaz (@oscarfernandezdiaz) - Turkish translation update by Sabri Ünal (@yakushabb) ### Changed - Greatly improve hinting for translators ## [0.1.6] - 2022-11-07 ### Added - Accommodating for markdown headings when syncing first line of note into title - Creating new note from CLI ### Fixed - Under Phosh the keyboard appearing upon returning to the note list from the markdown render view (#33) - Crash extending markdown lists containing links - Crash copy and pasting lists with links - Spelling mistakes flagged in markdown code blocks, links, etc (#32) ## [0.1.5] - 2022-11-02 ### Added - Initial markdown support, including: - Rendered markdown view - Syntax highlighting - Syntax themes - Task list support including toggling items from rendered view (which directly sync to server) - Scroll position matching between views (approximate) - Changes from server update into rendered view - Ability to disable markdown features - Further markers into list continuation support ### Change - Sync up with GtkSourceView dark background colour change - Custom user agent for Nextcloud Notes API calls - Extra logging for API calls ### Fixed - Note could be shown twice in list (#20) ## [0.1.4] - 2022-08-11 ### Added - Startup notification - German translation by Jürgen Benvenuti (@gastornis) - Turkish translation by Sabri Ünal (@yakushabb) ### Changed - Various misc. tidy ### Fixed - Copy and paste merging problem with spelling enabled - Task lists not continuing after checked task ## [0.1.3] - 2022-08-11 ### Added - Basic spell checking ### Changed - Update icon by Sam Hewitt (@snwh) - To `main` branch, from `master` ## [0.1.2] - 2022-07-28 ### Added - Basic keyboard navigation in the note list (#3, #18) - Help for missing Secret Service - Russian translation by Yaroslav Pronin (@proninyaroslav) ### Fixed - Case where no notes were shown on initial sync from server if all notes fell into "the rest" (older than the preceding month) by Yaroslav Pronin (@proninyaroslav) (#21) ## [0.1.1] - 2022-04-10 ### Added - Continuation of basic markdown lists - Spanish translation by Óscar Fernández Díaz (@oscarfernandezdiaz) ### Fixed - Crash in sync RFC2822 date handling - Title edits not getting immediately synced ## [0.1.0] - 2022-04-03 ### Added - Initial release iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/LICENSE000066400000000000000000001043731507102636600214170ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Iotas Copyright (C) 2022 Chris Heywood This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Iotas Copyright (C) 2022 Chris Heywood This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/README.md000066400000000000000000000062701507102636600216660ustar00rootroot00000000000000# Iotas note taking Iotas aims to provide distraction-free note taking via its mobile-first design. ## Featuring - Optional speedy sync with Nextcloud Notes - Offline note editing, syncing when back online - Category editing and filtering - Favourites - Spell checking - Search within the collection or individual notes - Focus mode and optional hiding of the editor header and formatting bars - In preview: export to PDF, ODT and HTML - A convergent design, seeing Iotas as at home on desktop as mobile - Search from GNOME Shell - Note backup and restoration (from CLI, for using without sync) - The ability to change font size and toggle monospace style Writing in markdown is supported but optional, providing - Formatting via toolbar and shortcuts - Syntax highlighting with themes - Formatted render view - The ability to check off task lists from the rendered markdown Slightly more technical details, for those into that type of thing - Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy - There's basic sync conflict detection - Notes are constantly saved - Large note collections are partially loaded to quicken startup - Notes are stored in SQLite, providing for fast search (FTS) without reinventing the wheel. Plain files can be retrieved by making a backup (CLI). ## Install Get it on Flathub ## Issues & contact Please report any bugs you come across in [the usual place](https://gitlab.gnome.org/World/iotas/-/issues). ## FAQ / tips Can be found in the [the fledgling wiki](https://gitlab.gnome.org/World/iotas/-/wikis). ## Development Iotas was conceived in response to the question: what can be used to write simple notes on mobile Linux with fast sync to a self-hosted FLOSS server? It's fairly minimal by design, so changes adding complexity may not be merged. Probably best to drop a note to say hi (in an issue) if you're interested in working on something and don't want to risk wasted effort. Providing a good experience for the current generation of Linux mobile devices is more aligned than a feature-rich desktop app. Iotas follows the [GNOME Code of Conduct](https://conduct.gnome.org) for all communications and contributions. ### Authentication storage Iotas uses the Secret Service to store authentication details for Nextcloud. This is typically handled smoothly by GNOME Keyring but that may not be the case on mobile or other environments. KWallet is [reported](https://gitlab.gnome.org/World/iotas/-/issues/106) to be working as of Iotas v0.2.7. ## Thanks Much was learnt and borrowed from projects Secrets, Feeds, Lollypop, Apostrophe, Fractal, Text Editor, Paper and Nextcloud Notes for Android. Many thanks! ## Why "Iotas"? An iota is a little bit and this app is designed for jotting down little things on little devices. Iota stems from the same Greek word as jot and is commonly used in negative statements eg. "not one iota of …", but we think the word has more to give. Maybe somebody will take note? iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/build-aux/000077500000000000000000000000001507102636600222745ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/build-aux/flatpak/000077500000000000000000000000001507102636600237165ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/build-aux/flatpak/katex.json000066400000000000000000000012631507102636600257270ustar00rootroot00000000000000{ "name" : "katex", "buildsystem": "simple", "build-options": { "env": { "DEST": "/app/share/iotas/media/" } }, "build-commands": [ "mkdir -p ${DEST}/js/", "cp katex.min.js ${DEST}/js/", "mkdir -p ${DEST}/css/web/", "cp katex.min.css ${DEST}/css/web/", "mkdir -p ${DEST}/css/web/fonts/", "cp fonts/*.woff2 ${DEST}/css/web/fonts/" ], "sources": [ { "type": "archive", "url": "https://github.com/KaTeX/KaTeX/releases/download/v0.16.22/katex.tar.gz", "sha256": "055cd79635251419ed908c334582a41dee341d8af05b4c5588277e145127a78f" } ] } org.gnome.World.Iotas.Devel.json000066400000000000000000000040071507102636600316300ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/build-aux/flatpak{ "app-id": "org.gnome.World.Iotas", "runtime": "org.gnome.Platform", "runtime-version": "master", "sdk": "org.gnome.Sdk", "tags" : [ "devel", "development", "nightly" ], "command": "iotas", "finish-args": [ "--device=dri", "--share=ipc", "--socket=fallback-x11", "--share=network", "--socket=wayland", "--talk-name=org.freedesktop.secrets" ], "cleanup" : [ "*.a", "*.la", "/include", "/lib/cmake", "/lib/pkgconfig", "/man", "/share/aclocal", "/share/gtk-doc", "/share/man", "/share/pkgconfig" ], "modules": [ "python3-requirements.json", "katex.json", { "name" : "pandoc", "buildsystem": "simple", "build-commands": [ "cp bin/pandoc /app/bin/pandoc" ], "sources": [ { "type": "archive", "url": "https://github.com/jgm/pandoc/releases/download/3.8.1/pandoc-3.8.1-linux-amd64.tar.gz", "sha256": "2d9086a2d01e7887797e0cc4f07a8fa6008b34f89612dd9214192c0008ab58ab", "only-arches": ["x86_64"] }, { "type": "archive", "url": "https://github.com/jgm/pandoc/releases/download/3.8.1/pandoc-3.8.1-linux-arm64.tar.gz", "sha256": "b333dd83017cd0ca3748146c051034fff4eb0b05677e47f1aea36aa5240fd3b5", "only-arches": ["aarch64"] } ] }, "python3-pytest.json", { "name" : "iotas", "buildsystem" : "meson", "builddir" : true, "config-opts": [ "-Dprofile=development" ], "sources" : [ { "type" : "dir", "path" : "../../" } ] } ] } iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/build-aux/flatpak/python3-pytest.json000066400000000000000000000026631507102636600275520ustar00rootroot00000000000000{ "name": "python3-pytest", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pytest\" --no-build-isolation" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", "sha256": "9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", "sha256": "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", "sha256": "e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", "sha256": "539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7" } ] } iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/build-aux/flatpak/python3-requirements.json000066400000000000000000000174731507102636600307520ustar00rootroot00000000000000{ "name": "python3-requirements", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "python3-pygtkspellcheck", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pygtkspellcheck\" --no-build-isolation" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/40/d9/412da520de9052b7e80bfc810ec10f5cb3dbfa4aa3e23c2820dc61cdb3d0/pycairo-1.28.0.tar.gz", "sha256": "26ec5c6126781eb167089a123919f87baa2740da2cca9098be8b3a6b91cc5fbc" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/38/b0/35926bad6885fb7bc24aa7e1b45e6d86540c6c57ee4abc4fed1ef58d4ec0/pyenchant-3.3.0-py3-none-any.whl", "sha256": "3da00b1d01314d85aac733bb997415d7a3e875666dc81735ddcf320aa36b7a70" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/cf/71/90c0650485f40a684f54f09fd31aa03158af7f72129fd2089b67b4daa6d0/pygobject-3.54.3.tar.gz", "sha256": "a8da09134a0f7d56491cf2412145e35aa74e91d760e8f337096a1cda0b92bae7" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/85/d4/610e9b4be60bac8f5a155a9553a982c3462a6b3eb117e9903f59e9389fac/pygtkspellcheck-5.0.3-py3-none-any.whl", "sha256": "5bd6fb3bdfcb3ce13825535ba6f1dc5d2e07a3e5d87d3034d8478d8bc884902c" } ] }, { "name": "python3-requests", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"requests\" --no-build-isolation" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", "sha256": "f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", "sha256": "6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", "sha256": "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", "sha256": "2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", "sha256": "e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc" } ] }, { "name": "python3-markdown-it-py", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"markdown-it-py\" --no-build-isolation" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", "sha256": "87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", "sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" } ] }, { "name": "python3-linkify-it-py", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"linkify-it-py\" --no-build-isolation" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", "sha256": "6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", "sha256": "db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5" } ] }, { "name": "python3-mdit-py-plugins", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"mdit-py-plugins\" --no-build-isolation" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", "sha256": "87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/fb/86/dd6e5db36df29e76c7a7699123569a4a18c1623ce68d826ed96c62643cae/mdit_py_plugins-0.5.0-py3-none-any.whl", "sha256": "07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", "sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" } ] }, { "name": "python3-pypandoc", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pypandoc\" --no-build-isolation" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/61/06/0763e0ccc81754d3eadb21b2cb86cf21bdedc9b52698c2ad6785db7f0a4e/pypandoc-1.15-py3-none-any.whl", "sha256": "4ededcc76c8770f27aaca6dff47724578428eca84212a31479403a9731fc2b16" } ] } ] } iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/000077500000000000000000000000001507102636600213135ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/gtksourceview-5/000077500000000000000000000000001507102636600243565ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/gtksourceview-5/language-specs/000077500000000000000000000000001507102636600272545ustar00rootroot00000000000000iotas-markdown.lang000066400000000000000000000510141507102636600330000ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/gtksourceview-5/language-specs text/x-markdown *.markdown;*.md;*.mkd <!-- --> .md False False True Revert Changes edit-undo-symbolic True horizontal 12 True 500 _completion folder-symbolic Apply Changes Apply Clear and Apply eraser3-symbolic True 0 0 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/editor.ui000066400000000000000000000357401507102636600235660ustar00rootroot00000000000000
theme
fontsize
Focus Mode editor.focus-mode
Find and Replace… editor.enter-search Jump To… editor.show-outline
Edit Title… editor.rename Change Category… editor.edit-category Delete editor.delete-note
Export… editor.export-note
True 0 0
iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/editor_rename_header_bar.ui000066400000000000000000000043511507102636600272430ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/editor_search_entry.ui000066400000000000000000000017631507102636600263320ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/editor_search_header_bar.ui000066400000000000000000000121261507102636600272400ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/export_dialog.ui000066400000000000000000000334671507102636600251440ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/first_start_page.ui000066400000000000000000000060631507102636600256340ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/font_size_selector.ui000066400000000000000000000035301507102636600261700ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/formatting_header_bar.ui000066400000000000000000000227201507102636600266000ustar00rootroot00000000000000
Horizontal Rule format.horizontal-rule Quote format.quote Code format.code Table format.table
Level 1 format.heading-1 Level 2 format.heading-2 Level 3 format.heading-3 Level 4 format.heading-4 Remove format.heading-remove
iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/index.ui000066400000000000000000000211021507102636600233720ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/index_menu_button.ui000066400000000000000000000034151507102636600260200ustar00rootroot00000000000000
theme
Sync with Nextcloud Notes win.start-nextcloud-signin action-disabled Refresh win.refresh action-disabled
Preferences app.settings Keyboard Shortcuts app.shortcuts About Iotas app.about
iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/index_note_list.ui000066400000000000000000000246441507102636600254700ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/index_row.ui000066400000000000000000000056471507102636600243010ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/index_search_header_bar.ui000066400000000000000000000023171507102636600270620ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/keyboard_shortcuts_dialog.ui000066400000000000000000000400471507102636600275310ustar00rootroot00000000000000 Index <Ctrl>N Create New Note F9 Show Sidebar <Shift>Delete Delete Note Up Move Up List Down Move Down List <Ctrl>S Start Selection <Ctrl>F Search <Alt>Return Open First Search Result <Ctrl><Shift>Delete Reset Filter Editor F2 Edit Title <Ctrl>E Change Category <Ctrl>D Toggle Markdown Render <Ctrl><Shift>S Export <Ctrl>J Jump to Section <Ctrl>N Create New Note Including Selection <Ctrl>Z Undo Typing <Ctrl><Shift>Z Redo Typing <Ctrl>period Insert Emoji <Alt>E Focus Text View <Alt>H Focus Header Bar <Alt>F Focus Formatting Bar Formatting <Ctrl>B Bold <Ctrl>I Italic <Ctrl>1 7 Heading <Ctrl>U Unordered List <Ctrl>O Ordered List <Alt>C Checkbox <Ctrl>T Toggle Checkbox <Ctrl>K Link <Ctrl><Shift>C Code <Ctrl><Shift>X Strikethrough <Ctrl><Shift>R Horizontal Rule <Ctrl><Shift>Q Quote <Ctrl><Shift>T Table Editor Search <Ctrl>F Search <Ctrl>H Replace <Ctrl>G Next Match <Ctrl><Shift>G Previous Match Editor Appearance <Ctrl><Shift>F Focus Mode <Ctrl>Up Increase Line Length <Ctrl>Down Decrease Line Length <Ctrl>plus Increase Font Size <Ctrl>minus Decrease Font Size General F11 Toggle Fullscreen <Ctrl>comma Show Preferences <Ctrl>question Show Shortcuts <Ctrl>L Open Previous Note Escape Go Back <Ctrl>Q Quit iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/link_dialog.ui000066400000000000000000000035321507102636600245460ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/meson.build000066400000000000000000000007341507102636600240760ustar00rootroot00000000000000glade_conf = configuration_data() glade_conf.set('PACKAGE_URL', website) glade_conf.set('DATA_DIR', pkgdatadir) glade_conf.set('LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale')) glade_conf.set('APPID', app_id) glade_conf.set('VERSION', iotas_version + version_suffix) glade_conf.set('CONTRIBUTORS', contributors) glade_conf.set('TRANSLATORS', translators) glade_conf.set('authorfullname', authorfullname) glade_conf.set('prettyname', prettyname) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/nextcloud_login_dialog.ui000066400000000000000000000217521507102636600270120ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/outline_dialog.ui000066400000000000000000000114401507102636600252650ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/preferences_dialog.ui000066400000000000000000000315151507102636600261140ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/render_search_header_bar.ui000066400000000000000000000045071507102636600272350ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/selection_header_bar.ui000066400000000000000000000053471507102636600264210ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/sidebar.ui000066400000000000000000000034401507102636600237010ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/sidebar_row.ui000066400000000000000000000035361507102636600245760ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/style.css000066400000000000000000000141441507102636600236060ustar00rootroot00000000000000:root { --editor-headers-backdrop: var(--headerbar-backdrop-color); } @media (prefers-color-scheme: dark) { :root { /* As view-bg-color is being used for header bar background a darker tint than * headerbar-backdrop-color is desirable as the header backdrop background to prevent the * header becoming lighter as it goes into backdrop. */ --editor-headers-backdrop: color-mix(in srgb, var(--headerbar-backdrop-color) 75%, var(--dark-5)); } } #Sections, box .index-section-title, box image.index-section, box #NotesListBox { transition-duration: 200ms; } #Sections.small { margin: 12px 0 12px 0; } #Sections:not(small) { margin: 24px 12px 24px 12px; } box.small .index-section-title { margin-left: 18px; margin-bottom: 6px; margin-top: 0px; } box:not(small) .index-section-title { margin-bottom: 10px; margin-top: 10px; } box.small image.index-section { margin-bottom: 5px; } box.small #NotesListBox { border-radius: 0px; border-top: none; border-left: none; border-right: none; } box.small #NotesListBox row { border-radius: 0px; } .editor { background-color: var(--view-bg-color); } .editor-textview { line-height: 1.4; background-color: inherit; } button.note-title-header label:hover { color: color-mix(in srgb, var(--window-fg-color) 70%, transparent); } button.note-title-header { background: none; } /* Aligning with libadwaita toolbar view raised border style */ #EditorTopBarRevealer { box-shadow: 0 1px var(--headerbar-darker-shade-color); } #EditorTopBarRevealer headerbar { box-shadow: none; background-color: var(--view-bg-color); } #EditorBottomBarRevealer { box-shadow: 0 -1px var(--headerbar-darker-shade-color); } #EditorBottomBarRevealer headerbar { background-color: var(--view-bg-color); } /* Style editor header bars when window doesn't have focus */ #EditorTopBarRevealer headerbar:backdrop { background-color: var(--editor-headers-backdrop); } #EditorBottomBarRevealer headerbar:backdrop { background-color: var(--editor-headers-backdrop); } @media (prefers-contrast: more) { /* Header bar outlines */ #EditorTopBarRevealer { box-shadow: 0 1px var(--headerbar-border-color); } #EditorBottomBarRevealer { box-shadow: 0 -1px var(--headerbar-border-color); } } /* Squat editor bottom bar on mobile */ headerbar.formatting-small { min-height: 0px; } headerbar.formatting-small button { min-height: 20px; } headerbar.formatting-small windowhandle box button { padding-top: 4px; padding-bottom: 4px; } headerbar.formatting-small windowhandle > box { padding-top: 1px; padding-bottom: 1px; } #TablePopover button.on { background-color: color-mix(in srgb, var(--accent-bg-color) 40%, transparent); } #TablePopover grid button.hovering { background-color: color-mix(in srgb, var(--accent-bg-color) 70%, transparent); } #TablePopover box overlay label { color: color-mix(in srgb, var(--window-fg-color) 80%, transparent); font-weight: bold; font-variant-numeric: proportional-nums; font-size: 1.75em; } #OutlineDialog list { border-bottom-left-radius: 0; border-bottom-right-radius: 0; border-top-left-radius: 0; border-top-right-radius: 0; } #OutlineDialog list > row { border-bottom-left-radius: 0; border-bottom-right-radius: 0; border-top-left-radius: 0; border-top-right-radius: 0; } #OutlineDialog headerbar.list-matched { background-color: var(--card-bg-color); } /* The outline dialog uses the Adw.ActionRow prefix and suffix (RTL) for indentation. Here we * remove some undesirable spacing #techdebt */ #OutlineDialog list > row .prefixes { margin-right: 0; } #OutlineDialog list > row box { border-spacing: 0; } window .themeselector { margin: 9px; } window .themeselector checkbutton { padding: 0; min-height: 44px; min-width: 44px; padding: 1px; background-clip: content-box; border-radius: 9999px; box-shadow: inset 0 0 0 1px var(--border-color); } window .themeselector checkbutton.follow:checked, window .themeselector checkbutton.light:checked, window .themeselector checkbutton.dark:checked { box-shadow: inset 0 0 0 2px var(--accent-bg-color); } window .themeselector checkbutton.follow { background-image: linear-gradient(to bottom right, #fff 49.99%, #202020 50.01%); } window .themeselector checkbutton.light { background-color: #fff; } window .themeselector checkbutton.dark { background-color: #202020; } window .themeselector checkbutton radio { -gtk-icon-source: none; border: none; background: none; box-shadow: none; min-width: 12px; min-height: 12px; transform: translate(27px, 14px); padding: 2px; } window .themeselector checkbutton radio:checked { -gtk-icon-source: -gtk-icontheme("object-select-symbolic"); background-color: var(--accent-bg-color); color: var(--accent-fg-color); } label.index-category-pill { font-size: .83333em; border-radius: 4px; margin: 0; padding: 1px 6px; } /* Some (hopefully temporary) handling of the keyboard focus ring. Using a bunch of hard * coded values which line up with Adwaita as of v1.4. * */ window .sidebar-pane listview row.focused { outline: 0 solid transparent; outline-width: 2px; outline-offset: -2px; outline-color: color-mix(in srgb, var(--accent-color) 50%, transparent); } @media (prefers-contrast: more) { /* Using a bunch of hard coded values which line up with Adwaita as of v1.4 */ window .sidebar-pane listview row.focused { outline-color: color-mix(in srgb, var(--accent-color) 80%, transparent); } } /* A temporary fix while using deprecated GtkEntryCompletion. Will potentially have issues outside * of Adwaita. Fixes issue with popup surrounds in dark mode. */ entry.category-selector popover contents { background-color: var(--view-bg-color); } /* Cater for selections still being used for state as part of transitioning away from a past * feature. We're removing selection styling. * TODO move away from using the listbox selections for state */ #Sections row:selected { background-color: transparent; } #Sections row:selected:hover { /* ~ libadwaita/src/stylesheet/widgets/_lists.scss:354 */ background-color: color-mix(in srgb, var(--view-fg-color) 3%, transparent); } iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/table_dialog.ui000066400000000000000000000046411507102636600247020ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/theme_selector.ui000066400000000000000000000057261507102636600253030ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/data/ui/window.ui000066400000000000000000000022131507102636600235740ustar00rootroot00000000000000 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas.doap000066400000000000000000000021211507102636600223620ustar00rootroot00000000000000 Iotas Simple note taking Python GTK 4 Libadwaita Chris Heywood cheywood cheywood iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/000077500000000000000000000000001507102636600215215ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/application.py000066400000000000000000000443571507102636600244130ustar00rootroot00000000000000from gettext import gettext as _ import gi gi.require_version("Adw", "1") from gi.repository import Adw, Gdk, Gio, GLib, GObject, Gtk import logging from typing import Callable, Optional from iotas.attachment_helpers import flush_all_attachments_on_disk from iotas.backup_manager import BackupManager import iotas.const as const from iotas.config_manager import ConfigManager from iotas.database import Database, DbCursor from iotas.migration_assistant import MigrationAssistant from iotas.note_database import NoteDatabase from iotas.preferences_dialog import PreferencesDialog from iotas.nextcloud_sync_worker import NextcloudSyncWorker from iotas.sync_manager import SyncManager from iotas.widgets import load_widgets from iotas.window import Window class Application(Adw.Application): development_mode = const.IS_DEVEL application_id = const.APP_ID def __init__(self, *args) -> None: super().__init__( *args, application_id=self.application_id, flags=Gio.ApplicationFlags.HANDLES_OPEN, resource_base_path="/org/gnome/World/Iotas", register_session=True, ) ConfigManager.set_app_id(const.APP_ID) self.__config_manager = ConfigManager.get_default() self.__add_cli_options() self.__index_category_label_css_provider: Gtk.CssProvider = None style_manager = Adw.StyleManager.get_default() style_manager.connect("notify::dark", lambda _o, _v: self.__apply_css()) style_manager.connect("notify::high-contrast", lambda _o, _v: self.__apply_css()) self.cursors: dict[str, DbCursor] = {} self.__actions: dict[str, Gio.SimpleAction] = {} self.__window: Optional[Adw.ApplicationWindow] = None self.__preferences_dialog: Optional[PreferencesDialog] = None self.__previous_version = "" self.connect("startup", lambda _o: self.__on_startup()) self.connect("activate", lambda _o: self.__on_activate()) self.connect("handle-local-options", self.__on_handle_local_options) self.__config_manager.connect_changed( ConfigManager.INDEX_CATEGORY_STYLE, self.__apply_index_category_label_css, ) def disconnect_nextcloud(self) -> None: """Disconnect from Nextcloud instance and exit.""" if not self.__sync_manager.authenticated: return assert self.__window # mypy self.__sync_manager.sign_out() self.db.delete_all_clean_synced_notes() flush_all_attachments_on_disk() self.__config_manager.nextcloud_username = "" self.__window.close() def do_open(self, files: list[Gio.File], n_files: int, _hint: str) -> None: """Handle opening "files". In this case URI for the temporary handler. :param list[Gio.File] files: Files :param int n_files: Number of files :param str _hint: Hint """ # Note: Iotas' addition of this URI handler is a stopgap measure until the freedesktop # intent system is fleshed out. The handling provided here will be unceremoniously removed # when that system is available and may be removed or modified without notice beforehand; # this is not a stable public interface. if n_files != 1: self.quit() return file = files[0] uri = GLib.Variant("s", file.get_uri()) self.activate_action("create-note-from-uri", uri) def reset_sync_marker(self) -> None: """Resets the timestamp for transfer with Nextcloud Notes.""" self.__sync_manager.reset_marker() def reset_database(self) -> None: """Destroy the database and quit.""" self.db_base.trash() flush_all_attachments_on_disk() self.__config_manager.nextcloud_prune_threshold = 0 self.quit() def apply_style(self) -> None: """Apply style preference.""" manager = Adw.StyleManager.get_default() style = self.__config_manager.style if style == "dark": manager.props.color_scheme = Adw.ColorScheme.FORCE_DARK elif style == "light": manager.props.color_scheme = Adw.ColorScheme.FORCE_LIGHT else: manager.props.color_scheme = Adw.ColorScheme.DEFAULT @GObject.Property(type=bool, default=False) def debug_session(self) -> bool: return self.__debug_session @GObject.Property(type=str) def previous_version(self) -> str: return self.__previous_version @previous_version.setter def set_previous_version(self, value: str) -> None: self.__previous_version = value def __on_startup(self) -> None: """Handle startup.""" Gtk.Application.do_startup(self) Adw.init() self.db_base = Database() self.db = NoteDatabase(self.db_base) self.__sync_manager = SyncManager(self.db) self.__backup_manager = BackupManager(self.db, const.VERSION) self.previous_version = self.__config_manager.last_launched_version migration_assistant = MigrationAssistant(self.db) migration_assistant.migrate() load_widgets() self.__setup_actions() def __on_handle_local_options(self, _obj: GObject.Object, options: GLib.VariantDict) -> int: """Handle options, setup logging.""" options = options.end().unpack() # Print paths before logging is setup and app initialised, for clean output if "display-backup-path" in options: print(BackupManager.get_default_primary_path()) self.quit() return 0 elif "display-ca-file-path" in options: print(NextcloudSyncWorker.CA_CHAIN_FILE) self.quit() return 0 self.__debug_session = "debug-session" in options loglevel = logging.INFO if self.development_mode or self.__debug_session: loglevel = logging.DEBUG for module in ("urllib3", "gtkspellcheck", "markdown_it", "pypandoc"): logging.getLogger(module).setLevel(logging.INFO) logging.basicConfig( format="%(asctime)s | %(module)s | %(levelname)s | %(message)s", datefmt="%H:%M:%S", level=loglevel, ) if "create-backup" in options: self.register() if self.get_property("is-remote"): self.activate_action("create-backup") logging.info("Requesting backup from already running Iotas") logging.info( "Note: backup outcome will be logged from the other process; the return code " "here doesn't reflect the backup result" ) success = True else: success = self.__backup_manager.create_backup( self.__config_manager.nextcloud_sync_configured, self.__config_manager.backup_note_extension, ) self.quit() return int(not success) elif "restore-backup" in options: self.register() if self.get_property("is-remote"): logging.error( "Please quit the running instance of Iotas before restoring the backup" ) self.quit() success = False else: success = self.__backup_manager.restore_backup( self.__config_manager.nextcloud_sync_configured ) self.quit() return int(not success) elif "quit-running" in options: self.register() if self.get_property("is-remote"): self.activate_action("quit") else: logging.warning("No running instance found") self.quit() return 0 elif "new-note" in options: # Application needs to be registered to send action if remote instance self.register() self.activate_action("create-note") elif "open-note" in options: # Application needs to be registered to send action if remote instance self.register() note_id = GLib.Variant("u", options["open-note"]) self.activate_action("open-note", note_id) elif "search" in options: # Application needs to be registered to send action if remote instance self.register() term = GLib.Variant("s", options["search"]) self.activate_action("search-from-cli", term) elif "toggle-extended-preferences" in options: self.register() if self.__config_manager.show_extended_preferences: logging.info("Hiding extended preferences") self.__config_manager.show_extended_preferences = False else: logging.info("Showing extended preferences") self.__config_manager.show_extended_preferences = True self.quit() return 0 # Let default option processing continue return -1 def __on_activate(self) -> None: """Handle window activation.""" if not self.__window: self.__create_window() assert self.__window # mypy self.__apply_css() self.apply_style() self.__window.present() def __on_quit(self) -> None: if self.__window: self.__window.cleanup_and_close() def __on_create_note(self) -> None: self.activate() if self.__window: self.__window.activate_action("win.create-note-from-cli") def __on_create_note_from_uri(self, param: GObject.ParamSpec) -> None: logging.info(isinstance(param, GObject.ParamSpec)) self.activate() if self.__window: self.__window.activate_action("win.create-note-from-uri", param), def __on_open_note(self, param: GObject.ParamSpec) -> None: logging.info(isinstance(param, GObject.ParamSpec)) self.activate() if self.__window: self.__window.activate_action("win.open-note", param), def __on_search_from_cli(self, param: GObject.ParamSpec) -> None: logging.info(isinstance(param, GObject.ParamSpec)) self.activate() if self.__window: self.__window.activate_action("win.search-from-cli", param), def __add_cli_options(self) -> None: self.add_main_option( "new-note", ord("n"), GLib.OptionFlags.NONE, GLib.OptionArg.NONE, # Translators: Description, CLI option _("Create a note"), None, ) self.add_main_option( "create-backup", 0, GLib.OptionFlags.NONE, GLib.OptionArg.NONE, # Translators: Description, CLI option _("Create a backup"), None, ) self.add_main_option( "restore-backup", 0, GLib.OptionFlags.NONE, GLib.OptionArg.NONE, # Translators: Description, CLI option _("Restore a backup"), None, ) self.add_main_option( "display-backup-path", 0, GLib.OptionFlags.NONE, GLib.OptionArg.NONE, # Translators: Description, CLI option _("Display backup path"), None, ) self.add_main_option( "display-ca-file-path", 0, GLib.OptionFlags.NONE, GLib.OptionArg.NONE, # Translators: Description, CLI option _("Display path for custom server SSL CA chain file"), None, ) self.add_main_option( "toggle-extended-preferences", 0, GLib.OptionFlags.NONE, GLib.OptionArg.NONE, # Translators: Description, CLI option _("Toggle display of extended preferences in UI"), None, ) self.add_main_option( "quit-running", 0, GLib.OptionFlags.NONE, GLib.OptionArg.NONE, # Translators: Description, CLI option _("Quit any running instance"), None, ) self.add_main_option( "debug-session", ord("d"), GLib.OptionFlags.NONE, GLib.OptionArg.NONE, # Translators: Description, CLI option _("Enable debug logging and functions"), None, ) self.add_main_option( "open-note", 0, GLib.OptionFlags.NONE, GLib.OptionArg.INT, # Translators: Description, CLI option _("Open note by id"), None, ) self.add_main_option( "search", 0, GLib.OptionFlags.NONE, GLib.OptionArg.STRING, # Translators: Description, CLI option _("Search in notes"), None, ) def __setup_actions(self) -> None: def add_action( name: str, method: Callable, shortcut: Optional[str] = None, parameter_type: Optional[GLib.VariantType] = None, ): if parameter_type is None: action = Gio.SimpleAction.new(name) else: action = Gio.SimpleAction.new(name, parameter_type) self.add_action(action) action.connect("activate", method) self.__actions[name] = action if shortcut is not None: self.set_accels_for_action(f"app.{name}", [shortcut]) add_action("about", lambda _o, _p: self.__show_about_dialog()) add_action("quit", lambda _o, _p: self.__on_quit(), "q") add_action("settings", lambda _o, _p: self.__show_preferences_dialog(), "comma") add_action( "create-note", lambda _o, _p: self.__on_create_note(), ) add_action( "create-note-from-uri", lambda _o, param: self.__on_create_note_from_uri(param), None, GLib.VariantType("s"), ) add_action( "open-note", lambda _o, param: self.__on_open_note(param), None, GLib.VariantType("u"), ) add_action( "search-from-cli", lambda _o, param: self.__on_search_from_cli(param), None, GLib.VariantType("s"), ) add_action("create-backup", lambda _o, _p: self.__create_backup()) def __create_window(self) -> None: self.__window = Window(self, self.db, self.__sync_manager) self.add_window(self.__window) def __apply_css(self) -> None: self.__apply_index_category_label_css() def __show_about_dialog(self) -> None: builder = Gtk.Builder() builder.add_from_resource("/org/gnome/World/Iotas/about_dialog.ui") about_dialog = builder.get_object("AboutDialog") about_dialog.present(self.__window) def __show_preferences_dialog(self) -> None: if self.__preferences_dialog is not None: return self.__preferences_dialog = PreferencesDialog() self.__preferences_dialog.connect( "start-onboarding", self.__on_preferences_dialog_start_onboarding ) self.__preferences_dialog.connect("closed", self.__on_preferences_dialog_closed) self.__preferences_dialog.present(self.__window) def __on_preferences_dialog_start_onboarding(self, dialog: PreferencesDialog) -> None: if not self.__preferences_dialog or not self.__window: # mypy return self.__preferences_dialog.close() self.__window.show_login_dialog() def __on_preferences_dialog_closed(self, _dialog: GObject.Object) -> None: if not self.__preferences_dialog: # mypy return self.__preferences_dialog.disconnect_by_func(self.__on_preferences_dialog_start_onboarding) self.__preferences_dialog = None def __create_backup(self) -> None: logging.info("Running remotely requested backup") self.__backup_manager.create_backup( self.__config_manager.nextcloud_sync_configured, self.__config_manager.backup_note_extension, ) def __apply_index_category_label_css(self) -> None: # First pass approach to building this is using a display CSS provider, instead of adding # providers to each label. Presumably this is better, but it's a mess. style_manager = Adw.StyleManager.get_default() category_style = self.__config_manager.index_category_style colour_names = { "blue": {"light": "blue_2", "dark": "blue_5"}, "green": {"light": "green_4", "dark": "green_5"}, "yellow": {"light": "yellow_4", "dark": "yellow_5"}, "orange": {"light": "orange_2", "dark": "orange_5"}, "red": {"light": "red_1", "dark": "red_5"}, "purple": {"light": "purple_2", "dark": "purple_5"}, } if style_manager.get_dark(): style_name = "dark" else: style_name = "light" css = "box label.index-category-pill {" if category_style in ("monochrome", "muted", "none"): css += """ border-color: @insensitive_fg_color; border-width: 1px; border-style: solid;""" else: css += f""" background-color: @{colour_names[category_style][style_name]}; color: @light_1;""" if category_style == "muted": # Matching libadwaita for dimmed/subtitle (non high-contrast, monochrome option is # provides for high contrast) css += "\nopacity: 0.55;" css += "\n}" display = Gdk.Display.get_default() if self.__index_category_label_css_provider is None: self.__index_category_label_css_provider = Gtk.CssProvider() else: Gtk.StyleContext.remove_provider_for_display( display, self.__index_category_label_css_provider ) self.__index_category_label_css_provider.load_from_data(css, -1) Gtk.StyleContext.add_provider_for_display( display, self.__index_category_label_css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION, ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/attachment.py000066400000000000000000000031341507102636600242240ustar00rootroot00000000000000from __future__ import annotations from gi.repository import GObject import os from typing import Optional from urllib.parse import quote class Attachment(GObject.Object): """A note attachment.""" def __init__(self) -> None: super().__init__() self.__note_id = -1 self.__note_remote_id: Optional[int] = None self.__path = "" @GObject.Property(type=int, default=-1) def note_id(self) -> int: return self.__note_id @note_id.setter def set_note_id(self, value: int) -> None: self.__note_id = value @GObject.Property(type=int, default=-1) def note_remote_id(self) -> Optional[int]: return self.__note_remote_id @note_remote_id.setter def set_note_remote_id(self, value: int) -> None: self.__note_remote_id = value @GObject.Property(type=str, default="") def filename(self) -> str: return os.path.basename(self.__path) @GObject.Property(type=str, default="") def path(self) -> str: return self.__path @path.setter def set_path(self, value: str) -> None: self.__path = value @GObject.Property(type=str, default="") def path_quoted(self) -> str: return quote(self.path) def duplicate(self) -> Attachment: """Duplicate attachment. Only the shallow fields are copied; the data on disk is not duplicated. :return: A copy of the attachment :rtype: """ ret = Attachment() ret.note_id = self.note_id ret.note_remote_id = self.note_remote_id ret.path = self.path return ret iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/attachment_helpers.py000066400000000000000000000231161507102636600257500ustar00rootroot00000000000000from gi.repository import GLib from enum import IntEnum, auto from io import BytesIO import logging import os from pathlib import Path from shutil import copyfile from threading import Thread from typing import BinaryIO, NamedTuple, Optional from urllib.parse import quote from markdown_it.token import Token from iotas.attachment import Attachment from iotas.markdown_helpers import ( get_image_attachments_from_note_content, get_image_attachments_from_tokens, filter_image_tokens, ) from iotas.note import Note ATTACHMENT_DATA_SUBPATH = "iotas" ATTACHMENT_DIR_NAME = "attachments" ATTACHMENT_MAX_SIZE_MB = 50 class AttachmentDiskStates(NamedTuple): """Whether attachments exist on disk.""" exists: dict[str, Attachment] """Found on disk""" missing: dict[str, Attachment] """Missing from disk""" class AttachmentsCopyOutcome(IntEnum): """Outcome on attachments copy to disk path run.""" NONE = auto() """There were no attachments to store""" FAILURE = auto() """One or more attachments failed to store""" HAD_MISSING = auto() """One or more attachments were missing on disk""" SUCCESS = auto() """All attachments were successfully copied""" class AttachmentsCopyResults(NamedTuple): """Outcome and stored attachments for copy to disk path run.""" outcome: AttachmentsCopyOutcome """Run outcome""" attachments: list[Attachment] = [] """Attachments which were stored""" def copy_note_attachments(note: Note, path: str, prefix_note_id: bool) -> AttachmentsCopyResults: """Copy note attachments to a directory. :param Note note: Note to work on :param str path: Destination directory :param bool prefix_note_id: Whether to prefix the note id :return: The outcome of the run and attachments which were stored :rtype: AttachmentsCopyResults """ attachments = get_image_attachments_from_note_content(note) if not attachments: return AttachmentsCopyResults(AttachmentsCopyOutcome.NONE) if not os.path.exists(path): try: os.mkdir(path) except OSError as e: logging.warning(f"Failed to create dir '{path}' to save attachments: {e}") return AttachmentsCopyResults(AttachmentsCopyOutcome.FAILURE) note_id_prefix = f"{note.id}." if prefix_note_id else "" had_failure = False had_missing = False stored = [] for attachment in attachments: filename = f"{note_id_prefix}{os.path.basename(attachment.path)}" if not attachment_exists_locally(attachment): logging.warning(f"'{attachment.path}' not available to save") had_missing = True continue dest_path = os.path.join(path, filename) try: copyfile(get_attachment_filesystem_path(attachment), dest_path) except OSError as e: logging.warning(f"Failed to save attachment '{attachment.path}': {e}") had_failure = True else: stored.append(attachment) if had_failure: return AttachmentsCopyResults(AttachmentsCopyOutcome.FAILURE) elif had_missing: return AttachmentsCopyResults(AttachmentsCopyOutcome.HAD_MISSING, stored) else: return AttachmentsCopyResults(AttachmentsCopyOutcome.SUCCESS, stored) def write_attachment_to_disk(attachment: Attachment, data: bytes) -> bool: """Write attachment to disk. Storing to user attachments directory. :param Attachment attachment: Attachment :param bytes data: Attachment data :return: Success :rtype: bool """ path = get_attachment_filesystem_path(attachment) if os.path.exists(path): logging.warning(f"Attachment '{attachment.filename}' already exists for note?") return False try: with open(get_attachment_filesystem_path(attachment), "wb") as f: f.write(data) except OSError as e: logging.warning(f"Failed to write attachment to disk: {e}") return False else: return True def get_attachments_dir() -> str: """Get user attachments directory. :return: Directory :rtype: str """ return os.path.join( GLib.get_user_data_dir(), ATTACHMENT_DATA_SUBPATH, ATTACHMENT_DIR_NAME, ) def get_attachments_on_disk_for_note(note: Note) -> list[Attachment]: """Get the attachments on disk for a note. :param Note note: Note to match :return: Attachments :rtype: list[Attachment] """ attachments = [] path = Path(get_attachments_dir()) prefix = f"{note.id}." # TODO Python 3.13+ remove exception handling try: files = list(path.glob(f"{prefix}*")) except OSError as e: logging.warning(f"Error listing attachments: {e}") else: for file in files: attachment = Attachment() attachment.note_id = note.id attachment.path = file.name[len(prefix) :] attachment.note_remote_id = note.remote_id attachments.append(attachment) return attachments def delete_attachments_for_note(note: Note) -> None: """Delete attachments from disk for note :param Note note: Note to delete for """ for attachment in get_attachments_on_disk_for_note(note): if not attachment_exists_locally(attachment): continue path = get_attachment_filesystem_path(attachment) try: os.remove(path) except OSError as e: logging.warning(f"Failed to delete attachment '{path}': {e}") def get_attachment_disk_states(note: Note, tokens: list[Token]) -> AttachmentDiskStates: """Get whether a note's attachments are stored on disk. :param Note note: Note to check for :param Tokens tokens: Parser tokens to get list of attachments from :return: Whether on disk :rtype: AttachmentDiskStates """ attachments = get_image_attachments_from_tokens(note, tokens) exists = {} missing = {} for attachment in attachments: if attachment_exists_locally(attachment): exists[attachment.path_quoted] = attachment else: missing[attachment.path_quoted] = attachment return AttachmentDiskStates(exists, missing) def get_attachment_filesystem_uri(attachment: Attachment) -> str: """Get attachment filesystem path as URI. :param Attachment attachment: Attachment :return: Path as URI :rtype: str """ return "file://" + quote(get_attachment_filesystem_path(attachment)) def get_attachment_filesystem_path(attachment: Attachment) -> str: """Get attachment filesystem path. :param Attachment attachment: Attachment :return: Path :rtype: str """ filename = f"{attachment.note_id}.{attachment.filename}" return os.path.join( get_attachments_dir(), filename, ) def attachment_exists_locally(attachment: Attachment) -> bool: """Get whether attachment exists on disk. :param Attachment attachment: Attachment :return: Exists :rtype: bool """ return os.path.exists(get_attachment_filesystem_path(attachment)) def get_attachment_file_object(attachment: Attachment) -> Optional[BinaryIO]: """Get attachment file object. :param Attachment attachment: Attachment :return: File object :rtype: BinaryIO, optional """ content = None try: with open(get_attachment_filesystem_path(attachment), "rb") as f: content = f.read() except OSError as e: logging.warning(f"Failed to open attachment: {e}") return None return BytesIO(content) def flush_all_attachments_on_disk() -> None: """Flush all attachments on disk.""" for file in Path(get_attachments_dir()).iterdir(): try: os.remove(file) except OSError as e: logging.warning(f"Error removing attachment '{file}': {e}") def set_attachment_filesystem_uris_on_tokens( tokens: list[Token], new_paths: dict[str, Attachment] ) -> None: """Update image paths in parser tokens to filesystem URIs. :param list[Token] tokens: Parser tokens to update :param dict[str, Attachment] new_paths: Dict with (quoted) existing markup paths, attachments for filesystem URIs """ images = filter_image_tokens(tokens) for img in images: src = img.attrs["src"] if src in new_paths: img.attrs["src"] = get_attachment_filesystem_uri(new_paths[src]) def trim_orphaned_images(note: Note, on_thread: bool) -> None: """Trim images on disk which don't appear in the note. :param Note note: Note to trim for :param bool on_thread: Whether to work on thread """ def work(note: Note) -> None: on_disk_paths = [ get_attachment_filesystem_path(attachment) for attachment in get_attachments_on_disk_for_note(note) ] if on_disk_paths: attachments = get_image_attachments_from_note_content(note) content_paths = [ get_attachment_filesystem_path(attachment) for attachment in attachments ] for path in on_disk_paths: if path not in content_paths: filename = os.path.basename(path) logging.debug( f"Deleting attachment no longer in note '{note.title}': '{filename}'" ) try: os.remove(path) except OSError as e: logging.warning(f"Error deleting attachment '{filename}': {e}") if on_thread: thread = Thread(target=work, args=(note,)) thread.daemon = True thread.start() else: work(note) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/backup_manager.py000066400000000000000000000313141507102636600250340ustar00rootroot00000000000000from gettext import gettext as _ from gi.repository import GLib, GObject import glob import json import logging import os import shutil from typing import Optional from iotas.backup_storage import BackupStorage from iotas.note import Note, DirtyFields from iotas.text_utils import sanitise_path class BackupManager(GObject.Object): DATA_SUBPATH = "iotas" PRIMARY_DIRNAME = "backup" ARCHIVE_DIRNAME = "backup-previous" METADATA_EXTENSION = "iota" EXPORT_SCHEMA_VERSION = "1.0" MAXIMUM_CONTENT_SIZE_MB = 100 def __init__( self, db: BackupStorage, iotas_version: str, storage_dir: Optional[str] = None ) -> None: super().__init__() self.__db = db self.__iotas_version = iotas_version if storage_dir: working_directory = storage_dir else: working_directory = os.path.join(GLib.get_user_data_dir(), self.DATA_SUBPATH) self.__primary_backup_path = os.path.join(working_directory, self.PRIMARY_DIRNAME) self.__archive_backup_path = os.path.join(working_directory, self.ARCHIVE_DIRNAME) self.__file_extension = "md" self.__sync_configured = False def create_backup(self, sync_configured: bool, file_extension: str) -> bool: """Create a backup. :param bool sync_configured: Whether sync is configured :param str file_extension: File extension to use for notes :return: Whether successful :rtype: bool """ self.__sync_configured = sync_configured self.__file_extension = file_extension if not os.path.exists(self.__primary_backup_path): try: os.mkdir(self.__primary_backup_path) except OSError as e: logging.error( f"Failed to create backup directory at {self.__primary_backup_path}: {e}" ) return False if not self.__switch_old_backup_to_archive(): logging.error("Failed to move previous backup to archive path") return False success = True notes = self.__db.get_all_notes(load_content=True) for note in notes: success, content_filename = self.__write_note_content(note) if not success: break meta_filename = f"{content_filename}.{self.METADATA_EXTENSION}" success = self.__write_note_metadata(note, meta_filename) if not success: break if success: logging.info(f"Backup created at {self.__primary_backup_path}") if sync_configured: logging.warning( "Backup restoration isn't possible with Nextcloud Notes sync configured" ) else: logging.error("Backup failed") return success def restore_backup(self, sync_configured: bool) -> bool: """Restore a backup. :param bool sync_configured: Whether sync is configured :return: Whether successful :rtype: bool """ # A fairly light touch has been taken here. Presuming that existing backups are # unmodified/sane restoring to an empty session should be fairly straight forward. # # Some work has been done towards merging into an existing collection and restoring to a # remotely connect session but as they haven't been thoroughly tested yet they're not # exposed. self.__sync_configured = sync_configured if not os.path.exists(self.__primary_backup_path): logging.error(f"No backup exists at {self.__primary_backup_path}") return False file_list = glob.glob( os.path.join(self.__primary_backup_path, f"*.{self.METADATA_EXTENSION}") ) if len(file_list) == 0: logging.error(f"No backup exists at {self.__primary_backup_path}") return False # Notify and quit if attempting to merge a backup into existing notes if self.__db.get_all_notes_count() > 0: logging.error("Backup restoration can only be run when there are no existing notes") return False # Notify and quit if attempting to restore a backup into a synced session if sync_configured: logging.error("Backup restoration isn't possible with Nextcloud Notes sync configured") return False # Load all notes first, to avoid dealing with transactions notes = [] success = True for meta_full_path in file_list: note = self.__load_note(meta_full_path) if note is None: success = False break notes.append(note) if not success: logging.error("Backup restoration failed") return False for note in notes: self.__restore_note(note) logging.info("Backup restoration completed") return True def __write_note_metadata(self, note: Note, meta_filename: str) -> bool: content = { "SchemaVersion": self.EXPORT_SCHEMA_VERSION, "IotasVersion": self.__iotas_version, "Title": note.title, "Category": note.category, "LastModified": note.last_modified, "Favourite": note.favourite, "Dirty": note.dirty, "LocallyDeleted": note.locally_deleted, "RemoteId": note.remote_id, "ETag": note.etag, } filename = os.path.join(self.__primary_backup_path, meta_filename) success = False try: with open(filename, "w") as f: f.write(json.dumps(content, indent=2)) success = True except OSError as e: logging.warning(f"Failed to write metadata to {filename}: {e}") return success def __write_note_content(self, note: Note) -> tuple[bool, str]: title = sanitise_path(note.title) content_filename = f"{title}.{self.__file_extension}" filename = os.path.join(self.__primary_backup_path, content_filename) success = False try: with open(filename, "w") as f: f.write(note.content) success = True except OSError as e: logging.warning(f"Failed to write metadata to {filename}: {e}") return (success, content_filename) def __restore_note(self, note: Note) -> None: # Check for existing remote id remote_id_note = None if self.__sync_configured and note.remote_id > -1: remote_id_note = self.__db.get_note_by_remote_id(note.remote_id) if remote_id_note is not None: self.__restore_note_with_matching_remote_id(note, remote_id_note) else: existing_note = self.__db.get_note_by_title(note.title) if existing_note is not None: self.__restore_note_with_matching_title(note, existing_note) else: # Create new logging.debug(f"Creating {note.title}") self.__db.add_note(note) def __restore_note_with_matching_remote_id(self, note: Note, remote_id_note: Note) -> None: if note.identical_to(remote_id_note): logging.debug(f'Skipping restoration of existing identical note "{note.title}"') else: # Translators: Description, prefixes note title on backup restoration clash duplicate_reason = _("RESTORATION REMOTE ID CLASH") self.__db.create_duplicate_note(note, duplicate_reason) logging.info(f'Duplicating note "{note.title}" due to matching remote id') def __restore_note_with_matching_title(self, note: Note, existing_note: Note): if note.identical_to(existing_note): logging.debug(f'Skipping restoration of existing identical note "{note.title}"') elif note.content == existing_note.content: if note.last_modified > existing_note.last_modified: # Update metadata if last modified newer and content matches self.__update_note_metadata(existing_note, note) logging.info(f'Updating metadata for note "{note.title}"') else: msg = 'Skipping note "{}" with matching title, contents and a newer timestamp' logging.info(msg.format(note.title)) else: # Duplicate note # Translators: Description, prefixes note title on backup restoration clash duplicate_reason = _("RESTORATION TITLE CLASH") self.__db.create_duplicate_note(note, duplicate_reason) logging.info( f'Duplicating note "{note.title}" due to matching title but different content' ) def __update_note_metadata(self, dest: Note, source: Note) -> None: # Update metadata if last modified newer and content matches changed_fields = DirtyFields() if dest.favourite != source.favourite: dest.favourite = source.favourite changed_fields.favourite = True if dest.last_modified != source.last_modified: dest.last_modified = source.last_modified changed_fields.last_modified = True if dest.category != source.category: dest.category = source.category changed_fields.category = True if dest.locally_deleted != source.locally_deleted: dest.locally_deleted = source.locally_deleted changed_fields.locally_deleted = True if dest.etag != source.etag: dest.etag = source.etag changed_fields.etag = True if dest.remote_id != source.remote_id: dest.remote_id = source.remote_id changed_fields.remote_id = True self.__db.persist_note_selective(dest, changed_fields) def __switch_old_backup_to_archive(self) -> bool: file_list = glob.glob( os.path.join(self.__primary_backup_path, f"*.{self.METADATA_EXTENSION}") ) if len(file_list) == 0: return True archive_path = self.__archive_backup_path if os.path.exists(archive_path): try: shutil.rmtree(archive_path) except OSError as e: logging.error(f"Failed to remove backup archive directory at {archive_path}: {e}") return False try: os.mkdir(archive_path) except OSError as e: logging.error(f"Failed to create backup archive directory at {archive_path}: {e}") return False for meta_file in file_list: content_file = ".".join(meta_file.split(".")[:-1]) if os.path.exists(content_file): try: shutil.move(content_file, archive_path) except OSError as e: logging.error(f"Failed to move {content_file} into {archive_path}: {e}") return False try: shutil.move(meta_file, archive_path) except OSError as e: logging.error(f"Failed to move {meta_file} into {archive_path}: {e}") return False return True def __load_note(self, meta_full_path: str) -> Optional[Note]: meta_filename = os.path.basename(meta_full_path) content_full_path = ".".join(meta_full_path.split(".")[:-1]) content_filename = os.path.basename(content_full_path) if not os.path.exists(content_full_path): logging.warning(f'Skipping "{content_filename}" due to missing content') return None # Skip restoring massive files if os.path.getsize(content_full_path) > self.MAXIMUM_CONTENT_SIZE_MB * 1000 * 1000: logging.error( f'Bailing "{content_filename}" due to exceeding {self.MAXIMUM_CONTENT_SIZE_MB}MB' ) return None try: with open(content_full_path, "r") as f: content = f.read() except OSError as e: logging.error(f"Failed to read note content from {content_full_path}: {e}") return None try: with open(meta_full_path, "r") as f: meta_str = f.read() meta = json.loads(meta_str) except (OSError, json.decoder.JSONDecodeError) as e: logging.error(f"Failed to read note metadata from {meta_filename}: {e}") return None note = Note.from_backup(meta, content, self.__sync_configured) if note is None: logging.error(f'Failed to parse note metadata from "{meta_filename}"') return None return note @staticmethod def get_default_primary_path() -> str: return os.path.join( GLib.get_user_data_dir(), BackupManager.DATA_SUBPATH, BackupManager.PRIMARY_DIRNAME ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/backup_storage.py000066400000000000000000000043701507102636600250700ustar00rootroot00000000000000from abc import ABC, abstractmethod from typing import Optional from iotas.note import Note, DirtyFields class BackupStorage(ABC): """Backup storage interface.""" @abstractmethod def add_note(self, note: Note) -> None: """Add a new note to the database. :param Note note: Note to add """ raise NotImplementedError() @abstractmethod def get_all_notes_count(self, include_locally_deleted: bool = True) -> int: """Fetch the number of notes in the database. :param bool include_locally_deleted: Whether to include locally deleted notes in the count :return: The count :rtype: int """ raise NotImplementedError() @abstractmethod def get_all_notes(self, load_content: bool = False) -> list[Note]: """Fetch all notes from the database. :param bool load_content: Whether to load the content for each note :return: List of notes :rtype: list[Note] """ raise NotImplementedError() @abstractmethod def get_note_by_remote_id(self, remote_id: int) -> Optional[Note]: """Fetch note from the database by remote id. :param int remote_id: Remote id of the note :return: The note, or None :rtype: Optional[Note] """ raise NotImplementedError() @abstractmethod def get_note_by_title(self, title: str) -> Optional[Note]: """Fetch note from the database by title. :param str title: Search title :return: The note, or None :rtype: Optional[Note] """ raise NotImplementedError() @abstractmethod def persist_note_selective(self, note: Note, updated_fields: DirtyFields) -> None: """Persist local note based on remote changes. :param Note note: The note to update :param DirtyFields updated_fields: Which fields to update """ raise NotImplementedError() @abstractmethod def create_duplicate_note(self, note: Note, reason: str) -> Note: """Create a duplicate note with a prefixed title. :param Note note: The note to duplicate :param str reason: The reason for the duplication, which is prefixed on the title """ raise NotImplementedError() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/category.py000066400000000000000000000155761507102636600237260ustar00rootroot00000000000000from __future__ import annotations from gettext import gettext as _ from gi.repository import GObject from enum import IntEnum, auto from typing import Optional, Self from iotas.note import Note class CategorySpecialPurpose(IntEnum): ALL = auto() UNCATEGORISED = auto() class Category(GObject.Object): # Translators: Title ALL_TITLE = _("All Notes") # Translators: Title UNCATEGORISED_TITLE = _("Uncategorised") def __init__(self, name: str, note_count: int) -> None: super().__init__() self.__parent = None self.name = name self.__sub_category_name = "" self.__child_note_count = 0 self.__note_count_with_children = 0 self.note_count = note_count self.__children: list[Category] = [] self.__special_purpose: Optional[CategorySpecialPurpose] = None def includes_note(self, note: Note) -> bool: """Whether category or sub-category includes note. :param Note note: Note to check :returns: Whether included :rtype: bool """ if note.locally_deleted: include = False elif self.__special_purpose == CategorySpecialPurpose.ALL: include = True elif self.__special_purpose == CategorySpecialPurpose.UNCATEGORISED: include = note.category == "" elif note.category == self.__name: include = True elif note.category.startswith(self.__name + "/"): include = True else: include = False return include def increase_note_count(self, amount: int = 1) -> None: """Increase note count. :param int amount: Amount to change by """ self.note_count += amount if self.__parent is not None: self.__parent.increase_child_note_count(amount) def decrease_note_count(self, amount: int = 1) -> None: """Decrease note count. :param int amount: Amount to change by """ self.note_count -= amount if self.__parent is not None: self.__parent.decrease_child_note_count(amount) def increase_child_note_count(self, amount: int = 1) -> None: """Increase children's note count. :param int amount: Amount to change by """ self.child_note_count += amount if self.__parent is not None: self.__parent.increase_child_note_count(amount) def decrease_child_note_count(self, amount: int = 1) -> None: """Decrease children's note count. :param int amount: Amount to change by """ self.child_note_count -= amount if self.__parent is not None: self.__parent.decrease_child_note_count(amount) def add_child(self, category: Category) -> None: """Link a child category. :param Category category: The new child """ if category not in self.__children: self.__children.append(category) def remove_child(self, category: Category) -> None: """Unlink a child category. :param Category category: The child """ if category in self.__children: self.__children.remove(category) def get_parent(self) -> Optional[Self]: """Get the parent category. :returns: The parent or None :rtype: Optional[Self] """ return self.__parent def set_parent(self, category: Optional[Category]) -> None: """Set the parent category. :param Optional[Category] category: The parent or None """ self.__parent = category if category is not None: self.__refresh_sub_category_name() # TODO remove with CategoryManager.recreate_category_for_expandable_change and Gtk v4.10+ def duplicate(self) -> Self: """Duplicate the category. :returns: The duplicate :rtype: Self """ new_category = Category(self.name, self.__note_count) new_category.set_parent(self.__parent) for child in self.__children: new_category.add_child(child) child.set_parent(new_category) new_category.increase_child_note_count(child.note_count) return new_category @GObject.Property(type=str, default="") def name(self) -> str: return self.__name @name.setter def set_name(self, value: str) -> None: self.__name = value self.__refresh_display_name() self.__sub_category_path = "/" in value if self.__sub_category_path: self.__refresh_sub_category_name() @GObject.Property(type=str, default="") def display_name(self) -> str: return self.__display_name @GObject.Property(type=int, default=0) def note_count(self) -> int: return self.__note_count @note_count.setter def set_note_count(self, value: int) -> None: self.__note_count = value self.note_count_with_children = self.child_note_count + value @GObject.Property(type=int, default=0) def child_note_count(self) -> int: return self.__child_note_count @child_note_count.setter def set_child_note_count(self, value: int) -> None: self.__child_note_count = value self.note_count_with_children = self.note_count + value @GObject.Property(type=int, default=0) def note_count_with_children(self) -> int: return self.__note_count_with_children @note_count_with_children.setter def set_note_count_with_children(self, value: int) -> None: self.__note_count_with_children = value @GObject.Property(type=int, default=False) def number_of_direct_children(self) -> int: return len(self.__children) @GObject.Property(type=int, default=None) def special_purpose(self) -> Optional[CategorySpecialPurpose]: return self.__special_purpose @special_purpose.setter def set_special_purpose(self, value: Optional[CategorySpecialPurpose]) -> None: self.__special_purpose = value @GObject.Property(type=str, default="") def sub_category_name(self) -> str: return self.__sub_category_name @GObject.Property(type=bool, default=False) def is_sub_category(self) -> bool: return self.__sub_category_path def __refresh_display_name(self): self.__display_name = Category.generate_display_name(self.__name) def __refresh_sub_category_name(self): if self.__parent is None and not self.__sub_category_path: return self.__sub_category_name = Category.generate_sub_category_name(self.__name) @staticmethod def generate_display_name(name: str) -> str: if "/" in name: return " / ".join(name.split("/")) else: return name @staticmethod def generate_sub_category_name(name: str) -> str: if "/" in name: return " / ".join(name.split("/")[1:]) else: # Shouldn't occur return name iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/category_header_bar.py000066400000000000000000000156141507102636600260530ustar00rootroot00000000000000from gi.repository import Adw, GLib, GObject, Gtk from iotas.category import Category from iotas.category_treeview_list_store import CategoryTreeViewListStore from iotas.note import Note from iotas.text_utils import sanitise_path @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/category_header_bar.ui") class CategoryHeaderBar(Adw.Bin): __gtype_name__ = "CategoryHeaderBar" __gsignals__ = { "abort": (GObject.SignalFlags.RUN_FIRST, None, ()), "categories-changed": (GObject.SignalFlags.RUN_FIRST, None, ()), } _entry: Gtk.Entry = Gtk.Template.Child() _completion: Gtk.EntryCompletion = Gtk.Template.Child() _apply_button: Gtk.Button = Gtk.Template.Child() _clear_button: Gtk.Button = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__model: CategoryTreeViewListStore self.__notes: list[Note] = [] self.__changeset: list[tuple[Note, str]] = [] completion_cell = Gtk.CellRendererText.new() completion_cell.set_property("xpad", 6) completion_cell.set_property("ypad", 6) self._completion.pack_start(completion_cell, False) self._completion.add_attribute(completion_cell, "text", 0) self._completion.connect("match-selected", self.__on_category_selected) self._entry.connect("icon-release", lambda _e, _p: self.__on_icon_released()) self.__category_buffer = self._entry.get_buffer() self.__category_buffer.connect( "notify::text", lambda _o, _v: self.__update_clear_field_icon_visibility() ) def setup(self, model: CategoryTreeViewListStore) -> None: """Perform initial setup. :param CategoryTreeViewListStore model: Categories model """ self.__model = model self._completion.set_model(self.__model) self._completion.set_match_func(self.__completion_match_check) def replace_notes(self, notes: list[Note]) -> None: """Replace the notes on which the header is working. For selection changes in the index once the header is already visible. :param list[Note] notes: Notes to work on """ self.__notes = notes.copy() self.__refresh_actions() def activate(self, notes: list[Note]) -> None: """Activate header bar. :param list[Note] notes: Notes to work on """ self.__notes = notes.copy() if self.__model.iter_n_children(None) > 0: self.__show_popup() # If editing multiple notes only populate the entry if they're all the same uniform_category = notes[0].category if len(notes) > 1: for note in notes[1:]: if note.category != uniform_category: uniform_category = "" break self._entry.set_text(Category.generate_display_name(uniform_category)) self._entry.grab_focus() self._entry.select_region(0, -1) self.__refresh_actions() def clear_and_apply(self) -> None: """Clear category and apply.""" self._entry.set_text("") self.__apply_change() def take_changeset(self) -> list[tuple[Note, str]]: """Fetch changeset and clear. :return: List of modified notes with their previous categories :rtype: list[tuple[Note, str]] """ changeset = self.__changeset self.__changeset = [] return changeset def focus(self) -> None: """Grab focus to entry.""" self._entry.grab_focus() @Gtk.Template.Callback() def _on_apply(self, _button: Gtk.Button) -> None: self.__apply_change() @Gtk.Template.Callback() def _on_entry_activated(self, _entry: Gtk.Entry) -> None: self.__apply_change() @Gtk.Template.Callback() def _on_clear(self, _button: Gtk.Button) -> None: self.clear_and_apply() @Gtk.Template.Callback() def _on_abort(self, _button: Gtk.Button) -> None: self.emit("abort") def __on_icon_released(self) -> None: # Intentionally allowed for either icon if self._entry.get_text() == "": self.__show_popup() else: self._entry.get_buffer().delete_text(0, -1) self._entry.set_property("secondary-icon-name", "") def __on_category_selected( self, _completion: Gtk.EntryCompletion, store: Gtk.TreeModel, iter: Gtk.TreeIter ) -> bool: new_category = store.get_value(iter, 0) self.__update_category(new_category) return True def __apply_change(self) -> None: if not self.__notes: return new_category = self._entry.get_text().strip() self.__update_category(new_category) def __show_popup(self) -> None: child = self._entry.get_first_child() while not isinstance(child, Gtk.Popover): child = child.get_next_sibling() child.set_visible(True) self._completion.complete() def __refresh_actions(self) -> None: self._apply_button.set_sensitive(self.__notes) self._clear_button.set_sensitive(self.__notes) def __update_category(self, new_category: str) -> None: if "/" in new_category: parts = new_category.split("/") parts = [sanitise_path(x).strip() for x in parts] parts = [x for x in parts if x != ""] new_category = "/".join(parts) self.__changeset = [] for note in self.__notes: if new_category != note.category: old_category = note.category note.category = new_category # Choosing to not bump last_modified for category updates note.flag_changed(update_last_modified=False) self.__changeset.append((note, old_category)) GLib.idle_add(self.emit, "categories-changed") def __update_clear_field_icon_visibility(self) -> None: icon_showing = self._entry.get_property("secondary-icon_name") if self.__category_buffer.get_text() != "": if not icon_showing: self._entry.set_property("secondary-icon-name", "edit-clear-symbolic") else: if icon_showing: self._entry.set_property("secondary-icon-name", "") def __completion_match_check( self, _completion: Gtk.EntryCompletion, value: str, compare_iter: Gtk.TreeIter ) -> bool: """GtkEntryCompletion matching function. :param GtkEntryCompletion _completion: The EntryCompletion :param str value: The string to match :param GtkTreeIter compare_iter: The GtkTreeIter pointing at the value to compare :returns: Whether they match :rtype: bool """ compare_category = self.__model.get_value(compare_iter, 1) if compare_category is None: # Seems to occur applying a dropdown value return False else: return value.lower() in compare_category.name.lower() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/category_list_model.py000066400000000000000000000117041507102636600261260ustar00rootroot00000000000000import gi gi.require_version("Gtk", "4.0") from gi.repository import Gio, GObject, Gtk from typing import Any from iotas.category import Category, CategorySpecialPurpose class CategoryListModel(Gtk.SortListModel): ALL_INDEX = 0 UNCATEGORISED_INDEX = 1 def __init__(self) -> None: self.__all_category: Category self.__uncategorised_category: Category self.__store = Gio.ListStore(item_type=Category) self.__sorter = Gtk.CustomSorter() super().__init__(model=self.__store, sorter=self.__sorter) def populate(self, categories: list[Category]) -> None: """Populate store with categories. :param list[Category] categories: Categories to populate """ self.__store.remove_all() # Populate reversed so children are created before parents for category in reversed(categories): self.__store.append(category) if category.special_purpose == CategorySpecialPurpose.ALL: self.all_category = category elif category.special_purpose == CategorySpecialPurpose.UNCATEGORISED: self.uncategorised_category = category self.invalidate_sort() def add(self, category: Category) -> None: """Add category to store. :param Category category: Category to add """ index_before = 1 for i in range(2, self.__store.get_n_items()): list_cat = self.__store.get_item(i) if list_cat.special_purpose is not None: continue if list_cat.name.lower() > category.name.lower(): break index_before = i self.__store.insert(index_before + 1, category) def remove(self, category: Category) -> None: """Remove category from store. :param Category category: Category to remove """ for i in range(0, self.__store.get_n_items()): list_cat = self.__store.get_item(i) if list_cat.special_purpose is not None: continue if list_cat.name == category.name: self.__store.remove(i) break def get_special(self, purpose: CategorySpecialPurpose) -> tuple[Category, int]: """Fetch a special purpose category. :param CategorySpecialPurpose purpose: The category a note has been removed from :return: The category and index in store :rtype: tuple[Category, int]: """ category = None index = -1 if purpose == CategorySpecialPurpose.ALL: category = self.all_category index = self.ALL_INDEX elif purpose == CategorySpecialPurpose.UNCATEGORISED: category = self.uncategorised_category index = self.UNCATEGORISED_INDEX return (category, index) def get_non_special(self, name: str) -> tuple[Category | None, int]: """Fetch a non-special purpose category. :param str name: The category name :return: The category and index in store :rtype: tuple[Category, int]: """ category = None index = 0 for i in range(0, self.__store.get_n_items()): list_cat = self.__store.get_item(i) if list_cat.name == name: category = list_cat index = i break return (category, index) def invalidate_sort(self) -> None: """Invalidate the sorter.""" self.__sorter.set_sort_func(CategoryListModel.sort_func) @GObject.Property(type=Category) def all_category(self) -> Category: return self.__all_category @all_category.setter def set_all_category(self, new_val: Category) -> None: self.__all_category = new_val @GObject.Property(type=Category) def uncategorised_category(self) -> Category: return self.__uncategorised_category @uncategorised_category.setter def set_uncategorised_category(self, new_val: Category) -> None: self.__uncategorised_category = new_val @staticmethod def sort_func(category1: Category, category2: Category, _data: Any) -> int: """Sort categories. :param Category category1: First category :param Category category2: Second category :param _data: Unused :return: -1 if category1 earlier, 1 if later, 0 unused :rtype: int """ if category1.special_purpose == CategorySpecialPurpose.ALL: return -1 elif category2.special_purpose == CategorySpecialPurpose.ALL: return 1 elif ( category1.special_purpose == CategorySpecialPurpose.UNCATEGORISED and category2.special_purpose is None ): return -1 elif ( category2.special_purpose == CategorySpecialPurpose.UNCATEGORISED and category1.special_purpose is None ): return 1 else: return -1 if category1.name.lower() < category2.name.lower() else 1 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/category_manager.py000066400000000000000000000245101507102636600254040ustar00rootroot00000000000000from gi.repository import GLib, GObject from collections import OrderedDict from threading import Thread from typing import Optional from iotas.category_storage import CategoryStorage from iotas.category import Category, CategorySpecialPurpose from iotas.category_list_model import CategoryListModel from iotas.category_treeview_list_store import CategoryTreeViewListStore class CategoryManager(GObject.Object): __gtype_name__ = "CategoryManager" __gsignals__ = { "initial-load-complete": (GObject.SignalFlags.RUN_FIRST, None, ()), } def __init__(self, db: CategoryStorage) -> None: super().__init__() self.__db = db self.__list_model = CategoryListModel() self.__tree_store = CategoryTreeViewListStore() self.__all_category: Optional[Category] = None self.__uncategorised_category: Optional[Category] = None self.__categories: OrderedDict[str, Category] = OrderedDict() self.__have_sub_category = False def populate(self) -> None: """Populate categories from database.""" def chain_population_to_stores() -> None: self.__list_model.populate(self.__get_with_special()) # Lean on the sorting in the list store to populate the tree store with its sorted # list including parent categories categories = [] for i in range(2, self.__list_model.get_n_items()): categories.append(self.__list_model.get_item(i)) self.__tree_store.populate(categories) self.emit("initial-load-complete") def thread_do() -> None: categories = self.__db.get_all_categories() for category in categories: if category.special_purpose == CategorySpecialPurpose.ALL: self.__all_category = category elif category.special_purpose == CategorySpecialPurpose.UNCATEGORISED: self.__uncategorised_category = category else: self.__categories[category.name] = category if category.is_sub_category: self.__ensure_parents(category, False) self.have_sub_category = True GLib.idle_add(chain_population_to_stores) thread = Thread(target=thread_do) thread.daemon = True thread.start() def note_added(self, new_category: str) -> None: """Make updates for a created note. :param Optional[str] new_category: The category a note has been added to """ self.note_category_changed(None, new_category) def note_category_changed( self, old_category: Optional[str], new_category: Optional[str] ) -> None: """Make updates for a note changing category. :param Optional[str] old_category: The category a note has been removed from :param Optional[str] new_category: The category a note has been added to """ if old_category is not None: self.__decrement_category(old_category, new_category is None) if new_category is not None: if new_category != "": category_updated = self.__increment_category(new_category) if not category_updated: self.__add_new_category(new_category) else: # Moving into uncategorised self.__increment_uncategorised() if old_category is None: # Handle new note creation self.__increment_all() if old_category is not None: self.__handle_possible_emptied_category(old_category) def note_deleted(self, old_category: str) -> None: """Make updates for a deleted note. :param Optional[str] old_category: The category a note has been removed from """ self.note_category_changed(old_category, None) # TODO with Gtk v4.10+ replace this with a binding from the model count to TreeExpander's # hide-expander def recreate_category_for_expandable_change(self, category: Category) -> None: """Recreate the provided category. Triggers an update in the model when a category changes in and out of leaf state. :param Category category: The category to recreate """ parent = category.get_parent() if parent is not None: parent.remove_child(category) new_category = category.duplicate() del self.__categories[category.name] self.__list_model.remove(category) self.__tree_store.delete(category) self.__categories[category.name] = new_category self.__list_model.add(new_category) self.__tree_store.add(new_category) if parent is not None: parent.add_child(new_category) def get_normal_category(self, name: str) -> tuple[Category | None, int]: return self.__list_model.get_non_special(name) def get_special_purpose_category(self, purpose: CategorySpecialPurpose) -> tuple[Category, int]: return self.__list_model.get_special(purpose) @GObject.Property(type=bool, default=False) def have_sub_category(self) -> bool: return self.__have_sub_category @have_sub_category.setter def set_have_sub_category(self, value: bool) -> None: self.__have_sub_category = value @GObject.Property(type=CategoryListModel, default=False) def list_model(self) -> CategoryListModel: return self.__list_model @GObject.Property(type=CategoryTreeViewListStore, default=False) def tree_store(self) -> CategoryTreeViewListStore: return self.__tree_store @GObject.Property(type=Category, default=None) def all_category(self) -> Optional[Category]: return self.__all_category def __get_with_special(self) -> list[Category]: assert self.__uncategorised_category assert self.__all_category out = list(self.__categories.values()) out.insert(0, self.__uncategorised_category) out.insert(0, self.__all_category) return out def __add_new_category(self, category_name: str) -> None: category = Category(category_name, 1) self.__categories[category_name] = category parent = None if category.is_sub_category: self.__ensure_parents(category, True) parent = category.get_parent() self.have_sub_category = True self.__list_model.add(category) self.__tree_store.add(category) # If parent has just changed to expandable, recreate it if parent is not None and parent.number_of_direct_children == 1: self.recreate_category_for_expandable_change(parent) def __increment_category(self, category_name: str) -> bool: category_updated = False if category_name in self.__categories: self.__categories[category_name].increase_note_count() category_updated = True return category_updated def __decrement_category(self, old_category_name: str, note_removed: bool) -> None: assert self.__uncategorised_category assert self.__all_category if old_category_name == "": # Moving out of uncategorised self.__uncategorised_category.decrease_note_count() else: if old_category_name in self.__categories: self.__categories[old_category_name].decrease_note_count() # Handle deletion if note_removed: self.__all_category.decrease_note_count() def __handle_possible_emptied_category(self, old_category: str) -> None: if old_category not in self.__categories: return category = self.__categories[old_category] if category.note_count_with_children == 0: delete_stack = [category] parent = category.get_parent() while parent is not None and parent.note_count_with_children == 0: delete_stack.append(parent) parent = parent.get_parent() delete_stack.reverse() delete_parent = delete_stack[0].get_parent() if delete_parent is not None: # If we reach a node to be removed that has a parent with other notes # (on itself or siblings) remove this node from its parent delete_parent.remove_child(delete_stack[0]) # Iterate deleting for parent in delete_stack: del self.__categories[parent.name] self.__list_model.remove(parent) self.__tree_store.delete(parent) self.__refresh_have_sub_category() def __increment_uncategorised(self) -> None: assert self.__uncategorised_category self.__uncategorised_category.increase_note_count() def __increment_all(self) -> None: assert self.__all_category self.__all_category.increase_note_count() def __ensure_parents(self, category: Category, populate_models: bool) -> None: parents = category.name.split("/")[:-1] full_path_parents = [] parts = [] for parent_name in parents: parts.append(parent_name) full_path_parents.append("/".join(parts)) level_child = category for parent_name in reversed(full_path_parents): if level_child.get_parent() is None: # Check for existing if parent_name in self.__categories: parent = self.__categories[parent_name] else: # Create if one doesn't exist parent = Category(parent_name, 0) self.__categories[parent_name] = parent if populate_models: self.__list_model.add(parent) self.__tree_store.add(parent) level_child.set_parent(parent) # Add child parent.add_child(level_child) # Update child note count parent.increase_child_note_count(level_child.note_count_with_children) # Prepare as child for next level level_child = parent def __refresh_have_sub_category(self): have = False for category in self.__categories.values(): if category.is_sub_category: have = True break if self.have_sub_category != have: self.have_sub_category = have iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/category_storage.py000066400000000000000000000005751507102636600254430ustar00rootroot00000000000000from abc import ABC, abstractmethod from iotas.category import Category class CategoryStorage(ABC): """Category storage interface.""" @abstractmethod def get_all_categories(self) -> list[Category]: """Fetch all categories from the database. :return: List of categories :rtype: list[Category] """ raise NotImplementedError() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/category_treeview_list_store.py000066400000000000000000000030231507102636600300670ustar00rootroot00000000000000from gi.repository import GObject, Gtk from iotas.category import Category class CategoryTreeViewListStore(Gtk.ListStore): def __init__(self) -> None: super().__init__(GObject.TYPE_STRING, Category) def populate(self, categories: list[Category]) -> None: """Populate store with categories. :param list[Category] categories: Categories to populate """ for category in categories: iter = self.append() self.set_value(iter, 0, category.display_name) self.set_value(iter, 1, category) def add(self, category: Category) -> None: """Add category to store. :param Category category: Category to remove """ iter = self.get_iter_first() if iter is None: new_iter = self.append() else: while iter is not None: if self.get_value(iter, 1).name.lower() > category.name.lower(): break iter = self.iter_next(iter) new_iter = self.insert_before(iter) self.set_value(new_iter, 0, category.display_name) self.set_value(new_iter, 1, category) def delete(self, category: Category) -> None: """Remove category from store. :param Category category: Category to remove """ iter = self.get_iter_first() while iter is not None: if self.get_value(iter, 1).name == category.name: self.remove(iter) break iter = self.iter_next(iter) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/config_manager.py000066400000000000000000000623361507102636600250440ustar00rootroot00000000000000from __future__ import annotations from gi.repository import Adw, Gio, GLib, GObject from enum import StrEnum import logging from typing import Callable, Optional class HeaderBarVisibility(StrEnum): """Top or bottom bar visibility.""" ALWAYS_VISIBLE = "always-visible" AUTO_HIDE = "auto-hide" AUTO_HIDE_FULLSCREEN_ONLY = "auto-hide-fullscreen-only" DISABLED = "disabled" class ConfigManager(GObject.Object): STYLE = "style-variant" WINDOW_SIZE = "window-size" FIRST_START = "first-start" FONT_SIZE = "font-size" LINE_LENGTH = "line-length" USE_MONOSPACE_FONT = "use-monospace-font" EDITOR_THEME = "editor-theme" EDITOR_FORMATTING_BAR_VISIBILTY = "editor-formatting-bar-visibility" EDITOR_HEADER_BAR_VISIBILTY = "editor-header-bar-visibility" BACKUP_NOTE_EXTENSION = "backup-note-extension" PERSIST_SIDEBAR = "persist-sidebar" INDEX_CATEGORY_STYLE = "index-category-style" NEXTCLOUD_ENDPOINT = "nextcloud-endpoint" NEXTCLOUD_USERNAME = "nextcloud-username" NEXTCLOUD_PRUNE_THRESHOLD = "nextcloud-prune-threshold" SYNC_INTERVAL = "sync-interval" NETWORK_TIMEOUT = "network-timeout" SPELLING_ENABLED = "spelling-enabled" SPELLING_LANGUAGE = "spelling-language" SHOW_STARTUP_SECRET_SERVICE_FAILURE = "show-startup-secret-service-failure" SHOW_SYNCING_DEBUG_NOTIFICATION = "show-syncing-debug-notification" MARKDOWN_RENDER = "markdown-render-enabled" MARKDOWN_DETECT_SYNTAX = "markdown-syntax-detection-enabled" MARKDOWN_KEEP_WEBKIT_PROCESS = "markdown-keep-webkit-process" MARKDOWN_TEX_SUPPORT = "markdown-tex-support" MARKDOWN_USE_MONOSPACE_FONT = "markdown-use-monospace-font" MARKDOWN_RENDER_MONOSPACE_FONT_RATIO = "markdown-render-proportional-to-monospace-font-ratio" MARKDOWN_DEFAULT_TO_RENDER = "markdown-default-to-render" LAST_LAUNCHED_VERSION = "last-launched-version" LAST_EXPORT_DIRECTORY = "last-export-directory" EXTRA_EXPORT_FORMATS = "extra-export-formats" SHOW_EXTENDED_PREFERENCES = "show-extended-preferences" # Retaining to for old migrations ################################################### MARKDOWN_SYNTAX_HIGHLIGHTING = "markdown-syntax-highlighting-enabled" HIDE_EDITOR_HEADERBAR = "auto-hide-editor-headerbar" HIDE_HEADERBAR_WHEN_FULLSCREEN = "hide-editor-headerbar-when-fullscreen" ##################################################################################### _instance = None _app_id = None settings: Gio.Settings def __init__(self, settings: Gio.Settings) -> None: super().__init__() self.settings = settings def connect_changed(self, property_name: str, callback: Callable[[], None]) -> None: """Connect callback to changed signal on property. The callback is called without the setting value. :param str property_name: Property to connect :param Callable[[], None] callback: Callback """ self.settings.connect(f"changed::{property_name}", lambda _k, _v: callback()) def create_action(self, key: str) -> Gio.Action: """Create action on Gio.Settings object for setting. :param str key: Key identifier :return: The action :rtype: Gio.Action """ return self.settings.create_action(key) def bind( self, key: str, object: GObject.Object, property: str, flags: Gio.SettingsBindFlags ) -> None: """Bind setting to property. :param str key: Setting key :param GObject.Object object: Destination object to bind to :param str property: Destination property name :param Gio.SettingsBindFlags: Binding flags """ self.settings.bind(key, object, property, flags) def get_window_size(self) -> GLib.Variant: """Get window size. :return: The size :rtype: GLib.Variant """ return self.settings.get_value(self.WINDOW_SIZE) def set_window_size(self, width: int, height: int) -> None: """Set window size. :param int width: Width :param int height: Height """ g_variant = GLib.Variant("ai", (width, height)) self.settings.set_value(self.WINDOW_SIZE, g_variant) @GObject.Property(type=bool, default=True) def first_start(self) -> bool: """Get whether doing first startup. :return: First startup :rtype: bool """ return self.settings.get_value(self.FIRST_START) @first_start.setter def set_first_start(self, value: bool) -> None: """Set whether first start. :param bool value: New value """ self.settings.set_boolean(self.FIRST_START, value) @GObject.Property(type=bool, default=True) def use_monospace_font(self) -> bool: """Get whether to use a monospace font. :return: Using monospace font :rtype: bool """ return self.settings.get_value(self.USE_MONOSPACE_FONT) @use_monospace_font.setter def set_use_monospace_font(self, value: bool) -> None: """Set whether to use a monospace font. :param bool value: New value """ self.settings.set_boolean(self.USE_MONOSPACE_FONT, value) @GObject.Property(type=int) def font_size(self) -> int: """Get font size. :return: Size :rtype: int """ return self.settings.get_int(self.FONT_SIZE) @font_size.setter def set_font_size(self, value: int) -> None: """Set font size. :param int value: New value """ self.settings.set_int(self.FONT_SIZE, value) @GObject.Property(type=int) def default_font_size(self) -> int: """Get default font size. :return: Default size :rtype: int """ return self.settings.get_default_value(self.FONT_SIZE).get_int32() @GObject.Property(type=int) def line_length(self) -> int: """Get line length. :return: Size in pixels :rtype: int """ return self.settings.get_int(self.LINE_LENGTH) @line_length.setter def set_line_length(self, value: int) -> None: """Set line length. :param int value: New value """ self.settings.set_int(self.LINE_LENGTH, value) @GObject.Property(type=int) def default_line_length(self) -> int: """Get default line length. :return: Default length :rtype: int """ return self.settings.get_default_value(self.LINE_LENGTH).get_int32() @GObject.Property(type=int) def line_length_max(self) -> int: """Get line length maximum. :return: Size in pixels :rtype: int """ return ( self.settings.get_property("settings-schema") .get_key(self.LINE_LENGTH) .get_range()[1][-1] ) @GObject.Property(type=bool, default=True) def spelling_enabled(self) -> bool: """Get whether spelling enabled. :return: Spelling enabled :rtype: bool """ return self.settings.get_value(self.SPELLING_ENABLED) @spelling_enabled.setter def set_spelling_enabled(self, value: bool) -> None: """Set spelling enabled. :param bool value: New value """ self.settings.set_boolean(self.SPELLING_ENABLED, value) @GObject.Property(type=str) def spelling_language(self) -> Optional[str]: """Get spelling language. :return: Language tag or None if empty :rtype: str """ lang = self.settings.get_string(self.SPELLING_LANGUAGE) if lang.strip() == "": lang = None return lang @spelling_language.setter def set_spelling_language(self, value: str) -> None: """Set spelling language. :param str value: New value """ self.settings.set_string(self.SPELLING_LANGUAGE, value) @GObject.Property(type=str) def style(self) -> str: """Get style. :return: Style :rtype: str """ return self.settings.get_string(self.STYLE) @style.setter def set_style(self, value: str) -> None: """Set style. :param str value: New value """ self.settings.set_string(self.STYLE, value) @GObject.Property(type=int) def sync_interval(self) -> int: """Get sync interval. :return: Interval :rtype: int """ return self.settings.get_int(self.SYNC_INTERVAL) @sync_interval.setter def set_sync_interval(self, value: int) -> None: """Set sync interval. :param int value: New value """ self.settings.set_int(self.SYNC_INTERVAL, value) @GObject.Property(type=str) def index_category_style(self) -> str: """Get the index category label style. :return: The style :rtype: str """ return self.settings.get_string(self.INDEX_CATEGORY_STYLE) @index_category_style.setter def set_index_category_style(self, value: str) -> None: """Set the index category style. :param str value: New value """ self.settings.set_string(self.INDEX_CATEGORY_STYLE, value) @GObject.Property(type=bool, default=True) def pin_sidebar(self) -> bool: """Get whether to pin the index sidebar (in large windows). :return: Whether to hide :rtype: bool """ return self.settings.get_value(self.PERSIST_SIDEBAR) @pin_sidebar.setter def set_pin_sidebar(self, value: bool) -> None: """Set whether to pin the index sidebar (in large windows). :param bool value: New value """ self.settings.set_boolean(self.PERSIST_SIDEBAR, value) @GObject.Property(type=str) def editor_theme(self) -> str: """Get editor theme. :return: Theme :rtype: str """ return self.settings.get_string(self.EDITOR_THEME) @editor_theme.setter def set_editor_theme(self, value: str) -> None: """Set editor theme. :param str value: New value """ self.settings.set_string(self.EDITOR_THEME, value) @property def editor_formatting_bar_visibility(self) -> Optional[HeaderBarVisibility]: """Get the formatting bar visibility. :return: Visibility, or None :rtype: HeaderBarVisibility, optional """ setting_value = self.settings.get_string(self.EDITOR_FORMATTING_BAR_VISIBILTY) try: obj = HeaderBarVisibility(setting_value) except ValueError as e: logging.warning(f"Couldn't parse formatting bar visibility from '{setting_value}': {e}") return None else: return obj @editor_formatting_bar_visibility.setter def editor_formatting_bar_visibility(self, value: HeaderBarVisibility) -> None: """Set the formatting bar visibility. :param HeaderBarVisibility value: New value """ self.settings.set_string(self.EDITOR_FORMATTING_BAR_VISIBILTY, str(value)) @GObject.Property(type=bool, default=True) def editor_formatting_bar_visible_for_window_state(self) -> bool: """Get whether the formatting bar is configured visible for the window maximised state." :return: Whether visible :rtype: bool """ setting_value = self.settings.get_string(self.EDITOR_FORMATTING_BAR_VISIBILTY) try: obj = HeaderBarVisibility(setting_value) except ValueError as e: logging.warning(f"Couldn't parse formatting bar visibility from '{setting_value}': {e}") return False else: visible = False if self.markdown_detect_syntax: if obj == HeaderBarVisibility.ALWAYS_VISIBLE: visible = True elif obj == HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY: app = Gio.Application.get_default() if not app: logging.error("Couldn't get app?") return False window = app.get_active_window() visible = not window.is_fullscreen() return visible @property def editor_header_bar_visibility(self) -> Optional[HeaderBarVisibility]: """Get the header bar visibility. :return: The visibility setting :rtype: HeaderBarVisibility """ setting_value = self.settings.get_string(self.EDITOR_HEADER_BAR_VISIBILTY) try: obj = HeaderBarVisibility(setting_value) except ValueError as e: logging.warning(f"Couldn't parse header bar visibility from '{setting_value}': {e}") return None else: return obj @editor_header_bar_visibility.setter def editor_header_bar_visibility(self, value: HeaderBarVisibility) -> None: """Set the header bar visibility. :param HeaderBarVisibility value: New value """ self.settings.set_string(self.EDITOR_HEADER_BAR_VISIBILTY, str(value)) @GObject.Property(type=bool, default=True) def editor_header_bar_visible_for_window_state(self) -> bool: """Get whether the header bar is configured visible for the window maximised state." :return: Whether visible :rtype: bool """ setting_value = self.settings.get_string(self.EDITOR_HEADER_BAR_VISIBILTY) try: obj = HeaderBarVisibility(setting_value) except ValueError as e: logging.warning(f"Couldn't parse header bar visibility from '{setting_value}': {e}") return False else: visible = False if obj == HeaderBarVisibility.ALWAYS_VISIBLE: visible = True elif obj == HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY: app = Gio.Application.get_default() if not app: logging.error("Couldn't get app?") return False window = app.get_active_window() visible = not window.is_fullscreen() return visible @GObject.Property(type=bool, default=True) def markdown_render_enabled(self) -> bool: """Get markdown render is enabled. :return: Markdown render enabled :rtype: bool """ return self.settings.get_value(self.MARKDOWN_RENDER) @markdown_render_enabled.setter def set_markdown_render_enabled(self, value: bool) -> None: """Set markdown render enabled. :param bool value: New value """ self.settings.set_boolean(self.MARKDOWN_RENDER, value) @GObject.Property(type=bool, default=True) def markdown_detect_syntax(self) -> bool: """Get markdown syntax detection is enabled. :return: Enabled :rtype: bool """ return self.settings.get_value(self.MARKDOWN_DETECT_SYNTAX) @markdown_detect_syntax.setter def set_markdown_detect_syntax(self, value: bool) -> None: """Set markdown syntax detection is enabled. :param bool value: New value """ self.settings.set_boolean(self.MARKDOWN_DETECT_SYNTAX, value) @GObject.Property(type=bool, default=True) def markdown_keep_webkit_process(self) -> bool: """Get markdown WebKit process being retained. :return: WebKit process being retained :rtype: bool """ return self.settings.get_value(self.MARKDOWN_KEEP_WEBKIT_PROCESS) @markdown_keep_webkit_process.setter def set_markdown_keep_webkit_process(self, value: bool) -> None: """Set markdown WebKit process being retained. :param bool value: New value """ self.settings.set_boolean(self.MARKDOWN_KEEP_WEBKIT_PROCESS, value) @GObject.Property(type=bool, default=True) def markdown_tex_support(self) -> bool: """Get whether markdown TeX rendering is supported. :return: Markdown TeX supported :rtype: bool """ return self.settings.get_value(self.MARKDOWN_TEX_SUPPORT) @markdown_tex_support.setter def set_markdown_tex_support(self, value: bool) -> None: """Set whether markdown TeX rendering is supported. :param bool value: New value """ self.settings.set_boolean(self.MARKDOWN_TEX_SUPPORT, value) @GObject.Property(type=bool, default=True) def markdown_use_monospace_font(self) -> bool: """Get whether to use a monospace font for the markdown render. :return: Using monospace font :rtype: bool """ return self.settings.get_value(self.MARKDOWN_USE_MONOSPACE_FONT) @markdown_use_monospace_font.setter def set_markdown_use_monospace_font(self, value: bool) -> None: """Set whether to use a monospace font for the markdown render. :param bool value: New value """ self.settings.set_boolean(self.MARKDOWN_USE_MONOSPACE_FONT, value) @GObject.Property(type=float) def markdown_render_monospace_font_ratio(self) -> float: """Get the adjustment in size from proportional to fixed width font. :return: Ratio :rtype: float """ return self.settings.get_double(self.MARKDOWN_RENDER_MONOSPACE_FONT_RATIO) @markdown_render_monospace_font_ratio.setter def set_markdown_render_monospace_font_ratio(self, value: float) -> None: """Set the adjustment in size from proportional to fixed width font. :param bool value: New value """ self.settings.set_double(self.MARKDOWN_RENDER_MONOSPACE_FONT_RATIO, value) @GObject.Property(type=bool, default=True) def markdown_default_to_render(self) -> bool: """Get whether to render the markdown when opening the note. :return: Defaulting to render :rtype: bool """ return self.settings.get_value(self.MARKDOWN_DEFAULT_TO_RENDER) @markdown_default_to_render.setter def set_markdown_default_to_render(self, value: bool) -> None: """Set whether to render the markdown when opening the note. :param bool value: New value """ self.settings.set_boolean(self.MARKDOWN_DEFAULT_TO_RENDER, value) @GObject.Property(type=str) def nextcloud_endpoint(self) -> str: """Get Nextcloud endpoint. :return: Endpoint :rtype: str """ return self.settings.get_string(self.NEXTCLOUD_ENDPOINT) @nextcloud_endpoint.setter def set_nextcloud_endpoint(self, value: str) -> None: """Set Nextcloud endpoint. :param str value: New value """ self.settings.set_string(self.NEXTCLOUD_ENDPOINT, value) @GObject.Property(type=str) def nextcloud_username(self) -> str: """Get Nextcloud username. :return: Username :rtype: str """ return self.settings.get_string(self.NEXTCLOUD_USERNAME) @nextcloud_username.setter def set_nextcloud_username(self, value: str) -> None: """Set Nextcloud username. :param str value: New value """ self.settings.set_string(self.NEXTCLOUD_USERNAME, value) @GObject.Property(type=bool, default=False) def nextcloud_sync_configured(self) -> bool: """Get whether sync with Nextcloud is configured. This does not mean authentication has been successful this session. :return: Whether configured :rtype: bool """ sync_username = self.nextcloud_username sync_endpoint = self.nextcloud_endpoint return sync_username != "" and sync_endpoint != "" @GObject.Property(type=int) def nextcloud_prune_threshold(self) -> int: """Get Nextcloud prune threshold. :return: Threshold :rtype: int """ return self.settings.get_int(self.NEXTCLOUD_PRUNE_THRESHOLD) @nextcloud_prune_threshold.setter def set_nextcloud_prune_threshold(self, value: int) -> None: """Set Nextcloud prune threshold. :param int value: New value """ self.settings.set_int(self.NEXTCLOUD_PRUNE_THRESHOLD, value) @GObject.Property(type=bool, default=True) def show_startup_secret_service_failure(self) -> bool: """Get to show Secret Service failure at startup. :return: Whether to show :rtype: bool """ return self.settings.get_value(self.SHOW_STARTUP_SECRET_SERVICE_FAILURE) @GObject.Property(type=bool, default=True) def show_syncing_debug_notification(self) -> bool: """Get whether to show sync debug notifications. :return: Whether to show :rtype: bool """ return self.settings.get_value(self.SHOW_SYNCING_DEBUG_NOTIFICATION) @GObject.Property(type=str) def backup_note_extension(self) -> str: """Get file extension for backed up notes. :return: Extension :rtype: str """ return self.settings.get_string(self.BACKUP_NOTE_EXTENSION) @backup_note_extension.setter def set_backup_note_extension(self, value: str) -> None: """Set file extension for backed up notes. :param str value: New value """ self.settings.set_string(self.BACKUP_NOTE_EXTENSION, value) @GObject.Property(type=str) def last_launched_version(self) -> str: """Get the last version which was run. :return: Version :rtype: str """ return self.settings.get_string(self.LAST_LAUNCHED_VERSION) @last_launched_version.setter def set_last_launched_version(self, value: str) -> None: """Set the last version which was run. :param str value: New value """ self.settings.set_string(self.LAST_LAUNCHED_VERSION, value) @GObject.Property(type=str) def last_export_directory(self) -> str: """Get the last export directory. :return: Directory :rtype: str """ return self.settings.get_string(self.LAST_EXPORT_DIRECTORY) @last_export_directory.setter def set_last_export_directory(self, value: str) -> None: """Set the last export directory. :param str value: New value """ self.settings.set_string(self.LAST_EXPORT_DIRECTORY, value) @GObject.Property(type=str) def extra_export_formats(self) -> str: """Get any extra export formats. :return: Raw formats string :rtype: str """ return self.settings.get_string(self.EXTRA_EXPORT_FORMATS) @extra_export_formats.setter def set_extra_export_formats(self, value: str) -> None: """Set extra export formats. :param str value: New value """ self.settings.set_string(self.EXTRA_EXPORT_FORMATS, value) @GObject.Property(type=bool, default=True) def show_extended_preferences(self) -> bool: """Get whether to show a great many preferences. :return: Whether to show :rtype: bool """ return self.settings.get_value(self.SHOW_EXTENDED_PREFERENCES) @show_extended_preferences.setter def set_show_extended_preferences(self, value: bool) -> None: """Set whether to show a great many preferences. :param bool value: New value """ self.settings.set_boolean(self.SHOW_EXTENDED_PREFERENCES, value) @GObject.Property(type=float) def network_timeout(self) -> float: """Get the network timeout. :return: Timeout in seconds :rtype: float """ return self.settings.get_double(self.NETWORK_TIMEOUT) @network_timeout.setter def set_network_timeout(self, value: float) -> None: """Set the network timeout. :param int value: New value """ self.settings.set_double(self.NETWORK_TIMEOUT, value) # Piped through the configuration manager for now as a result of the HTML generator using it # directly as configuration. @GObject.Property(type=bool, default=True) def high_contrast(self) -> bool: """Get whether high contrast output should be used for screen rendering. :return: Whether visible :rtype: bool """ return Adw.StyleManager.get_default().get_high_contrast() # TODO remove ~early 2025 ##################################################### def get_markdown_syntax_hightlighting_enabled(self) -> bool: """Get markdown syntax highlighting is enabled. :return: Highlighting enabled :rtype: bool """ return self.settings.get_value(self.MARKDOWN_SYNTAX_HIGHLIGHTING) def get_hide_editor_headerbar(self) -> bool: """Get whether to hide the editor headerbar. :return: Whether to hide :rtype: bool """ return self.settings.get_value(self.HIDE_EDITOR_HEADERBAR) def get_hide_editor_headerbar_when_fullscreen(self) -> bool: """Get whether to hide the editor headerbar when fullscreen. :return: Whether to hide :rtype: bool """ return self.settings.get_value(self.HIDE_HEADERBAR_WHEN_FULLSCREEN) ############################################################################### @staticmethod def set_app_id(app_id: str) -> None: if not ConfigManager._instance: ConfigManager._app_id = app_id @staticmethod def get_default() -> ConfigManager: if not ConfigManager._instance: settings = Gio.Settings.new(ConfigManager._app_id) ConfigManager._instance = ConfigManager(settings) return ConfigManager._instance iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/const.py.in000066400000000000000000000007651507102636600236360ustar00rootroot00000000000000#!@PYTHON@ APP_ID = "@APPID@" GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@" LOCALEDIR = "@LOCALE_DIR@" NAME = "@NAME@" PKGDATADIR = "@DATA_DIR@" PROFILE = "@PROFILE@" VERSION = "@VERSION@" IS_DEVEL = PROFILE == "Devel" SUFFIX = " (Devel)" if IS_DEVEL else "" SHORT_NAME = GETTEXT_PACKAGE APP_ID_CHANGE_VERSION = "0.2.7" # Mirroring libadwaita/src/stylesheet/widgets/_header-bar.scss:2: min-height: 47px; # Used for the height of padding to account for overlay header bars (pixels) HEADER_BAR_HEIGHT = 47 iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/database.py000066400000000000000000000177671507102636600236610ustar00rootroot00000000000000from __future__ import annotations from gi.repository import Gio, GLib import itertools import logging import os import sqlite3 from threading import current_thread, Lock from typing import Optional from iotas.config_manager import ConfigManager class DbCursor: """ Database cursor. """ def __init__(self, obj: Database, commit: bool = False) -> None: self.__obj = obj self.__commit = commit self.__cursor: Optional[sqlite3.Connection] = None def __enter__(self) -> sqlite3.Connection: thread_id = current_thread().name app = Gio.Application.get_default() # App can be None for unit tests if app and thread_id in app.cursors.keys(): cursor = app.cursors[thread_id] return cursor else: cursor = self.__obj.get_cursor() self.__cursor = cursor return cursor def __exit__(self, type, value, traceback) -> None: if self.__cursor is not None: if self.__commit: self.__obj.acquire_lock() self.__cursor.commit() self.__obj.release_lock() self.__cursor.close() self.__cursor = None class DbLock: """ Database lock. """ def __init__(self) -> None: self.__lock = Lock() self.__locked = False def acquire(self) -> None: """Acquire lock.""" self.__locked = True self.__lock.acquire() def release(self) -> None: """Release lock.""" self.__locked = False self.__lock.release() @property def locked(self) -> bool: return self.__locked class Database: """ Base database object. """ DATA_SUBPATH = "iotas" FILENAME = "notes.db" VERSION = 3 __fts_creation = """ CREATE VIRTUAL TABLE note_fts_idx USING fts5(title, note_content, content='note', content_rowid='id'); CREATE TRIGGER note_ai AFTER INSERT ON note BEGIN INSERT INTO note_fts_idx(rowid, title, note_content) VALUES (new.id, new.title, new.content); END; CREATE TRIGGER note_ad AFTER DELETE ON note BEGIN INSERT INTO note_fts_idx(note_fts_idx, rowid, title, note_content) VALUES('delete', old.id, old.title, old.content); END; CREATE TRIGGER note_au AFTER UPDATE ON note BEGIN INSERT INTO note_fts_idx(note_fts_idx, rowid, title, note_content) VALUES('delete', old.id, old.title, old.content); INSERT INTO note_fts_idx(rowid, title, note_content) VALUES (new.id, new.title, new.content); END; """ __create_script = f""" CREATE TABLE note (id INTEGER PRIMARY KEY, title TEXT NOT NULL, content TEXT NOT NULL, excerpt TEXT NOT NULL, last_modified INT NOT NULL, favourite BOOLEAN NOT NULL, category TEXT NOT NULL, remote_id INT NOT NULL, dirty BOOLEAN NOT NULL, locally_deleted BOOLEAN NOT NULL, etag TEXT, read_only BOOLEAN NOT NULL DEFAULT false, failed_pushes TEXT); CREATE index idx_note_last_modified ON note(last_modified); CREATE index idx_note_remote_id ON note(remote_id); {__fts_creation} """ # A migration is a tuple comprising the query and whether we want to resync from the server __migrations = {} __migrations[1] = ("ALTER TABLE note ADD COLUMN read_only BOOLEAN NOT NULL DEFAULT false", True) __second_migration = f"""{__fts_creation} INSERT INTO note_fts_idx (rowid, title, note_content) SELECT id, title, content FROM note; """ __migrations[2] = (__second_migration, True) __migrations[3] = ("ALTER TABLE note ADD COLUMN failed_pushes TEXT", False) def __init__(self, custom_directory: Optional[str] = None) -> None: self.__thread_lock = DbLock() # Allow for custom directory for testing if custom_directory: self.__db_directory = custom_directory else: self.__db_directory = os.path.join(GLib.get_user_data_dir(), self.DATA_SUBPATH) self.__db_path = os.path.join(self.__db_directory, self.FILENAME) f = Gio.File.new_for_path(self.__db_path) if not f.query_exists(): try: d = Gio.File.new_for_path(self.__db_directory) if not d.query_exists(): d.make_directory_with_parents() with DbCursor(self, True) as sql: sql.executescript(self.__create_script) sql.execute("PRAGMA user_version=%s" % self.VERSION) except Exception as e: logging.error("DB init error: {}".format(e)) raise (e) else: current_version = self.__get_version() if current_version < self.VERSION: self.__run_migrations(current_version) elif current_version > self.VERSION: versions = f"v{current_version} > v{self.VERSION}" logging.warning(f"Database schema version is newer than expected ({versions})") def acquire_lock(self): self.__thread_lock.acquire() def release_lock(self): self.__thread_lock.release() def execute(self, request: str) -> list: """Execute a query :param str request: The request :return: A list of ids, if applicable :rtype: list """ try: ids = [] db = Gio.Application.get_default().db with DbCursor(db) as sql: result = sql.execute(request) ids += list(itertools.chain(*result)) return ids except Exception as e: logging.error("DB execute error: {} for {}".format(e, request)) return [] def get_cursor(self) -> sqlite3.Connection: """Get a cursor. :return: The cursor :rtype: sqlite3.Connection """ return sqlite3.connect(self.__db_path) def trash(self) -> None: """Trash the database, remove the file.""" os.remove(self.__db_path) def __get_version(self) -> int: request = "PRAGMA user_version" try: version = None with DbCursor(self) as sql: result = sql.execute(request) row = result.fetchone() if isinstance(row, tuple) and len(row) == 1: version = row[0] except Exception as e: logging.error("DB execute error: {} for {}".format(e, request)) if not version: logging.warning("Didn't get version from DB, using 1") version = 1 return version def __set_version(self, version: int) -> None: if not isinstance(version, int): return request = f"PRAGMA user_version = {version}" try: with DbCursor(self) as sql: sql.execute(request) except Exception as e: logging.error("DB execute error: {} for {}".format(e, request)) def __run_migrations(self, current_version: int) -> None: logging.info( "Running database schema migration from v{} to v{}".format( current_version, self.VERSION ) ) resync_requested = False in_error = False while current_version != self.VERSION: request, resync = self.__migrations[current_version + 1] try: with DbCursor(self) as sql: sql.executescript(request) except Exception as e: logging.error("DB execute error: {} for {}".format(e, request)) in_error = True break current_version += 1 if resync: resync_requested = True if resync_requested: ConfigManager.get_default().nextcloud_prune_threshold = 0 if not in_error: self.__set_version(current_version) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/editor.py000066400000000000000000002033571507102636600233730ustar00rootroot00000000000000from gettext import gettext as _ import gi gi.require_version("GtkSource", "5") from gi.repository import Adw, Gdk, Gio, GLib, GObject, Gtk, GtkSource, Pango from dataclasses import dataclass import logging from typing import Any, Optional import webbrowser from iotas.attachment import Attachment from iotas.category_header_bar import CategoryHeaderBar from iotas.category_treeview_list_store import CategoryTreeViewListStore from iotas.config_manager import ConfigManager, HeaderBarVisibility import iotas.const as const from iotas.editor_rename_header_bar import EditorRenameHeaderBar from iotas.editor_search_header_bar import EditorSearchHeaderBar from iotas.editor_text_view import EditorTextView from iotas.export_dialog import ExportDialog from iotas.focus_mode_helper import FocusModeHelper from iotas.font_size_selector import FontSizeSelector from iotas.formatting_header_bar import FormattingHeaderBar from iotas.note import Note from iotas.outline_dialog import OutlineDialog from iotas.outline_generator import OutlineHeading, OutlineGenerator from iotas.render_search_header_bar import RenderSearchHeaderBar from iotas.sync_manager import SyncManager from iotas.text_utils import ( parse_any_url_at_iter, parse_markdown_automatic_link, parse_markdown_inline_link, ) from iotas.theme_selector import ThemeSelector from iotas.ui_utils import add_mouse_button_accel, is_likely_mobile_device @dataclass class EditorSessionDetails: note: Note scroll_position: float cursor_position: int direct_switching: Optional[bool] = None @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/editor.ui") class Editor(Adw.Bin): __gtype_name__ = "Editor" __gsignals__ = { "note-modified": (GObject.SignalFlags.RUN_FIRST, None, (Note,)), "note-deleted": (GObject.SignalFlags.RUN_FIRST, None, (Note,)), "category-changed": (GObject.SignalFlags.RUN_FIRST, None, (Note, str)), "exit": (GObject.SignalFlags.RUN_FIRST, None, ()), } LINE_LENGTH_STEP = 50 TOAST_DURATION = 3.0 HEADERBAR_HIDE_DELAY = 2000 MARGIN_BELOW_CURSOR = 22 _top_bar_revealer: Gtk.Revealer = Gtk.Template.Child() _bottom_bar_revealer: Gtk.Revealer = Gtk.Template.Child() _title_label: Gtk.Label = Gtk.Template.Child() _is_dirty: Gtk.Label = Gtk.Template.Child() _headerbar_stack: Gtk.Stack = Gtk.Template.Child() _main_header_bar: Adw.HeaderBar = Gtk.Template.Child() _rename_header_bar: EditorRenameHeaderBar = Gtk.Template.Child() _search_header_bar: EditorSearchHeaderBar = Gtk.Template.Child() _category_header_bar: CategoryHeaderBar = Gtk.Template.Child() _formatting_header_bar: FormattingHeaderBar = Gtk.Template.Child() _render_search_header_bar: RenderSearchHeaderBar = Gtk.Template.Child() _menu_button: Gtk.MenuButton = Gtk.Template.Child() _title_button: Gtk.Button = Gtk.Template.Child() _content_overlay: Gtk.Overlay = Gtk.Template.Child() _render_edit_stack: Gtk.Stack = Gtk.Template.Child() _render_edit_button_stack: Gtk.Stack = Gtk.Template.Child() _render_button: Gtk.Button = Gtk.Template.Child() _edit_button: Gtk.Button = Gtk.Template.Child() _sourceview: EditorTextView = Gtk.Template.Child() _editor_scrolledwin: Gtk.ScrolledWindow = Gtk.Template.Child() _read_only_image: Gtk.Image = Gtk.Template.Child() _render_loading: Adw.StatusPage = Gtk.Template.Child() _toast_overlay: Adw.ToastOverlay = Gtk.Template.Child() _top_margin_box: Gtk.Box = Gtk.Template.Child() _bottom_margin_box: Gtk.Box = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__active = False self.__note: Optional[Note] = None self.__note_had_edit = False self.__updating_from_remote = False self.__sync_authenticated = False self.__buffer_handlers: list[int] = [] self.__current_note_handlers: list[int] = [] # Any types to accommodate for lazy loading self.__render_view: Optional[Any] = None self.__html_generator: Optional[Any] = None self.__focus_mode_action: Gio.SimpleAction self.__cancel_action: Gio.SimpleAction self.__previous_sessions: list[EditorSessionDetails] = [] self.__pointer_cursor_y: Optional[float] = None self.__outline_dialog: Optional[OutlineDialog] = None self.__hiding_bars_timeout = None self.__outline_generator = OutlineGenerator() self.__config_manager = ConfigManager.get_default() self._menu_button.get_popover().add_child(ThemeSelector(), "theme") self.__font_size_selector = FontSizeSelector() self._menu_button.get_popover().add_child(self.__font_size_selector, "fontsize") self._sourceview.connect("margins-updated", lambda _o: self.__update_margin_box_heights()) self._category_header_bar.connect("categories-changed", self.__on_category_changed) self._category_header_bar.connect("abort", self.__on_abort_category_change) self._search_header_bar.connect( "resumed", lambda _o: self.__enter_search(resuming=True, for_replace=False) ) self._search_header_bar.connect( "open-for-replace", lambda _o: self.__enter_search(resuming=False, for_replace=True) ) self._render_search_header_bar.connect( "resumed", lambda _o: self.__enter_search(resuming=True, for_replace=False) ) self._rename_header_bar.connect("renamed", self.__on_title_renamed) self._rename_header_bar.connect("cancelled", self.__on_rename_cancelled) self._formatting_header_bar.connect( "height-change", lambda _o: self.__update_toolbar_underlay_margins() ) self._render_edit_button_stack.set_visible(self.__config_manager.markdown_render_enabled) self.__categories_model = None style_manager = Adw.StyleManager.get_default() style_manager.connect("notify::dark", lambda _o, _v: self.__update_scheme_and_dark_style()) style_manager.connect( "notify::high-contrast", lambda _o, _v: self.__update_scheme_and_dark_style() ) self.__config_manager.connect_changed( ConfigManager.MARKDOWN_DETECT_SYNTAX, self.__on_detect_syntax_changed, ) self.__config_manager.connect_changed( ConfigManager.EDITOR_THEME, self.__on_theme_changed, ) self.__config_manager.connect_changed( ConfigManager.MARKDOWN_RENDER, self.__on_render_enabled_changed, ) self.__config_manager.connect_changed( ConfigManager.MARKDOWN_KEEP_WEBKIT_PROCESS, self.__on_keep_webkit_changed, ) self.__config_manager.connect_changed( ConfigManager.MARKDOWN_TEX_SUPPORT, self.__on_tex_support_changed, ) self.__config_manager.connect_changed( ConfigManager.LINE_LENGTH, self.__refresh_line_length_from_setting, ) self.__push_font_updates() style_manager.connect( "notify::monospace-font-name", lambda _o, _v: self.__push_font_updates() ) style_manager.connect( "notify::document-font-name", lambda _o, _v: self.__push_font_updates() ) self.__config_manager.connect_changed( ConfigManager.USE_MONOSPACE_FONT, self.__push_font_updates, ) self.__config_manager.connect_changed( ConfigManager.MARKDOWN_USE_MONOSPACE_FONT, self.__push_font_updates, ) self.__config_manager.connect_changed( ConfigManager.EDITOR_FORMATTING_BAR_VISIBILTY, self.__update_for_formatting_bar_setting_change, ) self.__cache_formatting_bar_visibility() self.__config_manager.connect_changed( ConfigManager.EDITOR_HEADER_BAR_VISIBILTY, self.__update_for_header_bar_setting_change, ) self.__cache_header_bar_visibility() self.__focus_mode_helper = FocusModeHelper(self._sourceview.get_buffer()) def setup( self, model: CategoryTreeViewListStore, sync_manager: SyncManager, ) -> None: """Perform initial setup. :param CategoryTreeViewListStore model: Tree model :param SyncManager sync_manager: Sync manager """ self.__setup_actions() self._category_header_bar.setup(model) self.__sync_manager = sync_manager self._search_header_bar.setup(self._sourceview) self._render_search_header_bar.setup() self.__font_size_selector.setup() self.__refresh_line_length_from_setting() self._formatting_header_bar.setup(self._sourceview) window = self.get_root() window.connect("notify::fullscreened", self.__on_window_fullscreened) self._sourceview.setup() def init_note(self, note: Note, restore_session: Optional[EditorSessionDetails]) -> None: """Initialise editing session. :param Note note: Note to edit :param EditorSessionDetails restore_session: Session to restore, optional """ self.current_note = note self.note_had_edit = False buffer = self._sourceview.get_buffer() for handler_id in self.__buffer_handlers: buffer.disconnect(handler_id) self._sourceview.set_visible(True) self._sourceview.spellchecker_enabled = False self._formatting_header_bar.prepare() buffer.set_text(note.content) def delayed_enable_spellchecker(): self._sourceview.spellchecker_enabled = True if self.__config_manager.spelling_enabled: GLib.idle_add(delayed_enable_spellchecker) self.__buffer_handlers = [] handler_id = buffer.connect("changed", lambda _o: self.__on_buffer_changed()) self.__buffer_handlers.append(handler_id) self.__setup_syntax_detection() self.__setup_note_signals() self.__update_title() self.__update_dirty() self._read_only_image.set_visible(note.read_only) self._sourceview.set_editable(not note.read_only) self.__update_readonly_actions() # Handle case of leaflet swiped back to index while renaming or searching if self._headerbar_stack.get_visible_child() in ( self._rename_header_bar, self._search_header_bar, self._category_header_bar, self._render_search_header_bar, ): self._headerbar_stack.set_visible_child(self._main_header_bar) if self._render_edit_stack.get_visible_child() == self.__render_view: self.__toggle_render() else: # This only sets the widget visibility; there's logic below which determines whether, # based on configuration, the bottom bar is shown self._formatting_header_bar.set_visible(True) # By popping this note off our previous sessions it allows returning from the index to # switching between two notes self.__flush_note_from_previous_sessions(note) if restore_session: buffer = self._sourceview.get_buffer() cursor_iter = buffer.get_iter_at_offset(restore_session.cursor_position) scroll_position = restore_session.scroll_position GLib.idle_add(self._editor_scrolledwin.get_vadjustment().set_value, scroll_position) else: # Set scroll to top cursor_iter = buffer.get_start_iter() scroll_position = 0 self._editor_scrolledwin.get_vadjustment().set_value(scroll_position) buffer.place_cursor(cursor_iter) self.__update_scheme_and_dark_style() if not (restore_session and restore_session.direct_switching): self._top_bar_revealer.set_reveal_child(True) if ( self.__config_manager.markdown_detect_syntax and self.__formatting_bar_visibility_setting != HeaderBarVisibility.DISABLED ): self._bottom_bar_revealer.set_reveal_child(True) elif self._bottom_bar_revealer.get_reveal_child(): self._bottom_bar_revealer.set_reveal_child(False) self.__update_margin_box_heights() GLib.idle_add(self.__update_toolbar_underlay_margins) self.__check_and_hide_bars_after_delay() if self.__focus_mode_action.get_state(): self.__focus_mode_helper.active = True # Handle initialising in view mode if ( self.__config_manager.markdown_render_enabled and self.__config_manager.markdown_default_to_render and note.content.strip() != "" ): # Prevent a flash of the editor while loading rendered view self._sourceview.set_visible(False) # The idle avoids locked high CPU usage after first render GLib.idle_add(self.__toggle_render) if is_likely_mobile_device(): if self.__config_manager.editor_formatting_bar_visibility in ( HeaderBarVisibility.AUTO_HIDE, HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY, ): logging.warning("Auto hiding currently provides a poor experience on mobile") if restore_session: self.__restore_session_location(restore_session) def close_note(self) -> None: """Close the current editing note.""" if not self.__note: return self.__store_session_details() if self.__hiding_bars_timeout: GLib.source_remove(self.__hiding_bars_timeout) self.__hiding_bars_timeout = None if self.__outline_dialog: self.__outline_dialog.close() if self.current_note.title_is_top_line: self.current_note.title_is_top_line = False for handler in self.__current_note_handlers: self.__note.disconnect(handler) self.__current_note_handlers = [] self.__focus_mode_helper.active = False self._bottom_bar_revealer.set_visible(True) self.current_note = None # If cleaning up WebKit process after each render do that now on closing the note. # Don't do this for other cases as the switch is visible as the navigation page # animates across. if not self.__config_manager.markdown_keep_webkit_process: if self._render_edit_stack.get_visible_child() == self.__render_view: self._sourceview.set_visible(True) self.__toggle_render() def cancel(self) -> None: """Perform a cancel action. Action performed will depend on whether currently editing the title. """ if self._headerbar_stack.get_visible_child() in ( self._rename_header_bar, self._category_header_bar, ): self._headerbar_stack.set_visible_child(self._main_header_bar) self._sourceview.grab_focus() self.__check_and_hide_bars_after_delay() elif self._headerbar_stack.get_visible_child() == self._search_header_bar: self.__exit_search() elif self._headerbar_stack.get_visible_child() == self._render_search_header_bar: self.__exit_render_search() else: self._search_header_bar.disable_actions() self._render_search_header_bar.disable_actions() self.emit("exit") def set_sync_authenticated(self, authenticated: bool) -> None: """Set that an authenticated sync session exists. :param bool authenticated: Whether authenticated """ self.__sync_authenticated = authenticated def focus_textview_if_editing(self) -> None: """Grab the focus to the TextView.""" # Don't focus if showing render view if self._render_edit_stack.get_visible_child() != self._editor_scrolledwin: return # Don't focus if search etc toolbar is active if ( self._top_bar_revealer.get_reveal_child() and self._headerbar_stack.get_visible_child() != self._main_header_bar ): return self._sourceview.grab_focus() def update_for_dialog_visibility(self, visible: bool) -> None: """Update if dialogs visible, disabling actions. :param bool visible: Whether a dialog is visible """ if self.active: self.__cancel_action.set_enabled(not visible) def get_previous_session(self) -> Optional[EditorSessionDetails]: """Get previous session details. :return: Session details :rtype: EditorSessionDetails, optional """ if self.__previous_sessions: return self.__previous_sessions[-1] else: return None def show_downloaded_attachment_in_render(self, attachment: Attachment) -> None: """Update render to display newly available attachment. :param Attachment attachment: Attachment to show """ if self.__note is None or attachment.note_id != self.__note.id: return if self._render_edit_stack.get_visible_child() != self.__render_view: return logging.debug(f"Attachment '{attachment.filename}' downloaded") self.__render_view.show_attached_image(attachment) @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @active.setter def set_active(self, value: bool) -> None: self.__active = value self.__enable_actions(value) if value and self.__config_manager.markdown_detect_syntax: self._formatting_header_bar.active = True else: self._formatting_header_bar.active = False @GObject.Property(type=Note, default=None) def current_note(self) -> Optional[Note]: return self.__note @current_note.setter def set_current_note(self, value: Note) -> None: self.__note = value @GObject.Property(type=bool, default=False) def editing(self) -> bool: """Whether editing. :returns: Whether editing :rtype: bool """ # Using the editor having an active note to determine if return self.__note is not None @GObject.Property(type=bool, default=False) def note_had_edit(self) -> bool: """Get whether note was modified during session. Determines whether excerpt will later be updated. :returns: Whether modified :rtype: bool """ return self.__note_had_edit @note_had_edit.setter def set_note_had_edit(self, value: bool) -> None: """Set whether note was modified during session.""" self.__note_had_edit = value @Gtk.Template.Callback() def _on_mouse_back_button_click( self, _gesture: Gtk.GestureClick, _n_press: int, _x: float, _y: float ) -> None: self.cancel() @Gtk.Template.Callback() def _on_editor_single_click( self, gesture: Gtk.GestureSingle, _seq: Optional[Gdk.EventSequence] = None ) -> None: # If the click is in the visible top row of the buffer where the show-triggering motion area # will be don't hide otherwise we immediately hide and re-show, which is glitchy. if not self.__click_in_top_margin(gesture): self.__check_and_hide_header_bar() if not self.__click_in_bottom_margin(gesture): self.__check_and_hide_formatting_bar() event = gesture.get_current_event() if event is None: return state = event.get_modifier_state() if state & Gdk.ModifierType.CONTROL_MASK and state & Gdk.ModifierType.BUTTON1_MASK: _interpreted, x, y = gesture.get_point(None) self.__check_and_handle_link_click(x, y) @Gtk.Template.Callback() def _on_top_margin_motion( self, _controller: Gtk.EventControllerMotion, _x: float, _y: float ) -> None: self.__check_and_show_header_bar() @Gtk.Template.Callback() def _on_top_margin_clicked( self, gesture: Gtk.GestureClick, n_press: int, _x: float, _y: float ) -> None: self.__check_and_show_header_bar() @Gtk.Template.Callback() def _on_bottom_margin_motion( self, _controller: Gtk.EventControllerMotion, _x: float, _y: float ) -> None: self.__check_and_show_formatting_bar() @Gtk.Template.Callback() def _on_motion(self, _controller: Gtk.EventControllerMotion, _x: float, y: float) -> None: self.__pointer_cursor_y = y @Gtk.Template.Callback() def _on_motion_leave(self, _controller: Gtk.EventControllerMotion) -> None: self.__pointer_cursor_y = None @Gtk.Template.Callback() def _on_bottom_margin_clicked( self, gesture: Gtk.GestureClick, n_press: int, _x: float, _y: float ) -> None: self.__check_and_show_formatting_bar() @Gtk.Template.Callback() def _on_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> bool: # Prevent some keys from resulting in the bars re-hiding if keyval not in ( Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab, Gdk.KEY_Alt_L, Gdk.KEY_Alt_R, Gdk.KEY_Meta_L, Gdk.KEY_Meta_R, Gdk.KEY_Control_L, Gdk.KEY_Control_R, Gdk.KEY_Shift_L, Gdk.KEY_Shift_R, ): check_mouse_cursor = True self.__check_and_hide_header_bar(check_mouse_cursor) self.__check_and_hide_formatting_bar(check_mouse_cursor) return Gdk.EVENT_PROPAGATE def __setup_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() action = Gio.SimpleAction.new("rename") action.connect("activate", lambda _o, _p: self.__apply_rename()) action_group.add_action(action) app.set_accels_for_action("editor.rename", ["F2"]) action = Gio.SimpleAction.new("edit-category") action.connect("activate", lambda _o, _p: self.__edit_category()) action_group.add_action(action) app.set_accels_for_action("editor.edit-category", ["e"]) action = Gio.SimpleAction.new("enter-search") action.connect("activate", lambda _o, _p: self.__on_enter_search()) action_group.add_action(action) app.set_accels_for_action("editor.enter-search", ["f"]) action = Gio.SimpleAction.new("toggle-render") action.connect("activate", lambda _o, _p: self.__toggle_render()) action_group.add_action(action) app.set_accels_for_action("editor.toggle-render", ["d"]) action = Gio.SimpleAction.new("go-back-or-cancel") action.connect("activate", lambda _o, _p: self.cancel()) action_group.add_action(action) self.__cancel_action = action app.set_accels_for_action("editor.go-back-or-cancel", ["Escape"]) action = Gio.SimpleAction.new("clear-category") action.connect("activate", lambda _o, _p: self.__on_clear_category()) action_group.add_action(action) app.set_accels_for_action("editor.clear-category", ["Delete"]) action = Gio.SimpleAction.new("create-new-note") action.connect("activate", lambda _o, _v: self.__on_create_new_note()) action_group.add_action(action) app.set_accels_for_action("editor.create-new-note", ["n"]) action = Gio.SimpleAction.new("export-note") action.connect("activate", lambda _o, _p: self.__on_export_note()) action_group.add_action(action) app.set_accels_for_action("editor.export-note", ["s"]) action = Gio.SimpleAction.new("show-outline") action.connect("activate", lambda _o, _p: self.__show_outline()) action_group.add_action(action) app.set_accels_for_action("editor.show-outline", ["j"]) action = Gio.SimpleAction.new("delete-note") action.connect("activate", lambda _o, _p: self.emit("note-deleted", self.__note)) action_group.add_action(action) action = Gio.SimpleAction.new("increase-line-length") action.connect("activate", lambda _o, _p: self.__on_increase_line_length()) action_group.add_action(action) app.set_accels_for_action("editor.increase-line-length", ["Up"]) action = Gio.SimpleAction.new("decrease-line-length") action.connect("activate", lambda _o, _p: self.__on_decrease_line_length()) action_group.add_action(action) app.set_accels_for_action("editor.decrease-line-length", ["Down"]) action = Gio.SimpleAction.new("toggle-line-length-limit") action.connect("activate", lambda _o, _p: self.__on_line_length_limit_toggle()) action_group.add_action(action) app.set_accels_for_action("editor.toggle-line-length-limit", ["l"]) action = Gio.SimpleAction.new("increase-font-size") action.connect("activate", lambda _o, _v: self.__font_size_selector.increase()) action_group.add_action(action) app.set_accels_for_action("editor.increase-font-size", ["plus", "equal"]) action = Gio.SimpleAction.new("decrease-font-size") action.connect("activate", lambda _o, _v: self.__font_size_selector.decrease()) action_group.add_action(action) app.set_accels_for_action( "editor.decrease-font-size", ["minus", "underscore"] ) action = Gio.SimpleAction.new("reset-font-size") action.connect("activate", lambda _o, _v: self.__font_size_selector.reset()) action_group.add_action(action) app.set_accels_for_action("editor.reset-font-size", ["0"]) action = Gio.SimpleAction.new_stateful("focus-mode", None, GLib.Variant("b", False)) action.connect("change-state", self.__on_focus_mode_toggle) action_group.add_action(action) app.set_accels_for_action("editor.focus-mode", ["f"]) self.__focus_mode_action = action action = Gio.SimpleAction.new("show-menu") action.connect("activate", lambda _o, _p: self._menu_button.popup()) action_group.add_action(action) app.set_accels_for_action("editor.show-menu", ["F10"]) action = Gio.SimpleAction.new("focus-editor") action.connect("activate", lambda _o, _p: self.__focus_editor()) action_group.add_action(action) app.set_accels_for_action("editor.focus-editor", ["e"]) action = Gio.SimpleAction.new("focus-header-bar") action.connect("activate", lambda _o, _p: self.__focus_header_bar()) action_group.add_action(action) app.set_accels_for_action("editor.focus-header-bar", ["h"]) action = Gio.SimpleAction.new("focus-formatting-bar") action.connect("activate", lambda _o, _p: self.__focus_formatting_bar()) action_group.add_action(action) app.set_accels_for_action("editor.focus-formatting-bar", ["f"]) app.get_active_window().insert_action_group("font-size-selector", action_group) self.__action_group = action_group self.__action_group = action_group app.get_active_window().insert_action_group("editor", action_group) def __enable_actions(self, enabled: bool) -> None: """Toggle whether editor actions are enabled. :param bool enabled: New value """ actions = self.__action_group.list_actions() for action in actions: self.__action_group.lookup_action(action).set_enabled(enabled) # Disable specific actions for read-only if enabled and self.__note is not None and self.__note.read_only: self.__update_readonly_actions() def __setup_syntax_detection(self) -> None: buffer = self._sourceview.get_buffer() if self.__config_manager.markdown_detect_syntax: language = GtkSource.LanguageManager.get_default().get_language("iotas-markdown") buffer.set_language(language) buffer.set_highlight_syntax(True) else: buffer.set_language(None) buffer.set_highlight_syntax(False) def __on_checkbox_toggled(self, _obj: GObject.Object, line: int, new_value: bool) -> None: buffer = self._sourceview.get_buffer() def get_iter_inside_checkbox(line): (success, line_start) = buffer.get_iter_at_line(line) if not success: return None line_end = line_start.copy() line_end.forward_to_line_end() match = line_start.forward_search("[", Gtk.TextSearchFlags.VISIBLE_ONLY, line_end) if match is None: logging.warn(f"Couldn't find checkbox on line {line}") return None (_, match_end) = match return match_end match_end = get_iter_inside_checkbox(line) if match_end is None: return buffer.begin_user_action() buffer.insert(match_end, "x" if new_value else " ") match_end = get_iter_inside_checkbox(line) if match_end is None: buffer.end_user_action() return match_end.forward_char() delete_end = match_end.copy() delete_end.forward_char() buffer.delete(match_end, delete_end) buffer.end_user_action() def __on_webview_loaded(self, _obj: GObject.Object) -> None: assert self.__render_view if self.__render_view.exporting: self.__render_view.exporting = False else: self._render_edit_button_stack.set_visible_child(self._edit_button) if not self.__render_view.get_visible(): self.__render_view.set_visible(True) self._render_edit_stack.set_visible_child(self.__render_view) def __on_enter_search(self) -> None: if self._search_header_bar.active: self._search_header_bar.refocus_search_and_select() else: self.__enter_search(resuming=False, for_replace=False) def __on_title_renamed(self, _obj: GObject.Object, new_title: str) -> None: assert self.__note if self.__note.title != new_title: self.__note.title = new_title if self.__note.title_is_top_line: self.__note.title_is_top_line = False self.__note.flag_changed() self.note_had_edit = True # Always called on UI thread self.emit("note-modified", self.__note) self._headerbar_stack.set_visible_child(self._main_header_bar) self.__check_and_hide_bars_after_delay() self._sourceview.grab_focus() def __on_rename_cancelled(self, _obj: GObject.Object) -> None: self._headerbar_stack.set_visible_child(self._main_header_bar) self.__check_and_hide_bars_after_delay() self._sourceview.grab_focus() def __on_clear_category(self) -> None: if not self._top_bar_revealer.get_reveal_child(): return if self._headerbar_stack.get_visible_child() == self._category_header_bar: self._category_header_bar.clear_and_apply() def __on_export_note(self) -> None: assert self.__note if self.__html_generator is None: self.__initialise_html_generator() self.__push_font_updates() dialog = ExportDialog( self.__note, self.__html_generator, self.__sync_manager, self.__ensure_webkit_initialised, ) dialog.present(self) def __on_detect_syntax_changed(self) -> None: if self.active: self.__setup_syntax_detection() if self.__config_manager.markdown_detect_syntax: if self.__formatting_bar_visibility_setting != HeaderBarVisibility.DISABLED: self.__show_formatting_bar() self._formatting_header_bar.active = True else: self.__hide_formatting_bar() self._formatting_header_bar.active = False def __on_theme_changed(self) -> None: if self.active and self.__config_manager.markdown_detect_syntax: self.__update_scheme_and_dark_style() def __on_render_enabled_changed(self) -> None: enabled = self.__config_manager.markdown_render_enabled self._render_edit_button_stack.set_visible(enabled) if ( not enabled and self.active and self._render_edit_stack.get_visible_child() == self.__render_view ): self.__toggle_render(force=True) def __on_keep_webkit_changed(self) -> None: keep = self.__config_manager.markdown_keep_webkit_process if not keep and ( not self.active or self._render_edit_stack.get_visible_child() == self._editor_scrolledwin ): if self.__render_view is not None: logging.debug("Calling terminate for WebKit process") self.__render_view.terminate_web_process() def __on_tex_support_changed(self) -> None: assert self.__note if self.active and self._render_edit_stack.get_visible_child() == self.__render_view: self.__render_view.render_retaining_scroll(self.__note, None) def __on_increase_line_length(self) -> None: setting_max = self.__config_manager.line_length_max current_length = self.__config_manager.line_length if current_length == setting_max: logging.info("Line length limit already disabled") return else: new_length = current_length + self.LINE_LENGTH_STEP if new_length < self.get_width() - 2 * self._sourceview.STANDARD_MARGIN: self.__config_manager.line_length = new_length logging.info(f"Line length increased to {new_length}px") else: self.__config_manager.line_length = setting_max self.__notify_line_length_limit_disabled() def __on_decrease_line_length(self) -> None: setting_max = self.__config_manager.line_length_max current_length = self.__config_manager.line_length new_length = current_length - self.LINE_LENGTH_STEP if current_length == setting_max: new_length = min(self.get_width(), self.__config_manager.default_line_length) self.__config_manager.line_length = new_length self.__notify_line_length_limit_enabled(new_length) elif new_length >= self.LINE_LENGTH_STEP: self.__config_manager.line_length = new_length logging.info(f"Line length decreased to {new_length}px") def __on_line_length_limit_toggle(self) -> None: setting_maximum = self.__config_manager.line_length_max if self.__config_manager.line_length == setting_maximum: new_length = self.__config_manager.default_line_length self.__config_manager.line_length = new_length self.__notify_line_length_limit_enabled(new_length) else: self.__config_manager.line_length = setting_maximum self.__notify_line_length_limit_disabled() def __on_window_fullscreened(self, window: Gtk.Window, _param: GObject.ParamSpec) -> None: if not self.active: return if self._render_edit_stack.get_visible_child() == self.__render_view: self.__render_view.update_style() if self.__header_bar_visibility_setting == HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY: if window.is_fullscreen(): self.__hide_header_bar() else: self.__show_header_bar() if self.__config_manager.markdown_detect_syntax: setting = self.__formatting_bar_visibility_setting if setting == HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY: if window.is_fullscreen(): self.__hide_formatting_bar() else: self.__show_formatting_bar() self.__update_toolbar_underlay_margins() def __on_render_single_click(self) -> None: self.__check_and_hide_header_bar() def __on_render_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> bool: if self._headerbar_stack.get_visible_child() != self._main_header_bar: return Gdk.EVENT_PROPAGATE result = self._render_search_header_bar.check_if_starting(controller, keyval, state) if result: self._render_search_header_bar.enter(self.__render_view, False, type_to_search=True) self._headerbar_stack.set_visible_child(self._render_search_header_bar) self.__show_header_bar() return result def __on_category_changed(self, _obj: CategoryHeaderBar) -> None: changeset = self._category_header_bar.take_changeset() if len(changeset) > 0: (note, old_category) = changeset[0] self.emit("category-changed", note, old_category) self._headerbar_stack.set_visible_child(self._main_header_bar) self.__check_and_hide_bars_after_delay() self._sourceview.grab_focus() def __on_abort_category_change(self, _obj: CategoryHeaderBar) -> None: self._headerbar_stack.set_visible_child(self._main_header_bar) self.__check_and_hide_bars_after_delay() self._sourceview.grab_focus() def __on_focus_mode_toggle(self, action: Gio.SimpleAction, state: bool) -> None: action.set_state(state) self.__focus_mode_helper.active = state def __on_create_new_note(self) -> None: self.emit("exit") content = "" buffer = self._sourceview.get_buffer() if buffer.get_has_selection(): (begin, end) = buffer.get_selection_bounds() content = buffer.get_slice(begin, end, False) param = GLib.Variant("s", content) self.activate_action("index.create-note-with-content", param) def __on_buffer_changed(self) -> None: if self.__updating_from_remote: return # Witnessed when closing for conflict if not self.__note: return self.__note.content = self.__get_content() if self.__note.title_is_top_line: self.__note.update_title_from_top_line() self.__note.flag_changed() self.note_had_edit = True # Maintain a margin between the cursor and the bottom of the window self.__check_and_scroll_for_cursor() GLib.idle_add(self.emit, "note-modified", self.__note) def __check_and_scroll_for_cursor(self) -> None: buffer = self._sourceview.get_buffer() insert = buffer.get_iter_at_mark(buffer.get_insert()) rect = self._sourceview.get_iter_location(insert) adj = self._editor_scrolledwin.get_vadjustment() lowest_visible = self._sourceview.get_top_margin() + rect.y + rect.height visible_below_cursor = adj.get_value() + adj.get_page_size() - lowest_visible if visible_below_cursor < self.MARGIN_BELOW_CURSOR: scroll_to = lowest_visible + self.MARGIN_BELOW_CURSOR - adj.get_page_size() adj.set_value(scroll_to) def __notify_line_length_limit_enabled(self, new_length: int) -> None: logging.info(f"Line length re-enabled, to {new_length}px") # Translators: Description, notification, {0} is a number msg = _("Line length now {0}px").format(new_length) self.__show_toast(msg) def __notify_line_length_limit_disabled(self) -> None: logging.info("Line length limit disabled") # Translators: Description, notification self.__show_toast(_("Line length limit disabled")) def __show_toast(self, msg: str) -> None: if not self.active: logging.debug(f"Not showing toast as editor inactive: {msg}") return toast = Adw.Toast.new(msg) toast.set_priority(Adw.ToastPriority.HIGH) toast.set_timeout(self.TOAST_DURATION) self._toast_overlay.dismiss_all() self._toast_overlay.add_toast(toast) def __init_webkit(self) -> None: # Lazy import module in an attempt to reduce startup performance hit on devices with # render view disabled from iotas.markdown_render_view import MarkdownRenderView if self.__html_generator is None: self.__initialise_html_generator() assert self.__html_generator # mypy app = Gio.Application.get_default() track_timing = app.debug_session or app.development_mode self.__render_view = MarkdownRenderView() self.__render_view.connect("checkbox-toggled", self.__on_checkbox_toggled) self.__render_view.connect("loaded", self.__on_webview_loaded) self.__render_view.setup(self.__html_generator, self.__config_manager, track_timing) self._render_edit_stack.add_child(self.__render_view) gesture = Gtk.GestureSingle() gesture.connect("end", lambda _o, _s: self.__on_render_single_click()) self.__render_view.add_controller(gesture) controller = Gtk.EventControllerKey() controller.connect("key-pressed", self.__on_render_key_pressed) self.__render_view.add_controller(controller) self.__push_font_updates() self._render_search_header_bar.bind_property( "active", self.__render_view, "searching", GObject.BindingFlags.SYNC_CREATE ) # Allow using the mouse back button to return to index, typically button #8 def callback(gesture: Gtk.GestureClick, _n_press: int, _x: float, _y: float) -> None: if gesture.get_current_button() == 8: self.cancel() add_mouse_button_accel(self.__render_view, callback) def __setup_note_signals(self) -> None: assert self.__note self.__current_note_handlers = [] handler_id = self.__note.connect("notify::dirty", lambda _o, _v: self.__update_dirty()) self.__current_note_handlers.append(handler_id) handler_id = self.__note.connect("notify::title", lambda _o, _v: self.__update_title()) self.__current_note_handlers.append(handler_id) handler_id = self.__note.connect("remote-content-update", self.__update_content_from_remote) self.__current_note_handlers.append(handler_id) def __get_content(self) -> str: buffer = self._sourceview.get_buffer() (start, end) = buffer.get_bounds() return buffer.get_text(start, end, True) def __update_title(self) -> None: assert self.__note self._title_label.set_label(self.__note.title) def __update_dirty(self) -> None: assert self.__note show_dirty = self.__sync_authenticated and self.__note.dirty and self.__note.title != "" self._is_dirty.set_visible(show_dirty) def __update_content_from_remote(self, _note: Note) -> None: if self.__note and not self.__note.dirty: self.set_sensitive(False) self.__updating_from_remote = True editor_scroll_value = self._editor_scrolledwin.get_vadjustment().get_value() buffer = self._sourceview.get_buffer() insert_iter = buffer.get_iter_at_mark(buffer.get_insert()) pre_offset = insert_iter.get_offset() buffer.set_text(self.__note.content) def delayed_editor_scroll_and_cursor_reset(): self._editor_scrolledwin.get_vadjustment().set_value(editor_scroll_value) if self.__note and len(self.__note.content) > pre_offset: buffer.place_cursor(buffer.get_iter_at_offset(pre_offset)) GLib.idle_add(delayed_editor_scroll_and_cursor_reset) if self._render_edit_stack.get_visible_child() == self.__render_view: self.__render_view.render_retaining_scroll(self.__note, export_format=None) self.__updating_from_remote = False self.set_sensitive(True) # Update outline from remote if self.__outline_dialog: self.__show_outline() def __get_scroll_position(self) -> float: adj = self._editor_scrolledwin.get_vadjustment() value = adj.get_value() upper = adj.get_upper() page_size = adj.get_page_size() if upper > page_size: return value / (upper - page_size) else: return 0.0 def __set_scroll_position(self, position: float) -> None: adj = self._editor_scrolledwin.get_vadjustment() upper = adj.get_upper() page_size = adj.get_page_size() adj.set_value((upper - page_size) * position) def __edit_category(self) -> None: """Show the category editing.""" assert self.__note if not self._top_bar_revealer.get_reveal_child(): self.__show_header_bar() if self._headerbar_stack.get_visible_child() == self._category_header_bar: return elif self._headerbar_stack.get_visible_child() == self._search_header_bar: self.__exit_search() elif self._headerbar_stack.get_visible_child() == self._render_search_header_bar: self.__exit_render_search() self._headerbar_stack.set_visible_child(self._category_header_bar) self._category_header_bar.activate([self.__note]) def __apply_rename(self) -> None: """Show the title rename entry.""" assert self.__note if self.__note.read_only: return if not self._top_bar_revealer.get_reveal_child(): self.__show_header_bar() if self._headerbar_stack.get_visible_child() == self._rename_header_bar: return elif self._headerbar_stack.get_visible_child() == self._search_header_bar: self.__exit_search() elif self._headerbar_stack.get_visible_child() == self._render_search_header_bar: self.__exit_render_search() self._headerbar_stack.set_visible_child(self._rename_header_bar) self._rename_header_bar.enter(self.__note.title) def __enter_search(self, resuming: bool, for_replace: bool) -> None: """Start searching within note.""" if self._render_edit_stack.get_visible_child() == self._editor_scrolledwin: self._search_header_bar.enter(resuming, for_replace) self._headerbar_stack.set_visible_child(self._search_header_bar) else: self._render_search_header_bar.enter(self.__render_view, resuming, type_to_search=False) self._headerbar_stack.set_visible_child(self._render_search_header_bar) if not self._top_bar_revealer.get_reveal_child(): self.__show_header_bar() def __exit_search(self) -> None: """Stop searching within note.""" self._headerbar_stack.set_visible_child(self._main_header_bar) self.__check_and_hide_bars_after_delay() self._sourceview.grab_focus() self._search_header_bar.exit() def __exit_render_search(self) -> None: self._headerbar_stack.set_visible_child(self._main_header_bar) self.__check_and_hide_bars_after_delay() self._render_search_header_bar.exit() def __toggle_render(self, force: bool = False) -> None: """Toggle whether showing rendered view.""" if not self.__config_manager.markdown_render_enabled and not force: return if self._render_edit_stack.get_visible_child() == self._editor_scrolledwin: if self._headerbar_stack.get_visible_child() == self._search_header_bar: self.__exit_search() if self._bottom_bar_revealer.get_reveal_child(): self._bottom_bar_revealer.set_visible(False) if self.__render_view is not None: self.__continue_loading_webkit() else: self._render_edit_stack.set_visible_child(self._render_loading) # Push the WebKit initialisation down the road a little, giving the loading view # time to initialise. A cleaner way to do this will be welcomed. GLib.timeout_add(50, self.__continue_loading_webkit) else: assert self.__render_view if self._headerbar_stack.get_visible_child() == self._render_search_header_bar: self.__exit_render_search() self._render_edit_button_stack.set_visible_child(self._render_button) self.__set_scroll_position(self.__render_view.scroll_position) self._sourceview.set_visible(True) self._render_edit_stack.set_visible_child(self._editor_scrolledwin) self.__check_and_terminate_webkit_process() self._bottom_bar_revealer.set_visible(True) self.__update_formatting_bar_visibility() self.__check_and_hide_bars_after_delay() self.focus_textview_if_editing() self._render_search_header_bar.disable_actions() self.__focus_mode_action.set_enabled(True) def __check_and_terminate_webkit_process(self) -> None: assert self.__render_view if ( not self.__config_manager.markdown_render_enabled or not self.__config_manager.markdown_keep_webkit_process ): logging.debug("Terminating WebKit process") self.__render_view.terminate_web_process() # Reduce flash when next loading render view self.__render_view.set_visible(False) def __update_readonly_actions(self): editable = not not self.__note.read_only for action in ("rename", "edit-category", "clear-category", "delete-note"): self.__action_group.lookup_action(action).set_enabled(editable) def __update_scheme_and_dark_style(self) -> None: """Sync. dark style change to editor style.""" buffer = self._sourceview.get_buffer() if not buffer: return style_manager = Adw.StyleManager.get_default() style_scheme_manager = GtkSource.StyleSchemeManager.get_default() scheme_id = self.__config_manager.editor_theme if style_manager.get_dark(): scheme_id = f"{scheme_id}-dark" scheme = None if style_manager.get_high_contrast(): high_contrast_id = f"{scheme_id}-high-contrast" scheme = style_scheme_manager.get_scheme(high_contrast_id) if not scheme: logging.debug(f"Scheme '{high_contrast_id}' doesn't exist") if scheme is None: scheme = style_scheme_manager.get_scheme(scheme_id) buffer.set_style_scheme(scheme) def __refresh_line_length_from_setting(self) -> None: length = self.__config_manager.line_length length_for_view = -1 if length == self.__config_manager.line_length_max else length self._sourceview.line_length = length_for_view def __push_font_updates(self) -> None: family = self.__get_editor_font_family() self._sourceview.update_font_family(family) if self.__html_generator is not None: family = self.__get_render_font_family() self.__html_generator.update_font_family(family) if self.__render_view: self.__render_view.update_style() def __get_render_font_family(self) -> str: return self.__get_font_family(self.__config_manager.markdown_use_monospace_font) def __get_editor_font_family(self) -> str: return self.__get_font_family(self.__config_manager.use_monospace_font) def __get_font_family(self, monospace: bool) -> str: style_manager = Adw.StyleManager.get_default() if monospace: font = style_manager.props.monospace_font_name else: font = style_manager.props.document_font_name font_description = Pango.font_description_from_string(font) return font_description.get_family() def __show_header_bar(self) -> None: """Show the headerbar.""" self._top_bar_revealer.set_reveal_child(True) self.__update_margin_box_heights() def __check_and_hide_bars_after_delay(self) -> None: if self.__hiding_bars_timeout is not None: return if self.__both_toolbars_hidden(): return if self.__neither_toolbar_auto_hiding(): return def callback(): self.__check_and_hide_header_bar() self.__check_and_hide_formatting_bar() self.__hiding_bars_timeout = None self.__hiding_bars_timeout = GLib.timeout_add(self.HEADERBAR_HIDE_DELAY, callback) def __both_toolbars_hidden(self) -> bool: return ( not self._top_bar_revealer.get_reveal_child() and not self._bottom_bar_revealer.get_reveal_child() ) def __neither_toolbar_auto_hiding(self) -> bool: return ( self.__formatting_bar_visibility_setting == self.__header_bar_visibility_setting == HeaderBarVisibility.ALWAYS_VISIBLE ) def __hide_header_bar(self) -> None: if self._headerbar_stack.get_visible_child() != self._main_header_bar: return elif self._menu_button.get_popover().get_visible(): return if self._top_bar_revealer.get_reveal_child(): self._top_bar_revealer.set_reveal_child(False) self.focus_textview_if_editing() self.__update_margin_box_heights() def __show_formatting_bar(self) -> None: self._bottom_bar_revealer.set_reveal_child(True) self.__update_margin_box_heights() def __hide_formatting_bar(self) -> None: self._bottom_bar_revealer.set_reveal_child(False) self.focus_textview_if_editing() self.__update_margin_box_heights() def __check_and_hide_formatting_bar(self, check_mouse_cursor_over_bar: bool = False) -> bool: if not self._bottom_bar_revealer.get_reveal_child(): return False if not self.__config_manager.markdown_detect_syntax: return False setting = self.__formatting_bar_visibility_setting hide = False if setting in (HeaderBarVisibility.AUTO_HIDE, HeaderBarVisibility.DISABLED): hide = True elif setting == HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY: hide = self.get_root().is_fullscreen() if hide and check_mouse_cursor_over_bar: y = self.__pointer_cursor_y if y is not None: hide = y < self.get_height() - self._sourceview.get_property("top-margin") if hide: self.__hide_formatting_bar() return hide def __check_and_show_formatting_bar(self) -> None: if self.__hiding_bars_timeout: GLib.source_remove(self.__hiding_bars_timeout) self.__hiding_bars_timeout = None if self._bottom_bar_revealer.get_reveal_child(): return if not self.active or self._render_edit_stack.get_visible_child() == self.__render_view: return if not self.__config_manager.markdown_detect_syntax: return if self.__formatting_bar_visibility_setting != HeaderBarVisibility.DISABLED: self.__show_formatting_bar() def __check_and_hide_header_bar(self, check_mouse_cursor_over_bar: bool = False) -> None: if not self._top_bar_revealer.get_reveal_child(): return hide = False if self.__header_bar_visibility_setting == HeaderBarVisibility.AUTO_HIDE: hide = True elif self.__header_bar_visibility_setting == HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY: hide = self.get_root().is_fullscreen() if hide and check_mouse_cursor_over_bar: y = self.__pointer_cursor_y if y is not None: hide = y > self._sourceview.get_property("top-margin") if hide: self.__hide_header_bar() def __check_and_show_header_bar(self) -> None: if self.__hiding_bars_timeout: GLib.source_remove(self.__hiding_bars_timeout) self.__hiding_bars_timeout = None if not self._top_bar_revealer.get_reveal_child(): self.__show_header_bar() def __update_for_formatting_bar_setting_change(self) -> None: self.__cache_formatting_bar_visibility() if self.active: self.__update_toolbar_underlay_margins() self.__update_formatting_bar_visibility() def __update_toolbar_underlay_margins(self) -> None: pad = self.__config_manager.editor_header_bar_visible_for_window_state margin = const.HEADER_BAR_HEIGHT if pad else 0 if self._content_overlay.get_margin_top() != margin: self._content_overlay.set_margin_top(margin) pad = self.__config_manager.editor_formatting_bar_visible_for_window_state if pad: margin = self._formatting_header_bar.get_property("height-request") else: margin = 0 if self._editor_scrolledwin.get_margin_bottom() != margin: self._editor_scrolledwin.set_margin_bottom(margin) def __update_formatting_bar_visibility(self) -> None: if not self.active or self._render_edit_stack.get_visible_child() == self.__render_view: return if not self.__config_manager.markdown_detect_syntax: return setting = self.__formatting_bar_visibility_setting if self._bottom_bar_revealer.get_reveal_child(): self.__check_and_hide_formatting_bar() else: show = False if setting == HeaderBarVisibility.ALWAYS_VISIBLE: show = True elif setting == HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY: show = not self.get_root().is_fullscreen() if show: self.__show_formatting_bar() def __update_for_header_bar_setting_change(self) -> None: self.__cache_header_bar_visibility() if not self.active: return setting = self.__header_bar_visibility_setting if self._top_bar_revealer.get_reveal_child(): self.__check_and_hide_header_bar() else: show = False if setting == HeaderBarVisibility.ALWAYS_VISIBLE: show = True elif setting == HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY: show = not self.get_root().is_fullscreen() if show: self.__show_header_bar() self.__update_toolbar_underlay_margins() def __cache_header_bar_visibility(self) -> None: self.__header_bar_visibility_setting = self.__config_manager.editor_header_bar_visibility def __cache_formatting_bar_visibility(self) -> None: self.__formatting_bar_visibility_setting = ( self.__config_manager.editor_formatting_bar_visibility ) # Return type intentionally skipped to allow for lazy loading WebKit def __ensure_webkit_initialised(self) -> Any: if self.__render_view is None: self.__init_webkit() return self.__render_view def __continue_loading_webkit(self) -> None: assert self.__note self.__ensure_webkit_initialised() assert self.__render_view if self.__sync_manager.authenticated: download_func = self.__sync_manager.download_attachments else: download_func = None self.__render_view.render( self.__note, export_format=None, attachment_download_func=download_func, scroll_position=self.__get_scroll_position(), ) self._search_header_bar.disable_actions() self.__focus_mode_action.set_enabled(False) def __update_margin_box_heights(self) -> None: margin = self._sourceview.get_property("top-margin") # When the bar is revealed the margin area is shrunk to allow interaction with the top of # the buffer height = 1 if self._top_bar_revealer.get_reveal_child() else margin self._top_margin_box.set_property("height-request", height) height = 1 if self._bottom_bar_revealer.get_reveal_child() else margin self._bottom_margin_box.set_property("height-request", height) def __click_in_top_margin(self, gesture: Gtk.Gesture) -> bool: (interpreted, _, y) = gesture.get_point(None) if not interpreted: return False if not self._top_bar_revealer.get_reveal_child(): return False return y < self._sourceview.get_property("top-margin") def __click_in_bottom_margin(self, gesture: Gtk.Gesture) -> bool: (interpreted, _, y) = gesture.get_point(None) if not interpreted: return False if not self._bottom_bar_revealer.get_reveal_child(): return False return y > self._sourceview.get_height() - self._sourceview.get_property("top-margin") def __focus_editor(self) -> None: # Don't focus if showing render view if self._render_edit_stack.get_visible_child() != self._editor_scrolledwin: return self._sourceview.grab_focus() def __focus_header_bar(self) -> None: self.__show_header_bar() if self._headerbar_stack.get_visible_child() == self._rename_header_bar: self._rename_header_bar.focus() elif self._headerbar_stack.get_visible_child() == self._search_header_bar: self._search_header_bar.refocus_search_and_select() elif self._headerbar_stack.get_visible_child() == self._category_header_bar: self._category_header_bar.focus() elif self._headerbar_stack.get_visible_child() == self._render_search_header_bar: self._render_search_header_bar.focus() else: self._title_button.grab_focus() def __focus_formatting_bar(self) -> None: if not self.__config_manager.markdown_detect_syntax: return if self.__formatting_bar_visibility_setting == HeaderBarVisibility.DISABLED: return self.__show_formatting_bar() self._formatting_header_bar.focus() def __check_and_handle_link_click(self, x: float, y: float) -> None: link = None buffer_x, buffer_y = self._sourceview.window_to_buffer_coords( Gtk.TextWindowType.TEXT, x, y, ) over_text, iter = self._sourceview.get_iter_at_location(buffer_x, buffer_y) if not over_text: logging.debug("Not over text for URL ctrl-click") return # Check and open basic link result = parse_any_url_at_iter(iter, http_only=True) if result: link = result.link else: # Check for a markdown inline and automatic links classes = iter.get_buffer().get_context_classes_at_iter(iter) if "inline-link" in classes: inline_result = parse_markdown_inline_link(iter) if inline_result: link = inline_result.link elif "automatic-link" in classes: auto_result = parse_markdown_automatic_link(iter) if auto_result: link = auto_result.link if link: logging.info(f"Opening URI from ctrl-click: {link}") webbrowser.open(link) self.__show_toast(_("Opening link in browser")) def __store_session_details(self) -> None: scroll_position = self._editor_scrolledwin.get_vadjustment().get_value() buffer = self._sourceview.get_buffer() insert_iter = buffer.get_iter_at_mark(buffer.get_insert()) cursor_location = insert_iter.get_offset() if len(self.__previous_sessions) and self.__previous_sessions[-1].note == self.current_note: return details = EditorSessionDetails( self.current_note, scroll_position, cursor_location, ) self.__previous_sessions.append(details) if len(self.__previous_sessions) > 2: self.__previous_sessions = self.__previous_sessions[-2:] def __flush_note_from_previous_sessions(self, note: Note) -> None: if self.__previous_sessions and self.__previous_sessions[-1].note == note: del self.__previous_sessions[-1] def __restore_session_location(self, session: EditorSessionDetails) -> None: self.__set_scroll_position(session.scroll_position) buffer = self._sourceview.get_buffer() cursor_iter = buffer.get_iter_at_offset(session.cursor_position) buffer.place_cursor(cursor_iter) def __show_outline(self) -> None: assert self.__note if self.__outline_dialog: self.__outline_dialog.close() self.__enable_actions(False) dialog = OutlineDialog() dialog.present(self) def populate(headings: list[OutlineHeading]) -> None: # This makes a crude assumption that if the locale is RTL the document contents are RTL. # Likely better than ignoring RTL but worse than knowing the document direction. rtl = self.get_default_direction() == Gtk.TextDirection.RTL dialog.populate(headings, rtl) self.__outline_generator.generate(self.__note, populate) def jump_to(dialog: OutlineDialog, line: int) -> None: if self._render_edit_stack.get_visible_child() == self._editor_scrolledwin: buffer = self._sourceview.get_buffer() success, line_iter = buffer.get_iter_at_line(line) buffer.place_cursor(line_iter) self._sourceview.jump_to_insertion_point() else: assert self.__render_view self.__render_view.scroll_to_heading(line) dialog.connect("jump-to", jump_to) def outline_closed(dialog: OutlineDialog) -> None: dialog.disconnect_by_func(jump_to) dialog.disconnect_by_func(outline_closed) self.__outline_dialog = None self.__enable_actions(True) dialog.connect("closed", outline_closed) self.__outline_dialog = dialog def __initialise_html_generator(self) -> None: if self.__html_generator: return from iotas.template_html_generator import TemplateHtmlGenerator self.__html_generator = TemplateHtmlGenerator( self.__config_manager, const.PKGDATADIR, const.HEADER_BAR_HEIGHT ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/editor_rename_header_bar.py000066400000000000000000000033631507102636600270510ustar00rootroot00000000000000from gi.repository import Adw, GObject, Gtk from iotas.text_utils import sanitise_path @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/editor_rename_header_bar.ui") class EditorRenameHeaderBar(Adw.Bin): __gtype_name__ = "EditorRenameHeaderBar" __gsignals__ = { "cancelled": (GObject.SignalFlags.RUN_FIRST, None, ()), "renamed": (GObject.SignalFlags.RUN_FIRST, None, (str,)), } _entry: Gtk.Entry = Gtk.Template.Child() _apply_button: Gtk.Button = Gtk.Template.Child() def __init__(self) -> None: super().__init__() def enter(self, title: str) -> None: """Start renaming. :param str title: Existing title """ self._entry.set_text(title) self._entry.grab_focus() self._entry.set_position(-1) def focus(self) -> None: """Grab focus to entry.""" self._entry.grab_focus() @Gtk.Template.Callback() def _on_apply_pressed(self, _button: Gtk.Button) -> None: self.__apply_rename() @Gtk.Template.Callback() def _abort_rename(self, _button: Gtk.Button) -> None: self.emit("cancelled") @Gtk.Template.Callback() def _on_entry_changed(self, _entry: Gtk.Editable) -> None: self._apply_button.set_sensitive(self.__entry_valid()) @Gtk.Template.Callback() def _on_entry_activated(self, _entry: Gtk.Entry) -> None: if self.__entry_valid(): self.__apply_rename() def __apply_rename(self) -> None: self.emit("renamed", self.__get_sanitised_entry()) def __entry_valid(self) -> bool: return self.__get_sanitised_entry() != "" def __get_sanitised_entry(self) -> str: new_title = self._entry.get_text().strip() return sanitise_path(new_title) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/editor_search_entry.py000066400000000000000000000040521507102636600261300ustar00rootroot00000000000000from gettext import gettext as _ from gi.repository import GObject, Gtk @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/editor_search_entry.ui") class EditorSearchEntry(Gtk.Box): __gtype_name__ = "EditorSearchEntry" __gsignals__ = { "activate": (GObject.SignalFlags.RUN_FIRST, None, ()), } text: Gtk.Text = Gtk.Template.Child() _info: Gtk.Label = Gtk.Template.Child() def __init__(self) -> None: self.__occurrence_count = 0 self.__occurrence_position = 0 super().__init__() def set_occurrence_count(self, count: int) -> None: """Set the number of search term occurrences. :param int count: New value """ self.__occurrence_count = count self.__update_position() def set_occurrence_position(self, position: int) -> None: """Set the current search term occurrence. :param int position: New value """ self.__occurrence_position = position self.__update_position() def select_all_and_focus(self) -> None: """Select and focus all text.""" if self.text.get_text() != "": self.text.select_region(0, -1) self.text.grab_focus() def get_text(self) -> str: """Fetch the text from the entry. :return: Unaccented form :rtype: str """ return self.text.get_text() def set_text(self, text: str) -> None: """Set the text on the entry. :param str text: New value """ return self.text.set_text(text) @Gtk.Template.Callback() def _on_activate(self, _obj: GObject.Object) -> None: self.emit("activate") def __update_position(self) -> None: if self.__occurrence_count == 0: occurrence_str = "" else: # Translators: Description, {0} the current position in {1} a number of search results occurrence_str = _("{0} of {1}").format( self.__occurrence_position, self.__occurrence_count ) self._info.set_label(occurrence_str) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/editor_search_header_bar.py000066400000000000000000000322461507102636600270510ustar00rootroot00000000000000from gi.repository import Gio, GObject, Gtk, GtkSource from typing import Optional from iotas.editor_search_entry import EditorSearchEntry @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/editor_search_header_bar.ui") class EditorSearchHeaderBar(Gtk.Box): __gtype_name__ = "EditorSearchHeaderBar" __gsignals__ = { "resumed": (GObject.SignalFlags.RUN_FIRST, None, ()), "open-for-replace": (GObject.SignalFlags.RUN_FIRST, None, ()), } _search_entry: EditorSearchEntry = Gtk.Template.Child() _backward_button: Gtk.Button = Gtk.Template.Child() _forward_button: Gtk.Button = Gtk.Template.Child() _revealer: Gtk.Revealer = Gtk.Template.Child() _replace_entry: Gtk.Entry = Gtk.Template.Child() _replace_toggle: Gtk.ToggleButton = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__settings = GtkSource.SearchSettings.new() self.__settings.set_wrap_around(True) self._search_entry.text.bind_property( "text", self.__settings, "search-text", ) self.__context: Optional[GtkSource.SearchContext] = None self.__offset_when_entered = 0 self.__context_signal_handler_id: Optional[int] = None self.__cursor_signal_handler_id: Optional[int] = None self.__current_match_tag = None self.__avoid_jumping_during_replace = False self.__active = False self._search_entry.text.connect( "notify::text", lambda _o, _v: self.__on_search_text_changed() ) self._revealer.bind_property( "child-revealed", self._replace_toggle, "active", GObject.BindingFlags.SYNC_CREATE ) def setup(self, sourceview: GtkSource.View): """Perform initial setup.""" self.__setup_actions() self.__sourceview = sourceview def enter(self, resuming: bool, for_replace: bool) -> None: """Enter search. :param bool resuming: Whether resuming search :param bool for_replace: Whether opening directly from a ctrl-h shortcut """ buffer = self.__sourceview.get_buffer() self.__context = GtkSource.SearchContext.new(buffer, self.__settings) insert_iter = buffer.get_iter_at_mark(buffer.get_insert()) self.__offset_when_entered = insert_iter.get_offset() self.__setup_current_match_styling() if for_replace: self._revealer.set_reveal_child(True) # Ensure when restarting search any term remains selected so it can be easily replaced by # typing. self.__restarting_with_nonempty_term = not resuming and self._search_entry.get_text() != "" self._search_entry.text.grab_focus() if resuming: self._search_entry.text.set_position(-1) elif self._search_entry.get_text() != "": self._search_entry.text.select_region(0, -1) self.__context_signal_handler_id = self.__context.connect( "notify::occurrences-count", lambda _o, _v: self.__on_occurrences_count_changed() ) self.__cursor_signal_handler_id = buffer.connect("cursor-moved", self.__on_cursor_moved) self.__replace_action.set_enabled(False) self.__active = True def exit(self) -> None: """Exit search.""" assert self.__context buffer = self.__sourceview.get_buffer() buffer.disconnect(self.__cursor_signal_handler_id) self.__context.disconnect(self.__context_signal_handler_id) self.__context = None begin, end = buffer.get_bounds() buffer.remove_tag(self.__current_match_tag, begin, end) self.__current_match_tag = None self._revealer.set_reveal_child(False) self.__active = False def disable_actions(self) -> None: """Disable actions.""" self.__action_group.lookup_action("backward").set_enabled(False) self.__action_group.lookup_action("forward").set_enabled(False) def refocus_search_and_select(self) -> None: """Grab focus to search entry and select any text.""" self._search_entry.text.grab_focus() if self._search_entry.get_text() != "": self._search_entry.text.select_region(0, -1) @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @Gtk.Template.Callback() def _on_search_entry_activate(self, _obj: GObject.Object) -> None: self.__move_forward() @Gtk.Template.Callback() def _on_replace_entry_activate(self, _obj: GObject.Object) -> None: if self.__replace_action.get_enabled(): self.__replace_selection() def __setup_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() action = Gio.SimpleAction.new("forward") action.connect("activate", lambda _a, _v: self.__move_forward()) action_group.add_action(action) app.set_accels_for_action("editor-search.forward", ["g"]) action.set_enabled(False) action = Gio.SimpleAction.new("backward") action.connect("activate", lambda _a, _v: self.__move_backward()) action_group.add_action(action) app.set_accels_for_action("editor-search.backward", ["g"]) action.set_enabled(False) action = Gio.SimpleAction.new("toggle-replace") action.connect("activate", lambda _a, _p: self.__toggle_replace_visible()) action_group.add_action(action) app.set_accels_for_action("editor-search.toggle-replace", ["h"]) action = Gio.SimpleAction.new("replace") action.connect("activate", lambda _a, _p: self.__replace_selection()) action_group.add_action(action) self.__replace_action = action self.__action_group = action_group app.get_active_window().insert_action_group("editor-search", action_group) def __on_context_forward(self, _obj: GObject.Object, result: Gio.AsyncResult) -> None: assert self.__context assert self.__current_match_tag success, match_start, match_end, __ = self.__context.forward_finish(result) if success: buffer = self.__sourceview.get_buffer() if self.__restarting_with_nonempty_term: buffer.place_cursor(match_start) else: buffer.select_range(match_start, match_end) self.__current_match_tag.set_priority(buffer.get_tag_table().get_size() - 1) self.__update_for_current_match(match_start, match_end) self.__sourceview.jump_to_insertion_point() if self.__restarting_with_nonempty_term: self.__restarting_with_nonempty_term = False self.__replace_action.set_enabled(success) def __on_context_backward(self, _obj: GObject.Object, result: Gio.AsyncResult) -> None: assert self.__current_match_tag success, match_start, match_end, __ = self.__context.backward_finish(result) if success: buffer = self.__sourceview.get_buffer() buffer.select_range(match_start, match_end) self.__current_match_tag.set_priority(buffer.get_tag_table().get_size() - 1) self.__sourceview.jump_to_insertion_point() self.__update_for_current_match(match_start, match_end) self.__replace_action.set_enabled(success) def __on_cursor_moved(self, _obj: GObject.Object) -> None: self.__update_for_current_match(None, None) self.__replace_action.set_enabled(False) def __on_search_text_changed(self) -> None: self.__replace_action.set_enabled(False) self._search_entry.set_occurrence_count(0) self._search_entry.set_occurrence_position(0) # Clear any tagged matches when deleting the search term buffer = self.__sourceview.get_buffer() begin, end = buffer.get_bounds() buffer.remove_tag(self.__current_match_tag, begin, end) def __on_occurrences_count_changed(self) -> None: assert self.__context count = self.__context.get_occurrences_count() self._search_entry.set_occurrence_count(count) self._search_entry.set_occurrence_position(0) search_can_move = count > 0 if not self.__sourceview.has_focus(): if search_can_move and not self.__avoid_jumping_during_replace: self.__jump_to_first() elif self.__restarting_with_nonempty_term: self.__restarting_with_nonempty_term = False self.__action_group.lookup_action("backward").set_enabled(search_can_move) self.__action_group.lookup_action("forward").set_enabled(search_can_move) self.__avoid_jumping_during_replace = False def __jump_to_first(self) -> None: buffer = self.__sourceview.get_buffer() start_iter = buffer.get_iter_at_offset(self.__offset_when_entered) self.__move_forward(start_iter) def __move_forward(self, from_iter: Optional[Gtk.TextIter] = None) -> None: """Move to next search match.""" if self.__context is None: if self._search_entry.get_text() != "": self.emit("resumed") return if not from_iter: buffer = self.__sourceview.get_buffer() if buffer.get_has_selection(): begin, end = buffer.get_selection_bounds() begin.order(end) from_iter = end else: mark = buffer.get_insert() from_iter = buffer.get_iter_at_mark(mark) self.__context.forward_async(from_iter, None, self.__on_context_forward) def __move_backward(self) -> None: """Move to previous search match.""" if self.__context is None: if self._search_entry.get_text() != "": self.emit("resumed") return buffer = self.__sourceview.get_buffer() if buffer.get_has_selection(): begin, end = buffer.get_selection_bounds() begin.order(end) else: mark = buffer.get_insert() begin = buffer.get_iter_at_mark(mark) self.__context.backward_async(begin, None, self.__on_context_backward) def __toggle_replace_visible(self) -> None: if not self.__active: self.emit("open-for-replace") return reveal = not self._revealer.get_child_revealed() self._revealer.set_reveal_child(reveal) if reveal: # Clearing the replace entry here to avoid the current match selection in the buffer # being removed, which would result in replace not working until the match is # re-navigated to. Ideally selection wouldn't be used to identify the current search # match. self._replace_entry.set_text("") self._replace_entry.grab_focus() self.__replace_action.set_enabled(self.__have_search_term_selection()) def __update_for_current_match( self, match_start: Optional[Gtk.TextIter], match_end: Optional[Gtk.TextIter] ) -> None: assert self.__context assert self.__current_match_tag buffer = self.__sourceview.get_buffer() new_position = 0 if buffer.get_has_selection(): bounds = buffer.get_selection_bounds() if len(bounds) == 2: begin, end = bounds begin.order(end) new_position = self.__context.get_occurrence_position(begin, end) self._search_entry.set_occurrence_position(new_position) if self.__current_match_tag is not None: begin, end = buffer.get_bounds() buffer.remove_tag(self.__current_match_tag, begin, end) if match_start is not None and match_end is not None: buffer.apply_tag(self.__current_match_tag, match_start, match_end) self.__current_match_tag.set_priority(buffer.get_tag_table().get_size() - 1) def __setup_current_match_styling(self) -> None: buffer = self.__sourceview.get_buffer() table = buffer.get_tag_table() scheme = buffer.get_style_scheme() if self.__current_match_tag is not None: table.remove(self.__current_match_tag) self.__current_match_tag = buffer.create_tag() assert self.__current_match_tag if scheme is not None: style = scheme.get_style("current-search-match") if style is not None: style.apply(self.__current_match_tag) self.__current_match_tag.set_priority(table.get_size() - 1) def __replace_selection(self) -> None: buffer = self.__sourceview.get_buffer() if not self.__have_search_term_selection(): return (start, end) = buffer.get_selection_bounds() self.__avoid_jumping_during_replace = True buffer.delete(start, end) new_text = self._replace_entry.get_text() if new_text != "": buffer.insert(start, new_text) self.__move_forward() def __have_search_term_selection(self) -> bool: buffer = self.__sourceview.get_buffer() if not buffer.get_has_selection(): return False (start, end) = buffer.get_selection_bounds() return start.get_text(end).lower() == self._search_entry.get_text().lower() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/editor_text_view.py000066400000000000000000000272421507102636600254660ustar00rootroot00000000000000import gi gi.require_version("GtkSource", "5") from gi.repository import Gdk, Gio, GLib, GObject, Gtk, GtkSource from gtkspellcheck import SpellChecker, NoDictionariesFound import locale import logging from typing import Optional from iotas.config_manager import ConfigManager import iotas.const as const from iotas import list_formatter class EditorTextView(GtkSource.View): __gtype_name__ = "EditorTextView" __gsignals__ = { "margins-updated": (GObject.SignalFlags.RUN_FIRST, None, ()), } SOURCEVIEW_NO_SPELLCHECK_TAG = "gtksourceview:context-classes:no-spell-check" STANDARD_MARGIN = 36 MINIMUM_MARGIN = 10 def __init__(self) -> None: super().__init__() self.__css_provider: Optional[Gtk.CssProvider] = None self.__config_manager = ConfigManager.get_default() self.__line_length = -1 self.__longpress_popover: Gtk.PopoverMenu self.__font_family = "monospace" self.__width_margins_set_for = None self.__config_manager.connect_changed(ConfigManager.FONT_SIZE, self.__update_font) self.__config_manager.connect_changed( ConfigManager.EDITOR_HEADER_BAR_VISIBILTY, lambda: self.__update_margins(self.get_width()), ) controller = Gtk.EventControllerKey() controller.connect("key-pressed", self.__on_key_pressed) self.add_controller(controller) self.__spellchecker = None if self.__config_manager.spelling_enabled: self.__init_spellchecker() self.__config_manager.connect_changed( ConfigManager.SPELLING_ENABLED, self.__on_spelling_toggled, ) # TODO Temporary hack to provide access to spelling on mobile self.__setup_longpress_touch_menu() def setup(self) -> None: """Initialisation after window creation.""" window = self.get_root() window.connect( "notify::fullscreened", lambda _o, _v: self.__update_margins(self.get_width()) ) def do_size_allocate(self, width: int, height: int, baseline: int) -> None: """Allocates widget with a transformation that translates the origin to the position in allocation. :param int width: Width of the allocation :param int height: Height of the allocation :param int baseline: The baseline of the child """ GtkSource.View.do_size_allocate(self, width, height, baseline) if width != self.__width_margins_set_for: self.__update_margins(width) def jump_to_insertion_point(self) -> None: """Jump to the insertion point. This jump is used to avoid issues with height allocation in `scroll_to_mark` when the buffer contains lines of varying height. """ buffer = self.get_buffer() insert_iter = buffer.get_iter_at_mark(buffer.get_insert()) location = self.get_iter_location(insert_iter) adjustment = self.get_vadjustment() adjustment.set_value(location.y) def update_font_family(self, font_family: str) -> None: """Update font family from system preference. :param str font_family: The font family """ self.__font_family = font_family self.__update_font() @GObject.Property(type=bool, default=False) def spellchecker_enabled(self) -> bool: if self.__spellchecker is not None: return self.__spellchecker.enabled else: return False @spellchecker_enabled.setter def set_spellchecker_enabled(self, value: bool) -> None: if self.__spellchecker is not None: self.__spellchecker.enabled = value @GObject.Property(type=int, default=-1) def line_length(self) -> int: return self.__line_length @line_length.setter def set_line_length(self, value: int) -> None: self.__line_length = value # Ensure margin resizing works during resize self.__update_margins(self.get_width()) # TODO Part of temporary hack to provide access to spelling menu on mobile def __on_longpress(self, _gesture: Gtk.GestureLongPress, x: float, y: float) -> None: # Long press menu is only currently used for spelling on mobile, don't show many if # spelling disabled if self.__spellchecker is None or not self.__spellchecker.enabled: return buffer_x, buffer_y = self.window_to_buffer_coords(Gtk.TextWindowType.TEXT, int(x), int(y)) iter = self.get_iter_at_location(buffer_x, buffer_y)[1] self.__spellchecker.move_click_mark(iter) self.__spellchecker.populate_menu(self.__longpress_popover.get_menu_model()) rect = Gdk.Rectangle() rect.x = x rect.y = y rect.width = rect.height = 1 self.__longpress_popover.set_pointing_to(rect) self.__longpress_popover.popup() def __on_spelling_toggled(self) -> None: if self.__config_manager.spelling_enabled: self.__init_spellchecker() self.spellchecker_enabled = True else: self.spellchecker_enabled = False def __on_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> bool: buffer = self.get_buffer() if keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter, Gdk.KEY_ISO_Enter): if list_formatter.check_and_extend_list(buffer): # Attempt to track cursor in viewport mark = buffer.get_insert() insert_iter = buffer.get_iter_at_mark(mark) buffer_coords = self.get_iter_location(insert_iter) visible_rect = self.get_visible_rect() if buffer_coords.y + buffer_coords.height >= visible_rect.y + visible_rect.height: # Without adding as an idle task we sometimes end up with an insufficient scroll GLib.idle_add(self.emit, "move-viewport", Gtk.ScrollStep.STEPS, 1) return Gdk.EVENT_STOP elif keyval in (Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab): if state == Gdk.ModifierType.SHIFT_MASK: list_formatter.decrease_indentation(buffer) else: list_formatter.increase_indentation(buffer) return Gdk.EVENT_STOP return Gdk.EVENT_PROPAGATE def __update_margins(self, width) -> None: self.__width_margins_set_for = width # Update top and bottom margin min_width_for_y_margin = 400 max_width_for_y_margin = self.__line_length if self.__line_length > 500 else 800 if width <= min_width_for_y_margin: y_margin_base = self.MINIMUM_MARGIN elif width < max_width_for_y_margin: value_range = max_width_for_y_margin - min_width_for_y_margin y_range = float(self.STANDARD_MARGIN - self.MINIMUM_MARGIN) in_range = width - min_width_for_y_margin y_margin_base = self.MINIMUM_MARGIN + int(in_range / value_range * y_range) else: y_margin_base = self.STANDARD_MARGIN # If the header bar is non hiding (set visible for the fullscreen state) there will be # padding elsewhere to ensure the text avoids the headerbar. Otherwise we add it here. if self.__config_manager.editor_header_bar_visible_for_window_state: y_margin = y_margin_base else: y_margin = y_margin_base + const.HEADER_BAR_HEIGHT if self.props.top_margin != y_margin: self.set_top_margin(y_margin) # Update side margins if width < 1: return if self.__line_length > 0 and width - 2 * self.STANDARD_MARGIN > self.__line_length: x_margin = (width - self.__line_length) / 2 else: x_margin = y_margin_base if self.get_left_margin() != x_margin: self.set_left_margin(x_margin) self.set_right_margin(x_margin) self.emit("margins-updated") def __update_font(self) -> None: if not self.__css_provider: self.__css_provider = Gtk.CssProvider() self.get_style_context().add_provider( self.__css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER ) size = self.__config_manager.font_size style = f""" .editor-textview {{ font-size: {size}pt; font-family: {self.__font_family}, monospace; }}""" self.__css_provider.load_from_data(style, -1) def __init_spellchecker(self) -> None: if self.__spellchecker is not None: return pref_language = self.__config_manager.spelling_language if pref_language is not None: language = pref_language logging.debug(f'Attempting to use spelling language from preference "{pref_language}"') else: default_language, _encoding = locale.getdefaultlocale() if default_language: language = default_language logging.debug(f'Attempting to use locale default spelling language "{language}"') else: logging.warning("Couldn't determine locale default language") try: self.__spellchecker = SpellChecker(self, language, collapse=False) except NoDictionariesFound: # Not communicating via UI for now as systems without any dictionaries are likely to # be corner cases, bespoke systems eg. Arch etc logging.warning("Disabling spell checker as no dictionaries were found") return assert self.__spellchecker # mypy self.spellchecker_enabled = False self.__spellchecker.batched_rechecking = True if pref_language is not None: self.__verify_preferred_language_in_use(pref_language) self.__spellchecker.connect( "notify::language", lambda _o, _v: self.__spelling_language_changed() ) buffer = self.get_buffer() table = buffer.get_tag_table() def process_added_tag(tag): if tag.get_property("name") == self.SOURCEVIEW_NO_SPELLCHECK_TAG: self.__spellchecker.append_ignore_tag(self.SOURCEVIEW_NO_SPELLCHECK_TAG) def tag_added(tag, *args): if isinstance(tag, Gtk.TextTag): process_added_tag(tag) elif len(args) > 0 and isinstance(args[0], Gtk.TextTag): process_added_tag(args[0]) table.connect("tag-added", tag_added) def __verify_preferred_language_in_use(self, pref_language: str) -> None: assert self.__spellchecker language_in_use = self.__spellchecker.language if language_in_use != pref_language: logging.warning( f'Spelling language from preference "{pref_language}" not found, clearing' " preference" ) logging.info("Available languages:") for code, name in self.__spellchecker.languages: logging.info(" - %s (%5s)" % (name, code)) self.__config_manager.spelling_language = "" def __spelling_language_changed(self) -> None: assert self.__spellchecker language = self.__spellchecker.language logging.info(f'New spelling language "{language}"') self.__config_manager.spelling_language = language # TODO Part of temporary hack to provide access to spelling menu on mobile def __setup_longpress_touch_menu(self) -> None: gesture = Gtk.GestureLongPress.new() gesture.set_touch_only(True) gesture.connect("pressed", self.__on_longpress) self.add_controller(gesture) self.__longpress_popover = Gtk.PopoverMenu.new_from_model(Gio.Menu()) self.__longpress_popover.set_parent(self) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/export_dialog.py000066400000000000000000000314301507102636600247340ustar00rootroot00000000000000from gettext import gettext as _ from gi.repository import Adw, Gdk, Gio, GLib, Gtk import json import logging import os import re from threading import Thread from typing import Any, Callable, Optional from iotas.attachment_helpers import get_attachment_disk_states from iotas.config_manager import ConfigManager import iotas.const as const from iotas.markdown_helpers import parse_to_tokens from iotas.note import Note from iotas.sync_manager import SyncManager from iotas.webkit_pdf_exporter import WebKitPdfExporter @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/export_dialog.ui") class ExportDialog(Adw.Dialog): __gtype_name__ = "ExportDialog" _main_stack: Gtk.Stack = Gtk.Template.Child() _headerbar_stack: Gtk.Stack = Gtk.Template.Child() _format_headerbar: Adw.HeaderBar = Gtk.Template.Child() _downloading_headerbar: Adw.HeaderBar = Gtk.Template.Child() _exporting_headerbar: Adw.HeaderBar = Gtk.Template.Child() _success_headerbar: Adw.HeaderBar = Gtk.Template.Child() _failure_headerbar: Adw.HeaderBar = Gtk.Template.Child() _failure_headerbar_label: Gtk.Label = Gtk.Template.Child() _format_listbox: Gtk.ListBox = Gtk.Template.Child() _cancel_button: Gtk.Button = Gtk.Template.Child() _show_button: Gtk.Button = Gtk.Template.Child() _downloading: Adw.StatusPage = Gtk.Template.Child() _exporting: Gtk.Box = Gtk.Template.Child() _success: Gtk.Box = Gtk.Template.Child() _success_label: Gtk.Label = Gtk.Template.Child() _failure: Gtk.Box = Gtk.Template.Child() _failure_label: Gtk.Label = Gtk.Template.Child() _download_failure: Adw.StatusPage = Gtk.Template.Child() _retry_row: Adw.ButtonRow = Gtk.Template.Child() def __init__( self, note: Note, html_generator, sync_manager: SyncManager, webkit_init_fn: Callable[[], None], ) -> None: super().__init__() self.__note = note self.__html_generator = html_generator self.__sync_manager = sync_manager self.__webkit_init = webkit_init_fn self.__config_manager = ConfigManager.get_default() # Any typing for lazy loading self.__exporter: Optional[Any] = None self.__show_path: Optional[str] = None self.__out_format: str self.__file_extension: str self.__location: Optional[str] = None self.__custom_formats: dict[str, dict[str, str]] = {} controller = Gtk.EventControllerKey.new() controller.connect("key-pressed", self._on_key_pressed) self.add_controller(controller) GLib.idle_add(self.__setup) def __setup(self) -> None: self._cancel_button.grab_focus() self.__load_extra_formats() @Gtk.Template.Callback() def _row_activated(self, _listbox: Gtk.ListBox, row: Adw.ButtonRow) -> None: format_id = row.get_title().lower() if format_id in self.__custom_formats: self.__file_extension = self.__custom_formats[format_id]["extension"] self.__out_format = self.__custom_formats[format_id]["format"] else: self.__file_extension = format_id self.__out_format = format_id self.__determine_output_location() @Gtk.Template.Callback() def _download_failure_row_activated(self, _listbox: Gtk.ListBox, row: Adw.ButtonRow) -> None: if row == self._retry_row: self.__download_missing_attachments() else: self.__export(allow_missing_images=True) @Gtk.Template.Callback() def _on_show_clicked(self, _button: Gtk.Button) -> None: launcher = Gtk.FileLauncher.new(Gio.File.new_for_uri(f"file://{self.__show_path}")) launcher.open_containing_folder() self.close() @Gtk.Template.Callback() def _on_cancel(self, _button: Gtk.Button) -> None: self.close() def _on_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> bool: if self._main_stack.get_visible_child() != self._exporting: if keyval in (Gdk.KEY_Down, Gdk.KEY_KP_Down): if self.get_property("focus-widget") == self._cancel_button: row = self._format_listbox.get_row_at_index(0) row.grab_focus() return Gdk.EVENT_STOP return Gdk.EVENT_PROPAGATE def __on_finished_downloading(self) -> None: self._headerbar_stack.set_visible_child(self._exporting_headerbar) self.__export() def __on_finished(self, show_path: str) -> None: self._main_stack.set_visible_child(self._success) self._headerbar_stack.set_visible_child(self._success_headerbar) # Translators: Description, {} is a format eg. PDF self._success_label.set_label(_("Exported to {}").format(self.__out_format.upper())) self.__show_path = show_path # For some reason if grab focus is called directly from the idle it blocks clean exit def focus_show_button(): self._show_button.grab_focus() GLib.idle_add(focus_show_button) def __on_failed(self, reason: str) -> None: self._main_stack.set_visible_child(self._failure) self._headerbar_stack.set_visible_child(self._failure_headerbar) # Translators: Description, {} is a format eg. PDF message = _("Failed to export to {}").format(self.__out_format.upper()) if reason != "": message = message + "\n\n" + reason logging.warning(message) self._failure_label.set_label(message) def __determine_output_location(self) -> None: self.__init_exporter() assert self.__exporter filesystem_writable_path = self.__get_writable_non_container_dir() if filesystem_writable_path: dialog = Gtk.FileDialog.new() dialog.set_initial_folder(Gio.File.new_for_path(filesystem_writable_path)) filename = self.__exporter.build_default_filename( self.__note, self.__out_format, self.__file_extension ) dialog.set_initial_name(filename) # Translators: Button dialog.set_accept_label(_("Export")) window = self.get_parent().get_root() dialog.save( window, None, self.__on_save_dialog_finish, ) else: logging.info( "Can't access user documents directory, exporting to location inside container" ) self.__location = None self.__export() def __on_save_dialog_finish(self, dialog: Gtk.FileDialog, task: Gio.Task) -> None: try: file = dialog.save_finish(task) except GLib.GError as e: logging.warning(f"Couldn't export note: {e.message}") self.close() else: self.__location = file.get_path() self.__save_last_export_directory() self.__download_missing_attachments() def __download_missing_attachments(self) -> None: _parser, tokens = parse_to_tokens(self.__note, exporting=False, tex_support=False) states = get_attachment_disk_states(self.__note, tokens) if not states.missing or not self.__sync_manager.authenticated: self._headerbar_stack.set_visible_child(self._exporting_headerbar) self.__export() return logging.info("Downloading attachments prior to export") self._headerbar_stack.set_visible_child(self._downloading_headerbar) self._main_stack.set_visible_child(self._downloading) def thread_do(): if self.__sync_manager.download_attachments(states.missing, on_thread=False): GLib.idle_add(self.__export) else: GLib.idle_add(self.__show_attachment_download_failure) thread = Thread(target=thread_do) thread.daemon = True thread.start() def __show_attachment_download_failure(self) -> None: self._main_stack.set_visible_child(self._download_failure) self._headerbar_stack.set_visible_child(self._failure_headerbar) # Translators: Title self._failure_headerbar_label.set_label(_("Transfer Failed")) def __export(self, allow_missing_images: bool = False) -> None: assert self.__exporter self._main_stack.set_visible_child(self._exporting) self.__exporter.export( self.__note, self.__out_format, self.__file_extension, self.__config_manager.markdown_tex_support, allow_missing_images, self.__location, ) def __get_writable_non_container_dir(self) -> Optional[str]: last_dir = self.__config_manager.last_export_directory if last_dir != "" and self.__dir_exists_writable(last_dir): return last_dir elif self.__can_write_documents_dir(): return self.__get_documents_dir() else: return None def __get_documents_dir(self) -> Optional[str]: return GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS) def __can_write_documents_dir(self) -> bool: documents_dir = self.__get_documents_dir() if documents_dir is None: return False else: return self.__dir_exists_writable(documents_dir) def __dir_exists_writable(self, path: str) -> bool: return os.path.exists(path) and os.access(path, os.W_OK) def __init_exporter(self) -> None: # More lazyloading to quicken startup from iotas.exporter import Exporter self.__pdf_exporter = WebKitPdfExporter( self.__webkit_init(), self.__config_manager.markdown_keep_webkit_process ) self.__exporter = Exporter(self.__pdf_exporter, self.__html_generator, const.PKGDATADIR) self.__exporter.connect("finished-downloading", lambda _o: self.__on_finished_downloading()) self.__exporter.connect("finished", lambda _o, path: self.__on_finished(path)) self.__exporter.connect("failed", lambda _o, reason: self.__on_failed(reason)) def __load_extra_formats(self) -> bool: raw_formats = self.__config_manager.extra_export_formats if raw_formats.strip() == "": return False try: formats_json = json.loads(raw_formats) except json.JSONDecodeError as e: logging.warning(f"Failed to load extra formats: {e.msg}") return False if type(formats_json) is not list: logging.warning("Failed to load extra formats: JSON not being a list") return False added = False for item in formats_json: if type(item) is not dict: logging.warning("Failed to load extra format: item not being an object") continue if "pandocOutFormat" not in item: logging.warning("Failed to load extra format: missing pandocOutFormat") continue if "fileExtension" not in item: logging.warning("Failed to load extra format: missing fileExtension") continue out_format = item["pandocOutFormat"] extension = item["fileExtension"] if type(out_format) is not str or out_format.strip() == "": logging.warning("Failed to load extra format: pandocOutFormat is not a string") continue if type(extension) is not str or extension.strip() == "": logging.warning("Failed to load extra format: due to fileExtension is not a string") continue if re.match(r"^[\w_]+$", out_format) is None: logging.warning( "Failed to load extra format: pandocOutFormat contains invalid characters" ) continue if re.match(r"^[\w]+$", extension) is None: logging.warning( "Failed to load extra format: fileExtension contains invalid characters" ) continue logging.debug(f"Adding extra pandoc format {out_format} with extension {extension}") button = Adw.ButtonRow() button.set_title(extension.upper()) button.set_end_icon_name("go-next-symbolic") self._format_listbox.append(button) format_id = out_format.lower() self.__custom_formats[format_id] = {"format": out_format, "extension": extension} added = True return added def __save_last_export_directory(self) -> None: assert self.__location # mypy if os.path.isdir(self.__location): dir_path = os.path.abspath(os.path.join(self.__location, os.pardir)) else: dir_path = os.path.dirname(self.__location) self.__config_manager.last_export_directory = dir_path iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/exporter.py000066400000000000000000000302551507102636600237500ustar00rootroot00000000000000from gi.repository import GObject, GLib import datetime import logging import os import re import shutil from typing import Optional import unicodedata import pypandoc from iotas.attachment_helpers import ( AttachmentsCopyOutcome, copy_note_attachments, get_attachment_disk_states, get_attachments_dir, ) from iotas.html_generator import HtmlGenerator from iotas.markdown_helpers import ( get_image_attachments_from_note_content, get_note_export_content, parse_to_tokens, ) from iotas.note import Note from iotas.pdf_exporter import PdfExporter class Exporter(GObject.Object): """Note exporter. :param PdfExporter pdf_exporter: PDF exporter :param HtmlGenerator html_generator: HTML generator :param str app_data_path: User data path """ __gsignals__ = { "finished-downloading": (GObject.SignalFlags.RUN_FIRST, None, ()), # str: out path "finished": (GObject.SignalFlags.RUN_FIRST, None, (str,)), # str: reason "failed": (GObject.SignalFlags.RUN_FIRST, None, (str,)), } def __init__( self, pdf_exporter: PdfExporter, html_generator: HtmlGenerator, app_data_path: str ) -> None: super().__init__() self.__pdf_exporter = pdf_exporter self.__pdf_exporter.set_callbacks( self.__on_pdf_export_finished, self.__on_pdf_export_failed ) self.__html_generator = html_generator self.__app_data_path = app_data_path self.__active = False self.__in_error = False self.__allow_missing_images = False def export( self, note: Note, out_format: str, file_extension: str, supporting_tex: bool, allow_missing_images: bool = False, user_location: Optional[str] = None, ) -> None: """Export note. :param Note note: Note to render :param str out_format: Export format :param str file_extension: File extension :param bool supporting_tex: TeX support :param bool allow_missing_images: Whether missing images are treated as a failure :param str user_location: User chosen export location, optional """ self.__note = note self.__out_format = out_format self.__supporting_tex = supporting_tex self.__allow_missing_images = allow_missing_images if user_location: self.__location = user_location else: # Running with limited permissions in container, export to exports dir inside container # with automatic filename export_dir = os.path.join(GLib.get_user_data_dir(), "iotas", "exports") filename = self.build_default_filename( note, out_format, file_extension, add_timestamp=True ) self.__location = os.path.join(export_dir, filename) if not os.path.exists(export_dir): try: os.mkdir(export_dir) except OSError as e: logging.warning(f"Failed to export {out_format} to {self.__location}: {e}") self.emit("failed", e) return if not self.__check_for_missing_attachments(): return if out_format == "pdf": self.__export_pdf() elif out_format == "md": self.__export_md() elif out_format == "html": self.__export_html() else: logging.info(f"Asking pandoc to export to {out_format}") self.__export_pandoc(out_format) def build_default_filename( self, note: Note, out_format: str, file_extension: str, add_timestamp: bool = False ) -> str: """Build an export filename for the note. :param Note note: Note to export :param str out_format: Export format :param str file_extension: File extension :param bool add_timestamp: Whether to prefix timestamp :return: Filename :rtype: str """ filename = self.__sanitise_title_for_filename(note.title) if add_timestamp: ts = datetime.datetime.now() filename = ts.strftime("%Y-%m-%dT%H:%M:%S") + " " + filename if out_format == "md": export_to_dir = len(get_image_attachments_from_note_content(note)) > 0 elif out_format == "html": export_to_dir = True else: export_to_dir = False if not export_to_dir: filename += "." + file_extension return filename @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @active.setter def set_active(self, value: bool) -> None: self.__active = value def __on_pdf_export_finished(self) -> None: self.__active = False self.emit("finished", self.__location) def __on_pdf_export_failed(self, error: str) -> None: self.__active = False self.emit("failed", error) def __export_pandoc(self, out_format: str) -> None: self.__active = True content = get_note_export_content(self.__note, prefix_note_id=True) working_dir = os.path.abspath(os.path.join(get_attachments_dir(), os.pardir)) try: pypandoc.convert_text( content, out_format, format="gfm+attributes+implicit_figures", outputfile=self.__location, cworkdir=working_dir, ) except (RuntimeError, OSError) as e: logging.warning(f"Failed to export {out_format} to {self.__location}: {e}") self.emit("failed", str(e)) else: logging.info(f"Exported {self.__out_format} to {self.__location}") self.emit("finished", self.__location) self.__active = False def __export_pdf(self) -> None: self.__active = True self.__pdf_exporter.export(self.__note, self.__location) def __export_md(self) -> None: self.__active = True if len(get_image_attachments_from_note_content(self.__note)) > 0: file_location = os.path.join( self.__location, f"{self.__sanitise_title_for_filename(self.__note.title)}.md" ) if not self.__create_export_directory(): return else: file_location = self.__location export_content = get_note_export_content(self.__note, prefix_note_id=False) try: with open(file_location, "w") as f: f.write(export_content) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to export MD: {e}") self.__active = False return if not self.__copy_attachments(): return self.__active = False logging.info(f"Exported {self.__out_format} to {self.__location}") self.emit("finished", self.__location) def __export_html(self) -> None: self.__active = True parser, tokens = parse_to_tokens( self.__note, exporting=True, tex_support=self.__supporting_tex ) html = self.__html_generator.generate( self.__note, tokens, parser.renderer.render, parser.options, searching=False, export_format="html", ) if not self.__create_export_directory(): return index_filename = os.path.join(self.__location, "index.html") try: with open(index_filename, "w") as f: f.write(html) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to export HTML: {e}") self.__active = False return if not self.__copy_attachments(): return css_dir = os.path.join(self.__location, "css") try: os.mkdir(css_dir) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to export HTML: {e}") self.__active = False return dest_file = os.path.join(css_dir, os.path.basename(HtmlGenerator.RESOURCE_CSS_PATH)) try: shutil.copyfile(f"{self.__app_data_path}/{HtmlGenerator.RESOURCE_CSS_PATH}", dest_file) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to export HTML: {e}") self.__active = False return if self.__supporting_tex: dest_file = os.path.join( css_dir, os.path.basename(HtmlGenerator.RESOURCE_KATEX_CSS_PATH) ) try: shutil.copyfile( f"{self.__app_data_path}/{HtmlGenerator.RESOURCE_KATEX_CSS_PATH}", dest_file ) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to export HTML: {e}") self.__active = False return js_dir = os.path.join(self.__location, "js") try: os.mkdir(js_dir) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to export HTML: {e}") self.__active = False return dest_file = os.path.join(js_dir, os.path.basename(HtmlGenerator.RESOURCE_KATEX_JS_PATH)) try: shutil.copyfile( f"{self.__app_data_path}/{HtmlGenerator.RESOURCE_KATEX_JS_PATH}", dest_file ) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to export HTML: {e}") self.__active = False return self.__active = False logging.info(f"Exported {self.__out_format} to {self.__location}") self.emit("finished", self.__location) def __sanitise_title_for_filename(self, title: str) -> str: """For synced notes the server has already done the sanitising for us. This is for local-only instances. """ value = unicodedata.normalize("NFKC", str(title)) return re.sub(r"[^\w\s\.-]", "", value).strip() def __create_export_directory(self) -> bool: if os.path.exists(self.__location): logging.debug(f"Removing existing {self.__location}") try: shutil.rmtree(self.__location) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to replace dir for {self.__out_format} export: {e}") self.__active = False return False try: os.mkdir(self.__location) except OSError as e: self.emit("failed", e) logging.warning(f"Failed to make dir for {self.__out_format} export: {e}") self.__active = False return False return True def __check_for_missing_attachments(self) -> bool: if len(get_image_attachments_from_note_content(self.__note)) > 0: logging.debug("Checking attachments are on disk") parser, tokens = parse_to_tokens( self.__note, exporting=True, tex_support=self.__supporting_tex ) states = get_attachment_disk_states(self.__note, tokens) success = len(states.missing) == 0 if not success and not self.__allow_missing_images: self.emit("failed", "Failed to export some attachments") self.__active = False return False return True def __copy_attachments(self) -> bool: if len(get_image_attachments_from_note_content(self.__note)) > 0: attachments_dir = os.path.join(self.__location, "attachments") logging.debug("Copying attachments") result = copy_note_attachments(self.__note, attachments_dir, prefix_note_id=False) success = result.outcome in ( AttachmentsCopyOutcome.NONE, AttachmentsCopyOutcome.SUCCESS, ) if not success and not self.__allow_missing_images: self.emit("failed", "Failed to export some attachments") self.__active = False return False return True iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/first_start_page.py000066400000000000000000000025461507102636600254420ustar00rootroot00000000000000from gi.repository import Adw, GLib, Gtk import logging from iotas.config_manager import ConfigManager, HeaderBarVisibility from iotas.ui_utils import have_window_with_width, is_likely_mobile_device @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/first_start_page.ui") class FirstStartPage(Adw.Bin): __gtype_name__ = "FirstStartPage" def initialise_device(self) -> None: """Apply any device-specific initialisation.""" # Another location (ala MigrationAssistant) using this pattern as a result of not yet # discovering the clean way to be notified when a window has obtained its initial size def wait_and_run(): if not have_window_with_width(): GLib.timeout_add(250, wait_and_run) else: self.__set_formatting_bar_visibility_based_on_device() wait_and_run() def __set_formatting_bar_visibility_based_on_device(self) -> None: if is_likely_mobile_device(): # Default setting is always visible so no change logging.info("Likely on mobile device, setting formatting bar to stay visible") else: logging.info("Likely not on mobile device, setting formatting bar to auto hide") ConfigManager.get_default().editor_formatting_bar_visibility = ( HeaderBarVisibility.AUTO_HIDE ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/focus_mode_helper.py000066400000000000000000000100321507102636600255510ustar00rootroot00000000000000import gi gi.require_version("GtkSource", "5") from gi.repository import Adw, GObject, GtkSource, Pango import logging class FocusModeHelper(GObject.Object): # Adwaita light_4 UNFOCUSED_COLOUR_LIGHT = "#c0bfbc" # Adwaita dark_2 UNFOCUSED_COLOUR_DARK = "#5e5c64" def __init__(self, buffer: GtkSource.Buffer) -> None: super().__init__() self.__buffer = buffer self.__handler_ids: list[int] = [] self.__active = False start_iter = buffer.get_start_iter() self.__last_start = buffer.create_mark(None, start_iter) self.__last_end = buffer.create_mark(None, start_iter) style_manager = Adw.StyleManager.get_default() style_manager.connect("notify::dark", self.__on_style_change) init_colour = ( self.UNFOCUSED_COLOUR_DARK if style_manager.get_dark() else self.UNFOCUSED_COLOUR_LIGHT ) self.__tag = buffer.create_tag( "unfocused", foreground=init_colour, underline=Pango.Underline.NONE ) @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @active.setter def set_active(self, value: bool) -> None: self.__active = value if self.__active and len(self.__handler_ids) == 0: self.__activate() elif not self.__active and len(self.__handler_ids) > 0: self.__deactivate() def __activate(self) -> None: logging.debug("Activating focus mode") for signal in ("cursor-moved", "changed"): handler_id = self.__buffer.connect(signal, lambda _o: self.__refresh(initial=False)) self.__handler_ids.append(handler_id) self.__reset_marks() self.__refresh(initial=True) def __deactivate(self) -> None: logging.debug("Deactivating focus mode") self.__buffer.remove_tag( self.__tag, self.__buffer.get_start_iter(), self.__buffer.get_end_iter() ) for handler_id in self.__handler_ids: self.__buffer.disconnect(handler_id) self.__handler_ids = [] def __refresh(self, initial: bool) -> None: buffer = self.__buffer # Determine current sentence start_iter = buffer.get_iter_at_mark(buffer.get_insert()) if not start_iter.starts_sentence() and not start_iter.starts_line(): start_iter.backward_sentence_start() end_iter = start_iter.copy() if not start_iter.ends_line(): end_iter.forward_sentence_end() # Check if changed last_start = buffer.get_iter_at_mark(self.__last_start) last_end = buffer.get_iter_at_mark(self.__last_end) start_changed = not last_start.equal(start_iter) or initial end_changed = not last_end.equal(end_iter) or initial if not start_changed and not end_changed: return # Untag last sections if start_changed: buffer.remove_tag(self.__tag, buffer.get_start_iter(), last_start) if end_changed: buffer.remove_tag(self.__tag, last_end, buffer.get_end_iter()) # Tag new sections if start_changed: if not start_iter.is_start(): buffer.apply_tag(self.__tag, buffer.get_start_iter(), start_iter) buffer.move_mark(self.__last_start, start_iter) if end_changed: if not end_iter.is_end(): buffer.apply_tag(self.__tag, end_iter, buffer.get_end_iter()) buffer.move_mark(self.__last_end, end_iter) def __on_style_change( self, style_manager: Adw.StyleManager, _value: GObject.ParamSpec, ) -> None: if style_manager.get_dark(): self.__tag.set_property("foreground", self.UNFOCUSED_COLOUR_DARK) else: self.__tag.set_property("foreground", self.UNFOCUSED_COLOUR_LIGHT) def __reset_marks(self) -> None: start_iter = self.__buffer.get_start_iter() self.__buffer.move_mark(self.__last_start, start_iter) self.__buffer.move_mark(self.__last_end, start_iter) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/font_size_selector.py000066400000000000000000000061651507102636600260030ustar00rootroot00000000000000from gi.repository import Gio, Gtk import logging from iotas.config_manager import ConfigManager @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/font_size_selector.ui") class FontSizeSelector(Gtk.Box): __gtype_name__ = "FontSizeSelector" _label: Gtk.Label = Gtk.Template.Child() VALID_SIZES = [ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 34, 38, ] def __init__(self) -> None: super().__init__() self.__increase_action: Gio.SimpleAction self.__decrease_action: Gio.SimpleAction self.__config_manager = ConfigManager.get_default() self.__config_manager.connect_changed( ConfigManager.FONT_SIZE, self.__refresh_from_setting, ) def setup(self): self.__setup_actions() self.__refresh_from_setting() def increase(self) -> None: if not self.__increase_action.get_enabled(): return previous_size = self.__config_manager.font_size ind = self.VALID_SIZES.index(previous_size) size = self.VALID_SIZES[ind + 1] self.__config_manager.font_size = size logging.info(f"Font size increased to {size}pt") def decrease(self) -> None: if not self.__decrease_action.get_enabled(): return previous_size = self.__config_manager.font_size ind = self.VALID_SIZES.index(previous_size) size = self.VALID_SIZES[ind - 1] self.__config_manager.font_size = size logging.info(f"Font size decreased to {size}pt") def reset(self) -> None: previous_size = self.__config_manager.font_size default_size = self.__config_manager.default_font_size if previous_size != default_size: self.__config_manager.font_size = default_size logging.info(f"Font size reset (to {default_size}pt)") def __setup_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() action = Gio.SimpleAction.new("increase") action.connect("activate", lambda _o, _v: self.increase()) action_group.add_action(action) self.__increase_action = action action = Gio.SimpleAction.new("decrease") action.connect("activate", lambda _o, _v: self.decrease()) action_group.add_action(action) self.__decrease_action = action action = Gio.SimpleAction.new("reset") action.connect("activate", lambda _o, _v: self.reset()) action_group.add_action(action) app.get_active_window().insert_action_group("font-size-selector", action_group) self.__action_group = action_group def __refresh_from_setting(self) -> None: size = self.__config_manager.font_size self._label.set_label("{}pt".format(size)) ind = self.VALID_SIZES.index(size) self.__increase_action.set_enabled(ind + 1 < len(self.VALID_SIZES)) self.__decrease_action.set_enabled(ind - 1 >= 0) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/formatter.py000066400000000000000000001255421507102636600241070ustar00rootroot00000000000000from gi.repository import GObject, Gtk, GtkSource from enum import IntEnum, auto import logging import math import re from typing import Callable, Optional from iotas.ordered_list_utils import ( check_line_for_ordered_list_item, calculate_ordered_list_index, format_ordered_list_item, ) from iotas.text_utils import ( get_iters_at_sourceview_context_class_extents, iter_forward_to_context_class_removed, parse_any_url_at_iter, parse_markdown_automatic_link, parse_markdown_inline_link, str_is_url, ) class LinkStateInfo(GObject.Object): """State information for a markup link in the buffer.""" creating: bool = True """Creating a new link""" url_angle_bracketed: bool = False """Editing link with URL angle-bracket wrapped""" automatic_link: bool = False """Creating a new link from an automatic link""" text: str = "" """Link text""" link: str = "" """Link URL""" title: str = "" """Link title, which gets stored and recreated""" source_text: str = "" """Source text for a link being edited. Used for verification if a note is server updated.""" start_offset: int = -1 """Start offset for a link being edited. Used for verification if a note is server updated.""" end_offset: int = -1 """End offset for a link being edited. Used for verification if a note is server updated.""" class _ListType(IntEnum): """Markup list type.""" UNORDERED = auto() ORDERED = auto() TASK = auto() class Formatter(GObject.Object): """Markup formatter.""" def __init__(self) -> None: super().__init__() self.__buffer: GtkSource.Buffer def bold(self) -> None: """Apply user bold formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ insert = self.__get_selection_start_or_insert_iter() if "bold" in self.__buffer.get_context_classes_at_iter(insert): # In bold, remove self.__delete_wrapping_markup("bold", insert, 2) elif self.__buffer.get_has_selection() and not self.__have_multi_line_selection(): # Have single line selection, wrap in bold self.__wrap_selection_in_markup("*", 2) else: text = self.__buffer.get_property("text") if self.__in_empty_bold(text, insert.get_offset()): # Handle toggle self.__delete_chars_around_iter(insert, 2) else: # Insert empty bold markup around cursor self.__insert_and_centre_iter(insert, "****") def italic(self) -> None: """Apply user italic formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ insert = self.__get_selection_start_or_insert_iter() if "italic" in self.__buffer.get_context_classes_at_iter(insert): # In italic, remove self.__delete_wrapping_markup("italic", insert, 1) elif self.__buffer.get_has_selection() and not self.__have_multi_line_selection(): # Have single line selection, wrap in italic self.__wrap_selection_in_markup("_", 1) else: text = self.__buffer.get_property("text") if self.__in_empty_italics(text, insert.get_offset()): # Handle toggle self.__delete_chars_around_iter(insert, 1) else: # Insert empty italic markup around cursor self.__insert_and_centre_iter(insert, "__") def strikethrough(self) -> None: """Apply user strikethrough formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ insert = self.__get_selection_start_or_insert_iter() if "strikethrough" in self.__buffer.get_context_classes_at_iter(insert): # In strikethrough, remove self.__delete_wrapping_markup("strikethrough", insert, 2) elif self.__buffer.get_has_selection() and not self.__have_multi_line_selection(): # Have single line selection, wrap in strikethrough self.__wrap_selection_in_markup("~", 2) else: text = self.__buffer.get_property("text") if self.__in_empty_strikethrough(text, insert.get_offset()): # Handle toggle self.__delete_chars_around_iter(insert, 2) else: # Insert empty strikethrough markup around cursor self.__insert_and_centre_iter(insert, "~~~~") def quote(self) -> None: """Apply user quote formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ insert = self.__get_selection_start_or_insert_iter() line_start = insert.copy() line_start.set_line_offset(0) if self.__have_multi_line_selection(): # Handle multi-line selection minimum_depth = self.__get_minimum_quote_marker_depth_across_selection_lines() if minimum_depth == 0: # Some lines have no marker, add markers to all logging.debug("Adding quote level") self.__run_method_on_selection_lines(self.__add_quote_marker_to_line) else: # All lines have a marker, remove a level logging.debug("Removing quote level") self.__run_method_on_selection_lines(self.__remove_quote_marker_from_line) elif "blockquote" in self.__buffer.get_context_classes_at_iter(line_start): # In quote, remove logging.debug("Removing quote") self.__buffer.begin_user_action() self.__remove_quote_marker_from_line(line_start) self.__buffer.end_user_action() else: # Prepend line with quote markup logging.debug("Adding quote") self.__buffer.begin_user_action() self.__add_quote_marker_to_line(line_start) self.__buffer.end_user_action() def heading(self, new_level: int) -> None: """Apply user heading formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, requested level, etc. :param int new_level: Requested header level, zero to remove """ insert = self.__get_selection_start_or_insert_iter() line_start = insert.copy() line_start.set_line_offset(0) # Check for existing heading heading_start = line_start.copy() existing_level = 0 while not heading_start.ends_line(): char = self.__get_line_char_at_iter(heading_start) if char == "#": heading_counter = heading_start.copy() while self.__get_line_char_at_iter(heading_counter) == "#": existing_level += 1 heading_counter.forward_char() break heading_start.forward_char() if existing_level == new_level: logging.info(f"Nothing to do, already have heading level {new_level}") return self.__buffer.begin_user_action() # Remove any existing heading if existing_level: end = heading_start.copy() end.forward_chars(existing_level) char = self.__get_line_char_at_iter(end) if char.isspace(): end.forward_char() self.__buffer.delete(heading_start, end) else: heading_start = line_start.copy() # Insert new heading if new_level: self.__buffer.insert(heading_start, "#" * new_level) self.__insert_space_if_not_exists(heading_start) self.__buffer.end_user_action() def get_link_state(self) -> LinkStateInfo: """Fetch link state information for context. Returned object will vary depending on note contents, cursor location or any selection. :return: Link information at cursor/selection :rtype: LinkStateInfo """ info = LinkStateInfo() mark = self.__buffer.get_insert() if self.__buffer.get_has_selection(): # Use selection start, end = self.__buffer.get_selection_bounds() selection_start_classes = self.__buffer.get_context_classes_at_iter(start) text = self.__buffer.get_text(start, end, include_hidden_chars=False) if "\n" in text: # Multiline selection, ignore selection and create new link logging.debug("Have newline, ignoring selection") info.creating = True elif "inline-link" in selection_start_classes: # Start of selection in existing inline link, parse and edit if self.__parse_link(start, info): info.creating = False else: # Failed to parse, ignore selection and create new link info.creating = True elif "automatic-link" in selection_start_classes: # Start of selection in automatic link, parse and edit, converting to inline link logging.debug("Have automatic-link") info.creating = False self.__parse_automatic_link(start, info) elif self.__selection_has_context_classes(): # There are some (language parsing) context classes in the selection, let's just # ignore the selection and create new link logging.debug("Not using selection for URL text as it appears to have formatting") info.creating = True elif str_is_url(text, http_only=False): # Selected text is URL, populate into link creation dialog info.creating = True info.link = text info.source_text = text info.start_offset = start.get_offset() info.end_offset = end.get_offset() return info elif self.__link_scheme_in_text(text): # There's a URI scheme somewhere in the selection but we haven't managed to # identify the whole selection as a URL. Ignore the selection and create a new link. info.creating = True else: # Populate the selected text into link creation dialog logging.debug("Using selection text") info.creating = True info.text = text info.source_text = text info.start_offset = start.get_offset() info.end_offset = end.get_offset() else: # No selection insert = self.__buffer.get_iter_at_mark(mark) classes = self.__buffer.get_context_classes_at_iter(insert) if "inline-link" in classes: # Existing inline link under cursor, parse and edit if self.__parse_link(insert, info): info.creating = False else: # Failed to parse, ignore link under cursor and create new link info.creating = True elif "automatic-link" in classes: # Cursor in automatic link, parse and edit, converting to inline link logging.debug("Have automatic-link") info.creating = True self.__parse_automatic_link(insert, info) elif self.__check_in_url_and_populate_state(insert, info): # Cursor in middle of URL, populate to link creation dialog info.creating = True else: # Create new link info.creating = True return info def link(self, info: LinkStateInfo) -> None: """Apply user link formatting action. This applies the result coming out of the link dialog. :param LinkStateInfo info: Details on the changes to be made """ self.__buffer.begin_user_action() if self.__buffer.get_has_selection(): insert, _ = self.__buffer.get_selection_bounds() insert_mark = self.__buffer.create_mark(None, insert) cleanup_mark = True else: insert_mark = self.__buffer.get_insert() cleanup_mark = False # If the edit is based on existing buffer text, delete that text after ensuring it hasn't # been modified by a remote update if info.source_text != "": start = self.__buffer.get_iter_at_offset(info.start_offset) end = self.__buffer.get_iter_at_offset(info.end_offset) text = self.__buffer.get_text(start, end, include_hidden_chars=False) if info.source_text != text: logging.warning("Note appears to have changed, inserting link instead") else: self.__buffer.delete(start, end) insert = self.__buffer.get_iter_at_mark(insert_mark) self.__insert_link(insert, info) # Nudge cursor back into link to enable immediate re-edit insert.backward_char() self.__buffer.place_cursor(insert) if cleanup_mark: self.__buffer.delete_mark(insert_mark) self.__buffer.end_user_action() def code(self) -> None: """Apply user code formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ insert = self.__get_selection_start_or_insert_iter() context_classes = self.__buffer.get_context_classes_at_iter(insert) if "code-block" in context_classes: # In code block, remove self.__buffer.begin_user_action() self.__delete_wrapping_markup("code-block", insert, 3, user_action=False) # Also remove the newline inserted on the starting markup, useful quick toggle to undo insert = self.__get_selection_start_or_insert_iter() prev_char = insert.copy() prev_char.backward_char() self.__buffer.delete(prev_char, insert) self.__buffer.end_user_action() elif "code-span" in context_classes: # In code span, remove backticks = 2 if "2-backticks-code-span" in context_classes else 1 self.__delete_wrapping_markup("code-span", insert, backticks) elif not self.__buffer.get_has_selection() or "indented-code-block" in context_classes: # Have no selection, or have indented code block # For now indented codeblocks are basically ignored if "indented-code-block" in context_classes: logging.info( "Your indented codeblock likely isn't being handled as you'd hope, sorry!" ) text = self.__buffer.get_property("text") if self.__in_empty_codespan(text, insert.get_offset()): # Handle toggle self.__delete_chars_around_iter(insert, 1) else: # Insert code span markup around cursor self.__insert_and_centre_iter(insert, "``") else: # Have selection start, end = self.__buffer.get_selection_bounds() start_mark = self.__buffer.create_mark(None, start) end_mark = self.__buffer.create_mark(None, end) if start.get_line() != end.get_line(): # Multi line selection, add code block markup logging.debug("Adding code-block for multi-line selection") chars = "```\n" # If selection doesn't start a line insert a newline before the start markup if not start.starts_line(): chars = "\n" + chars self.__buffer.begin_user_action() self.__buffer.insert(start, chars) end = self.__buffer.get_iter_at_mark(end_mark) chars = "```" if not end.starts_line(): # Selection doesn't end a line insert a newline before the end markup chars = "\n" + chars + "\n" elif not self.__blank_line_follows(end): # Not following blank line, single newline after chars += "\n" self.__buffer.insert(end, chars) self.__buffer.end_user_action() # Retain selection start = self.__buffer.get_iter_at_mark(start_mark) end.backward_chars(len(chars)) self.__buffer.select_range(start, end) else: # Single line selection, add code span markup logging.debug("Adding code-span for single-line selection") self.__buffer.begin_user_action() self.__buffer.insert(start, "`") end = self.__buffer.get_iter_at_mark(end_mark) self.__buffer.insert(end, "`") # Retain selection start = self.__buffer.get_iter_at_mark(start_mark) end = self.__buffer.get_iter_at_mark(end_mark) end.backward_chars(1) self.__buffer.select_range(start, end) # Cleanup self.__buffer.delete_mark(start_mark) self.__buffer.delete_mark(end_mark) self.__buffer.end_user_action() def unordered_list(self) -> None: """Apply user unordered list formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ logging.debug("unordered-list") self.__process_list(_ListType.UNORDERED, lambda iter: self.__buffer.insert(iter, "-")) def ordered_list(self) -> None: """Apply user ordered list formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ logging.debug("ordered-list") # If the previous line contains an ordered list item attempt to continue that list def add_marker(iter: Gtk.TextIter) -> None: # Default value = "1." line_start = iter.copy() line_start.set_line_offset(0) if not line_start.is_start(): # Get previous line text previous_line_start = line_start.copy() previous_line_start.backward_line() line_end = previous_line_start.copy() line_end.forward_to_line_end() previous_line = self.__buffer.get_text( previous_line_start, line_end, include_hidden_chars=False ) # Check if it contains an ordered list item regex_match = check_line_for_ordered_list_item(previous_line) if regex_match: _, index, marker = regex_match.groups() spacing = "" # Determine the value of the next item in the sequence sequence_next = calculate_ordered_list_index(index, 1) if sequence_next: value = format_ordered_list_item(spacing, sequence_next, marker).strip() self.__buffer.insert(iter, value) self.__process_list(_ListType.ORDERED, add_marker) def checkbox(self) -> None: """Apply user checkbox formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ logging.debug("checkbox") self.__process_list(_ListType.TASK, lambda iter: self.__buffer.insert(iter, "- [ ]")) def toggle_checkbox(self) -> None: """Toggle any checkbox on the current line or selected lines.""" logging.debug("toggle-checkbox") self.__buffer.begin_user_action() if self.__buffer.get_has_selection(): # Have selection, perform toggle for each line in selection self.__run_method_on_selection_lines(self.__toggle_checkbox_single_line) else: # No selection, toggle any checkpoint on cursor line mark = self.__buffer.get_insert() insert = self.__buffer.get_iter_at_mark(mark) line_start = insert.copy() line_start.set_line_offset(0) self.__toggle_checkbox_single_line(line_start) self.__buffer.end_user_action() def horizontal_rule(self) -> None: """Apply user horizontal rule formatting action. This may result in adding or removing formatting, depending on cursor and selection state, note contents, etc. """ insert = self.__get_selection_start_or_insert_iter() line_start = insert.copy() line_start.set_line_offset(0) # Check for existing horizontal rule on the cursor line, or the line at the start of the # selection start = line_start.copy() found = False while not start.ends_line(): if "horizontal-rule" in self.__buffer.get_context_classes_at_iter(start): found = True break start.forward_char() if found: # Horizontal rule found on line, remove logging.debug("Removing horizontal rule") end = line_start.copy() if not iter_forward_to_context_class_removed(end, "horizontal-rule"): return self.__buffer.delete(start, end) else: # Add horizontal rule markup logging.debug("Adding horizontal rule") chars = "- - -" if not insert.starts_line(): # Not at start of line, double newline before chars = "\n\n" + chars elif not self.__after_blank_line(insert): # Not preceding blank line, single newline before chars = "\n" + chars # Track suffixed chars separately so we can place the cursor back in the markup to # allow eg. toggling suffix_chars = "" if not insert.ends_line(): # Not at end of line, double newline after suffix_chars = "\n\n" elif not self.__blank_line_follows(insert): # Not following blank line, single newline after suffix_chars = "\n" self.__buffer.insert(insert, chars + suffix_chars) insert.backward_chars(len(suffix_chars)) self.__buffer.place_cursor(insert) def table(self, columns: int, rows: int, view_width: int, character_width: float) -> None: """Insert a table. :param int columns: Number of columns :param int rows: Number of rows (below header) :param int view_width: View pixel width :param float character_width: Estimated pixel width of single character in font """ logging.info(f"Insert {columns}x{rows} table") insert = self.__get_selection_start_or_insert_iter() # Attempt to insert a valid table which doesn't wrap for the current view width. # First, cap table pixel width for wide views view_width = min(view_width, 1000) character_width = max(1.0, character_width) # Calculate max number of characters for the width max_chars = math.floor(view_width / character_width * 0.9) per_column_internal_chars = int((max_chars - 1 - columns) / columns) # Minimum 3 characters column width, by GFM standard column_width = max(3, per_column_internal_chars) # Cap column width column_width = min(per_column_internal_chars, 20) table = "" for row in range(rows + 1): line = "|" for _ in range(columns): line += " " * column_width + "|" table += line + "\n" if row == 0: # Add header separator line = "|" for _ in range(columns): line += "-" * column_width + "|" table += line + "\n" self.__buffer.insert(insert, table) @GObject.Property(type=GtkSource.Buffer) def buffer(self) -> GtkSource.Buffer: return self.__buffer @buffer.setter def set_buffer(self, value: GtkSource.Buffer) -> None: self.__buffer = value def __get_wrapping_characters( self, start: Gtk.TextIter, end: Gtk.TextIter, characters: int ) -> Optional[str]: text = self.__buffer.get_property("text") if start.get_offset() < characters or end.get_offset() > len(text) - characters: # Handling bad request, being at start or end of buffer return None return text[start.get_offset() - characters : end.get_offset() + characters] def __get_line_char_at_iter(self, location: Gtk.TextIter) -> str: if location.ends_line(): return "" else: return self.__get_char_at_iter(location) def __get_char_at_iter(self, location: Gtk.TextIter) -> str: char_end = location.copy() char_end.forward_char() return self.__buffer.get_text(location, char_end, include_hidden_chars=False) def __insert_space_if_not_exists(self, location: Gtk.TextIter) -> None: if location.ends_line(): self.__buffer.insert(location, " ") else: char = self.__get_line_char_at_iter(location) if not char.isspace(): self.__buffer.insert(location, " ") def __in_empty_bold(self, text: str, location: int) -> bool: markup_width = 2 return self.__check_if_expression_occurs_at_location( text, r"(? bool: markup_width = 1 return self.__check_if_expression_occurs_at_location( text, r"(? bool: markup_width = 2 return self.__check_if_expression_occurs_at_location( text, r"(? bool: markup_width = 1 return self.__check_if_expression_occurs_at_location( text, r"(? bool: """Check if regular expression occurs in text at specified location. :param str text: Text to search :param str regex: Regex :param int location: Location as offset :return: Whether matched :rtype: bool """ success = False match_iter = re.finditer(regex, text) for match in match_iter: if match.start() == location: success = True break return success def __parse_link(self, inside: Gtk.TextIter, info: LinkStateInfo) -> bool: """Parse link elements from a known inline link. :param Gtk.TextIter inside: Iter inside inline link :param LinkStateInfo: Object to populate into :return: Success :rtype: bool """ result = parse_markdown_inline_link(inside) if not result: return False info.link = result.link info.text = result.text info.source_text = result.source_text info.start_offset = result.start_offset info.end_offset = result.end_offset info.url_angle_bracketed = result.url_angle_bracketed return True def __parse_automatic_link(self, inside: Gtk.TextIter, info: LinkStateInfo) -> bool: """Parse URL from a known automatic link. :param Gtk.TextIter inside: Iter inside inline link :param LinkStateInfo: Object to populate into :return: Success :rtype: bool """ info.creating = True result = parse_markdown_automatic_link(inside) if result: info.automatic_link = True info.title = "" info.link = result.link info.source_text = result.source_text info.start_offset = result.start_offset info.end_offset = result.end_offset return True else: # Failure very unlikely as we depend on the GtkSourceView language parsing to reach # here logging.warning("Failed to parse automatic-link") return False def __delete_wrapping_markup( self, cls: str, inside: Gtk.TextIter, width: int, user_action: bool = True ) -> None: logging.debug(f"Removing wrapping '{cls}'") start, end = get_iters_at_sourceview_context_class_extents(cls, inside) if not start: return end_mark = self.__buffer.create_mark(None, end) tmp = start.copy() tmp.forward_chars(width) if user_action: self.__buffer.begin_user_action() self.__buffer.delete(start, tmp) end = self.__buffer.get_iter_at_mark(end_mark) tmp = end.copy() end.backward_chars(width) self.__buffer.delete(end, tmp) self.__buffer.delete_mark(end_mark) if user_action: self.__buffer.end_user_action() def __wrap_selection_in_markup(self, char: str, count: int) -> None: """Wrap selection in markup. :param str char: Character to insert :param int count: Number of times to insert the character on each side of the selection """ logging.debug(f"Wrapping selection with '{char*count}'") start, end = self.__buffer.get_selection_bounds() start_mark = self.__buffer.create_mark(None, start) end_mark = self.__buffer.create_mark(None, end) self.__buffer.begin_user_action() self.__buffer.insert(start, char * count) end = self.__buffer.get_iter_at_mark(end_mark) self.__buffer.insert(end, char * count) # Retain selection start = self.__buffer.get_iter_at_mark(start_mark) end = self.__buffer.get_iter_at_mark(end_mark) end.backward_chars(count) self.__buffer.select_range(start, end) # Cleanup self.__buffer.delete_mark(start_mark) self.__buffer.delete_mark(end_mark) self.__buffer.end_user_action() def __delete_chars_around_iter(self, inside: Gtk.TextIter, either_side_count: int) -> None: start = inside.copy() start.backward_chars(either_side_count) end = start.copy() end.forward_chars(either_side_count * 2) self.__buffer.delete(start, end) def __insert_and_centre_iter(self, location: Gtk.TextIter, value: str) -> None: """Insert text and centre cursor in new text. :param Gtk.TextIter location: Location to insert :param str value: Text to insert """ if value == "": return insert = location.copy() mark = self.__buffer.create_mark(None, location) self.__buffer.insert(insert, value) insert = self.__buffer.get_iter_at_mark(mark) insert.backward_chars(int(len(value) / 2)) self.__buffer.place_cursor(insert) self.__buffer.delete_mark(mark) def __get_selection_start_or_insert_iter(self) -> Gtk.TextIter: """Fetch an iter at either the start of the selection or cursor. :return: The iter :rtype: Gtk.TextIter """ if self.__buffer.get_has_selection(): insert, _ = self.__buffer.get_selection_bounds() else: insert = self.__buffer.get_iter_at_mark(self.__buffer.get_insert()) return insert def __selection_has_context_classes(self) -> bool: """Check whether any context class exists in the selection. :return: Whether any context class exists :rtype: bool """ if not self.__buffer.get_has_selection(): logging.warning("No selection?") return False have_classes = False start, end = self.__buffer.get_selection_bounds() loc = start.copy() while loc.get_offset() != end.get_offset(): have_classes = len(self.__buffer.get_context_classes_at_iter(loc)) > 0 if have_classes: break loc.forward_char() return have_classes def __check_in_url_and_populate_state(self, iter: Gtk.TextIter, info: LinkStateInfo) -> bool: """Check whether location in buffer is in a URL and if so populate it into link info. :param Gtk.TextIter iter: Iter :param LinkStateInfo: Object to populate into :return: Whether URL found :rtype: bool """ result = parse_any_url_at_iter(iter, http_only=False) if result: info.link = result.link info.source_text = result.link info.start_offset = result.start_offset info.end_offset = result.end_offset return True else: return False def __link_scheme_in_text(self, text: str) -> bool: return "https://" in text or "http://" in text def __insert_link(self, insert: Gtk.TextIter, info: LinkStateInfo) -> None: link = info.link if " " in link or info.url_angle_bracketed: link = f"<{link}>" title = "" if info.title.strip() != "": title = f' "{info.title}"' self.__buffer.insert(insert, f"[{info.text}]({link}{title})") def __process_list(self, list_type: _ListType, add_marker: Callable) -> None: """Apply user list action to all lines in a selection or on the cursor line. :param _ListType list_type: Type of list the user has actioned :param Callable add_mark: Method to call to add marker """ self.__buffer.begin_user_action() if self.__buffer.get_has_selection(): def callback(line_start: Gtk.TextIter): self.__single_line_list_marker_action(line_start, list_type, add_marker) self.__run_method_on_selection_lines(callback) else: mark = self.__buffer.get_insert() insert = self.__buffer.get_iter_at_mark(mark) line_start = insert.copy() line_start.set_line_offset(0) self.__single_line_list_marker_action(line_start, list_type, add_marker) self.__buffer.end_user_action() def __run_method_on_selection_lines(self, method: Callable) -> None: if not self.__buffer.get_has_selection(): logging.warning("No selection, incorrect method use") return insert, end = self.__buffer.get_selection_bounds() end_mark = self.__buffer.create_mark(None, end) line_start = insert.copy() line_start.set_line_offset(0) while line_start.compare(end) < 0 and not line_start.is_end(): insert_mark = self.__buffer.create_mark(None, line_start) method(line_start) line_start = self.__buffer.get_iter_at_mark(insert_mark) line_start.forward_line() end = self.__buffer.get_iter_at_mark(end_mark) self.__buffer.delete_mark(insert_mark) self.__buffer.delete_mark(end_mark) def __single_line_list_marker_action( self, line_start: Gtk.TextIter, list_type: _ListType, add_marker: Callable ) -> None: # Set GtkSourceView context class from list type cls = "checkbox" if list_type == _ListType.TASK else "list-marker" # Build list of the types, excuding our actioned type other_types = list(_ListType) other_types.remove(list_type) # Check for and remove actioned type removed = False if cls in self.__buffer.get_context_classes_at_iter(line_start): removed = self.__remove_existing_list_marker_on_line(line_start, [list_type]) # If we haven't removed our actioned marker type from the line add it if not removed: logging.debug(f"No {list_type.name.lower()} marker removed, adding") self.__remove_existing_list_marker_on_line(line_start, other_types) add_marker(line_start) self.__insert_space_if_not_exists(line_start) def __remove_existing_list_marker_on_line( self, insert: Gtk.TextIter, types: list[_ListType] ) -> bool: """Remove any existing list marker for provided list types on line. :param Gtk.TextIter: Iter on line :param list[_ListType]: Types to remove :return: Whether any marker was removed :rtype: bool """ if len(types) == 0: logging.warning("No list type to remove") return False # Build the GtkSourceView context classes to remove remove_classes = [] if _ListType.UNORDERED in types or _ListType.ORDERED in types: remove_classes.append("list-marker") if _ListType.TASK in types: remove_classes.append("checkbox") line_start = insert.copy() line_start.set_line_offset(0) markup_start = line_start.copy() removed = False for cls in remove_classes: # Check if have context class at line start if cls in self.__buffer.get_context_classes_at_iter(line_start): logging.debug("Removing existing marker") end = line_start.copy() if not iter_forward_to_context_class_removed(end, cls): return False # Move past spaces first_char = self.__get_char_at_iter(markup_start) while first_char.isspace(): markup_start.forward_char() first_char = self.__get_char_at_iter(markup_start) # Skip this line if we find the marker for a type we're not removing if cls == "list-marker": if _ListType.UNORDERED not in types and first_char in ("*", "-", "+"): continue elif _ListType.ORDERED not in types and first_char not in ("*", "-", "+"): continue # Delete from the markup start to the end of the context class insert_mark = self.__buffer.create_mark(None, markup_start) self.__buffer.delete(markup_start, end) insert.assign(self.__buffer.get_iter_at_mark(insert_mark)) self.__buffer.delete_mark(insert_mark) removed = True break return removed def __toggle_checkbox_single_line(self, line_start: Gtk.TextIter) -> None: # Find checkbox check = line_start.copy() found = False while not check.ends_line(): check.forward_char() if "checkbox-check" in self.__buffer.get_context_classes_at_iter(check): found = True break if not found: logging.debug("No checkbox check found to toggle") return # Toggle end = check.copy() end.forward_char() value = self.__buffer.get_text(check, end, include_hidden_chars=False) new_value = "x" if value == " " else " " self.__buffer.delete(check, end) self.__buffer.insert(check, new_value) def __after_blank_line(self, insert: Gtk.TextIter) -> bool: if insert.get_line() == 0: return False line_start = insert.copy() line_start.set_line_offset(0) location = insert.copy() location.backward_line() return line_start.get_offset() == location.get_offset() + 1 def __blank_line_follows(self, insert: Gtk.TextIter) -> bool: location = insert.copy() # Check for no next line location.forward_to_line_end() if location.is_end(): return False location.forward_line() following_line_offset = location.get_offset() location.forward_line() # Second match option here caters for end of buffer return location.get_offset() in (following_line_offset + 1, following_line_offset) def __have_multi_line_selection(self) -> bool: if not self.__buffer.get_has_selection(): return False start, end = self.__buffer.get_selection_bounds() return start.get_line() != end.get_line() def __get_line_quote_marker_depth(self, iter: Gtk.TextIter) -> int: if "blockquote" not in self.__buffer.get_context_classes_at_iter(iter): return 0 offset = 0 loc = iter.copy() while not loc.ends_line(): char = self.__get_line_char_at_iter(loc) if char == ">": offset += 1 elif not char.isspace(): break loc.forward_char() return offset def __get_minimum_quote_marker_depth_across_selection_lines(self) -> int: """Get the minimum depth of blockquote (markers) in the selection lines. Should only be called with a selection. :return: Minimum quote marker depth :rtype: int """ if not self.__buffer.get_has_selection(): logging.warning("No selection, incorrect method use") return 0 offsets = set() line_start, end = self.__buffer.get_selection_bounds() line_start.set_line_offset(0) while line_start.compare(end) < 0 and not line_start.is_end(): offsets.add(self.__get_line_quote_marker_depth(line_start)) line_start.forward_line() return min(offsets) def __add_quote_marker_to_line(self, insert: Gtk.TextIter) -> None: self.__move_to_first_quote_marker_on_line(insert) self.__buffer.insert(insert, ">") self.__insert_space_if_not_exists(insert) def __remove_quote_marker_from_line(self, location: Gtk.TextIter) -> None: quote_start = location.copy() if not self.__move_to_first_quote_marker_on_line(quote_start): logging.warning("Couldn't find quote marker") return # Remove marker delete_end = quote_start.copy() delete_end.forward_char() self.__buffer.delete(quote_start, delete_end) # Remove following space if one exists if not quote_start.ends_line(): char = self.__get_line_char_at_iter(quote_start) if char.isspace(): delete_end = quote_start.copy() delete_end.forward_char() self.__buffer.delete(quote_start, delete_end) def __move_to_first_quote_marker_on_line(self, insert: Gtk.TextIter) -> bool: found = False search = insert.copy() while not search.ends_line(): if self.__get_line_char_at_iter(search) == ">": found = True break search.forward_char() if found: insert.assign(search) return found iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/formatting_header_bar.py000066400000000000000000000245241507102636600264100ustar00rootroot00000000000000from gi.repository import Adw, Gio, GLib, GObject, Gtk, GtkSource, Pango from typing import Callable, Optional from iotas.formatter import Formatter, LinkStateInfo from iotas.link_dialog import LinkDialog from iotas.table_dialog import TableDialog @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/formatting_header_bar.ui") class FormattingHeaderBar(Adw.BreakpointBin): """Editor formatting header bar.""" __gtype_name__ = "FormattingHeaderBar" __gsignals__ = { "height-change": (GObject.SignalFlags.RUN_FIRST, None, ()), } _breakpoint: Adw.Breakpoint = Gtk.Template.Child() _base_box: Gtk.Box = Gtk.Template.Child() _parent_box: Gtk.Box = Gtk.Template.Child() _extend_box: Gtk.Box = Gtk.Template.Child() _heading_menu: Gtk.MenuButton = Gtk.Template.Child() _menu_button: Gtk.MenuButton = Gtk.Template.Child() _header_bar: Adw.HeaderBar = Gtk.Template.Child() _link_button: Gtk.Button = Gtk.Template.Child() _table_button: Gtk.Button = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self._breakpoint.connect("apply", lambda _o: self.__apply_breakpoint()) self._breakpoint.connect("unapply", lambda _o: self.__unapply_breakpoint()) self.__formatter = Formatter() self.__link_dialog: LinkDialog | None = None self.__table_dialog: TableDialog | None = None self.__active = False def setup(self, sourceview: GtkSource.View) -> None: """Later startup initialisation. :param GtkSource.View sourceview: Sourceview """ self.__setup_actions() self.__sourceview = sourceview def prepare(self) -> None: """Initialise state entering editor.""" self.__formatter.buffer = self.__sourceview.get_buffer() def callback(): if self.get_width() == 0: GLib.idle_add(callback) return if self.get_width() < 500: self.__make_shorter() else: self.__make_taller() GLib.idle_add(callback) def focus(self) -> None: """Grab focus.""" self._heading_menu.grab_focus() @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @active.setter def set_active(self, value: bool) -> None: self.__active = value self.__enable_actions(value) def __on_table_create(self, _obj: TableDialog, width: int, height: int) -> None: view_width = self.__sourceview.get_width() if self.__sourceview.line_length > 0: view_width = min(view_width, self.__sourceview.line_length) if self.__get_text_direction() == Gtk.TextDirection.RTL: pango_context = self.__sourceview.get_rtl_context() else: pango_context = self.__sourceview.get_ltr_context() metrics = pango_context.get_metrics() character_width = metrics.get_approximate_char_width() self.__formatter.table(width, height, view_width, Pango.units_to_double(character_width)) # Can't directly call grab_focus from idle_add otherwise its returning of True will retain, # and repeat, the event def focus_sourceview(): self.__sourceview.grab_focus() GLib.idle_add(focus_sourceview) def __on_link_apply(self, _obj: LinkDialog, info: LinkStateInfo) -> None: self.__formatter.link(info) self.__sourceview.grab_focus() def __setup_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() def wrap(func: Callable, param: Optional[int] = None) -> None: args = (param,) if param is not None else () func(*args) self.__sourceview.grab_focus() action = Gio.SimpleAction.new("bold") action.connect("activate", lambda _a, _p: wrap(self.__formatter.bold)) action_group.add_action(action) app.set_accels_for_action("format.bold", ["b"]) action = Gio.SimpleAction.new("italic") action.connect("activate", lambda _a, _p: wrap(self.__formatter.italic)) action_group.add_action(action) app.set_accels_for_action("format.italic", ["i"]) action = Gio.SimpleAction.new("strikethrough") action.connect("activate", lambda _a, _p: wrap(self.__formatter.strikethrough)) action_group.add_action(action) app.set_accels_for_action("format.strikethrough", ["x"]) action = Gio.SimpleAction.new("quote") action.connect("activate", lambda _a, _p: wrap(self.__formatter.quote)) action_group.add_action(action) app.set_accels_for_action("format.quote", ["q"]) action = Gio.SimpleAction.new("heading-1") action.connect("activate", lambda _a, _p: wrap(self.__formatter.heading, 1)) action_group.add_action(action) app.set_accels_for_action("format.heading-1", ["1"]) action = Gio.SimpleAction.new("heading-2") action.connect("activate", lambda _a, _p: wrap(self.__formatter.heading, 2)) action_group.add_action(action) app.set_accels_for_action("format.heading-2", ["2"]) action = Gio.SimpleAction.new("heading-3") action.connect("activate", lambda _a, _p: wrap(self.__formatter.heading, 3)) action_group.add_action(action) app.set_accels_for_action("format.heading-3", ["3"]) action = Gio.SimpleAction.new("heading-4") action.connect("activate", lambda _a, _p: wrap(self.__formatter.heading, 4)) action_group.add_action(action) app.set_accels_for_action("format.heading-4", ["4"]) action = Gio.SimpleAction.new("heading-5") action.connect("activate", lambda _a, _p: wrap(self.__formatter.heading, 5)) action_group.add_action(action) app.set_accels_for_action("format.heading-5", ["5"]) action = Gio.SimpleAction.new("heading-6") action.connect("activate", lambda _a, _p: wrap(self.__formatter.heading, 6)) action_group.add_action(action) app.set_accels_for_action("format.heading-6", ["6"]) action = Gio.SimpleAction.new("heading-remove") action.connect("activate", lambda _a, _p: wrap(self.__formatter.heading, 0)) action_group.add_action(action) app.set_accels_for_action("format.heading-remove", ["7"]) action = Gio.SimpleAction.new("unordered-list") action.connect("activate", lambda _a, _p: wrap(self.__formatter.unordered_list)) action_group.add_action(action) app.set_accels_for_action("format.unordered-list", ["u"]) action = Gio.SimpleAction.new("ordered-list") action.connect("activate", lambda _a, _p: wrap(self.__formatter.ordered_list)) action_group.add_action(action) app.set_accels_for_action("format.ordered-list", ["o"]) action = Gio.SimpleAction.new("checkbox") action.connect("activate", lambda _a, _p: wrap(self.__formatter.checkbox)) action_group.add_action(action) app.set_accels_for_action("format.checkbox", ["c"]) action = Gio.SimpleAction.new("toggle-checkbox") action.connect("activate", lambda _a, _p: self.__formatter.toggle_checkbox()) action_group.add_action(action) app.set_accels_for_action("format.toggle-checkbox", ["t"]) action = Gio.SimpleAction.new("link") action.connect("activate", lambda _a, _p: self.__link()) action_group.add_action(action) app.set_accels_for_action("format.link", ["k"]) action = Gio.SimpleAction.new("code") action.connect("activate", lambda _a, _p: wrap(self.__formatter.code)) action_group.add_action(action) app.set_accels_for_action("format.code", ["c"]) action = Gio.SimpleAction.new("horizontal-rule") action.connect("activate", lambda _a, _p: wrap(self.__formatter.horizontal_rule)) action_group.add_action(action) app.set_accels_for_action("format.horizontal-rule", ["r"]) action = Gio.SimpleAction.new("table") action.connect("activate", lambda _a, _p: self.__table()) action_group.add_action(action) app.set_accels_for_action("format.table", ["t"]) app.get_active_window().insert_action_group("format", action_group) self.__action_group = action_group def __enable_actions(self, enabled: bool) -> None: actions = self.__action_group.list_actions() for action in actions: self.__action_group.lookup_action(action).set_enabled(enabled) def __apply_breakpoint(self) -> None: self.__make_shorter() self.emit("height-change") def __make_shorter(self) -> None: self._extend_box.set_visible(False) self._menu_button.set_visible(True) self._base_box.set_spacing(4) self._parent_box.set_spacing(4) self._header_bar.add_css_class("formatting-small") self.set_property("height-request", 24) def __unapply_breakpoint(self) -> None: self.__make_taller() self.emit("height-change") def __make_taller(self) -> None: self._extend_box.set_visible(True) self._menu_button.set_visible(False) self._base_box.set_spacing(6) self._parent_box.set_spacing(6) self._header_bar.remove_css_class("formatting-small") self.set_property("height-request", 47) def __link(self) -> None: """Show link dialog.""" info = self.__formatter.get_link_state() if not self.__link_dialog: self.__link_dialog = LinkDialog() self.__link_dialog.connect("apply", self.__on_link_apply) self.__link_dialog.show(info, self.get_root()) def __table(self) -> None: """Show table dialog.""" if not self.__table_dialog: self.__table_dialog = TableDialog() self.__table_dialog.connect("create", self.__on_table_create) self.__table_dialog.show(self.get_root()) def __get_text_direction(self) -> Gtk.TextDirection: widget_direction = self.__sourceview.get_direction() if widget_direction: direction = widget_direction else: direction = Gtk.Widget.get_default_direction() return direction iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/html_generator.py000066400000000000000000000034771507102636600251200ustar00rootroot00000000000000from abc import ABC, abstractmethod from typing import Callable, Optional from markdown_it.token import Token from markdown_it.utils import EnvType, OptionsDict from iotas.note import Note class HtmlGenerator(ABC): """HTML generator base.""" RESOURCE_CSS_PATH = "/media/css/web/markdown.css" RESOURCE_KATEX_CSS_PATH = "/media/css/web/katex.min.css" RESOURCE_KATEX_JS_PATH = "/media/js/katex.min.js" @abstractmethod def generate( self, note: Note, tokens: list[Token], render_func: Callable[[list[Token], OptionsDict, EnvType], str], parser_options: OptionsDict, searching: bool, export_format: Optional[str], scroll_position: Optional[float] = None, ) -> str: """Generator HTML for note. :param Note note: Note to render :param list[Token] tokens: Parser tokens :param Callable[[list[Token], OptionsDict, EnvType], str] render_func: Render function :param OptionsDict parser_options: Parser options :param bool searching: Whether search CSS should be included :param Optional[str] export_format: Export format, if using :param Optional[float] scroll_position: Position to scroll to :return: Generated HTML :rtype: str """ raise NotImplementedError() @abstractmethod def generate_user_stylesheet(self, searching: bool) -> str: """Generate part of stylesheet based on state (configuration etc). :param bool searching: Whether searching :return: stylesheet :rtype: str """ raise NotImplementedError() @abstractmethod def update_font_family(self, family: str) -> None: """Update the font family. :param str family: New font family """ raise NotImplementedError() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/html_generator_configuration.py000066400000000000000000000040351507102636600300360ustar00rootroot00000000000000from abc import ABC, abstractmethod class HtmlGeneratorConfiguration(ABC): """HTML generator configuration interface.""" @property @abstractmethod def markdown_tex_support(self) -> bool: """Get whether markdown TeX rendering is supported. :return: Markdown TeX supported :rtype: bool """ raise NotImplementedError() @property @abstractmethod def line_length(self) -> int: """Get line length. :return: Size in pixels :rtype: int """ raise NotImplementedError() @property @abstractmethod def markdown_use_monospace_font(self) -> bool: """Get whether to use a monospace font for the markdown render. :return: Using monospace font :rtype: bool """ raise NotImplementedError() @property @abstractmethod def use_monospace_font(self) -> bool: """Get whether to use a monospace font. :return: Using monospace font :rtype: bool """ raise NotImplementedError() @property @abstractmethod def font_size(self) -> int: """Get font size. :return: Size :rtype: int """ raise NotImplementedError() @property @abstractmethod def high_contrast(self) -> bool: """Get whether high contrast output should be used for screen rendering. :return: Whether visible :rtype: bool """ raise NotImplementedError() @property @abstractmethod def markdown_render_monospace_font_ratio(self) -> float: """Get the adjustment in size from proportional to fixed width font. :return: Ratio :rtype: float """ raise NotImplementedError() @property @abstractmethod def editor_header_bar_visible_for_window_state(self) -> bool: """Get whether the header bar is configured visible for the window maximised state." :return: Whether visible :rtype: bool """ raise NotImplementedError() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/index.py000066400000000000000000001211421507102636600232030ustar00rootroot00000000000000from gettext import gettext as _ from gettext import ngettext from gi.repository import Adw, Gdk, GObject, Gio, GLib, Gtk import logging from typing import Optional from iotas.category import Category, CategorySpecialPurpose from iotas.category_manager import CategoryManager from iotas.config_manager import ConfigManager import iotas.const as const from iotas.first_start_page import FirstStartPage from iotas.index_menu_button import IndexMenuButton from iotas.index_note_list import IndexNoteList from iotas.index_search_header_bar import IndexSearchHeaderBar, IndexSearchState from iotas.note import Note from iotas.note_manager import NoteManager from iotas.selection_header_bar import SelectionHeaderBar from iotas.sidebar import Sidebar from iotas.sync_manager import SyncManager from iotas.theme_selector import ThemeSelector @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/index.ui") class Index(Adw.BreakpointBin): __gtype_name__ = "Index" __gsignals__ = { # Parameters are the note and whether to open immediately (disabling animation) "note-opened": (GObject.SignalFlags.RUN_FIRST, None, (Note, bool)), "reauthenticate": (GObject.SignalFlags.RUN_FIRST, None, ()), } UNDO_NOTE_DELETION_DURATION = 5.0 BUMPED_OUT_OF_EDITOR_NOTIFICATION_DURATION = 5.0 SYNC_UPDATE_NOTIFICATION_DURATION = 2.0 NOTES_APP_MISSING_NOTIFICATION_DURATION = 8.0 BREAKPOINT_WIDTH = 700 _overlay_view: Adw.OverlaySplitView = Gtk.Template.Child() _breakpoint: Adw.Breakpoint = Gtk.Template.Child() _stack: Gtk.Stack = Gtk.Template.Child() _sidebar: Sidebar = Gtk.Template.Child() _note_list_scroll: Gtk.ScrolledWindow = Gtk.Template.Child() _note_list: IndexNoteList = Gtk.Template.Child() _first_start: FirstStartPage = Gtk.Template.Child() _loading: Adw.StatusPage = Gtk.Template.Child() _empty: Adw.StatusPage = Gtk.Template.Child() _search_info: Adw.StatusPage = Gtk.Template.Child() _search_empty: Adw.StatusPage = Gtk.Template.Child() _header_stack: Gtk.Stack = Gtk.Template.Child() _main_header_bar: Adw.HeaderBar = Gtk.Template.Child() _content_sidebar_button: Gtk.Button = Gtk.Template.Child() _search_header_bar: IndexSearchHeaderBar = Gtk.Template.Child() _selection_header_bar: SelectionHeaderBar = Gtk.Template.Child() _title: Gtk.Label = Gtk.Template.Child() _toast_overlay: Adw.ToastOverlay = Gtk.Template.Child() _menu_button: IndexMenuButton = Gtk.Template.Child() _new_button: Gtk.Button = Gtk.Template.Child() _misc_banner: Adw.Banner = Gtk.Template.Child() _offline_banner: Adw.Banner = Gtk.Template.Child() _app_id_change_reauthenticate_banner: Adw.Banner = Gtk.Template.Child() _generic_reauthenticate_banner: Adw.Banner = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__note_manager: NoteManager self.__category_manager: CategoryManager self.__sync_manager: SyncManager self.__config_manager = ConfigManager.get_default() self.__active = False self.__initialised = False self.__import_syncing = False self.__search_after_init: Optional[str] = None self.__searching_before_selection = False self.__add_fav_action: Gio.SimpleAction self.__remove_fav_action: Gio.SimpleAction self.__cancel_action: Gio.SimpleAction self.__syncing_toast: Optional[Adw.Toast] = None self.__search_model = None # Startup bootstrap category self.__category = Category("", 0) self.__category.special_purpose = CategorySpecialPurpose.ALL self._title.set_label(Category.ALL_TITLE) self._note_list.connect("note-opened", self.__on_note_opened) self._note_list.connect("note-checkbox-activated", self.__on_note_checkbox_activated) self._note_list.connect( "note-checkbox-deactivated", lambda _o, note: self._selection_header_bar.set_note_selected(note, False), ) self._selection_header_bar.connect("categories-changed", self.__on_notes_categories_changed) self._selection_header_bar.connect("delete", self.__on_notes_deleted) self._selection_header_bar.connect("set-favourite", self.__on_notes_set_favourite) self._selection_header_bar.connect("clear-favourite", self.__on_notes_clear_favourite) self._selection_header_bar.connect("abort", lambda _o: self.__cancel_selection()) self._menu_button.get_popover().add_child(ThemeSelector(), "theme") self.connect("realize", self.__on_realize) controller = Gtk.EventControllerKey() controller.connect("key-pressed", self.__on_index_key_pressed) self.add_controller(controller) self._search_header_bar.connect( "changed", lambda _o: self.__apply_search(invalidate_scroll_and_expansion=True) ) self.__config_manager.connect_changed( ConfigManager.INDEX_CATEGORY_STYLE, lambda: self._note_list.update_category_labels(self.__category), ) self.__config_manager.connect_changed( ConfigManager.PERSIST_SIDEBAR, self.__update_for_sidebar_pin_change, ) self._breakpoint.connect("apply", self.__on_breakpoint_apply) self._breakpoint.connect("unapply", self.__on_breakpoint_unapply) self._overlay_view.connect( "notify::show-sidebar", lambda _o, _v: self.__update_header_buttons_for_state() ) def setup( self, note_manager: NoteManager, category_manager: CategoryManager, sync_manager: SyncManager, ) -> None: """Perform initial setup. :param NoteManager note_manager: Note manager :param CategoryManager category_manager: Category manager :param SyncManager sync_manager: Remote sync manager """ self.__sync_manager = sync_manager self.__note_manager = note_manager self.__note_manager.connect( "initial-load-complete", lambda _o: self.__on_initial_load_from_db_complete() ) self.__note_manager.connect("new-note-persisted", self.__on_new_note_persisted) self.__category_manager = category_manager self.__setup_actions() self.__sync_manager.set_managers(self.__note_manager, self.__category_manager) self._sidebar.setup( self.__sync_manager, self.__category_manager, self.__on_category_activated, ) self._search_header_bar.setup(self._note_list, self.__note_manager) self._selection_header_bar.setup(self.__category_manager.tree_store) self._note_list.setup(self.__note_manager, self.__on_listbox_key_pressed) self._selection_header_bar.bind_property( "active", self._note_list, "selecting", GObject.BindingFlags.SYNC_CREATE ) self._search_header_bar.bind_property( "active", self._note_list, "searching", GObject.BindingFlags.SYNC_CREATE ) if self.__config_manager.first_start: self._stack.set_visible_child(self._first_start) self._first_start.initialise_device() else: self._stack.set_visible_child(self._loading) self.__sync_manager.connect("ready", self.__on_sync_ready) self.__sync_manager.connect("started", self.__on_sync_started) self.__sync_manager.connect("finished", self.__on_sync_finished) self.__sync_manager.connect("missing-password", self.__on_missing_password) self.__sync_manager.connect( "notes-capability-missing", self.__on_missing_server_notes_capability ) self.__sync_manager.init_auth() self.__sync_manager.bind_property( "offline", self._offline_banner, "revealed", GObject.BindingFlags.SYNC_CREATE ) def update_for_note_deletions(self, notes: list[Note]) -> None: """Perform updates for deleted notes. :param list[Note] notes: The deleted notes """ if len(notes) > 1: # Translators: Description, notification, {} is a positive number msg = _("{} notes deleted").format(len(notes)) else: # Translators: Description, notification msg = _("Note deleted") toast = Adw.Toast.new(msg) toast.set_timeout(self.UNDO_NOTE_DELETION_DURATION) # Translators: Button toast.set_button_label(_("Undo")) toast.connect("button-clicked", lambda _o: self.__undo_deletion()) toast.connect("dismissed", lambda _o: self.__note_manager.on_deletion_undo_elapsed()) self._toast_overlay.add_toast(toast) if self.__searching(): self.__apply_search() else: self.__invalidate_view(check_older_notes=False) self.__handle_emptied_category() def update_for_dialog_visibility(self, visible: bool) -> None: """Update if dialogs visible, disabling actions. :param bool visible: Whether a dialog is visible """ if self.active: self.__cancel_action.set_enabled(not visible) def update_layout_for_initial_size(self, width: int, height: int) -> None: """Update layout for initial window size. :param int width: Window width :param int height: Window height """ self.__update_for_sidebar_pin_change(width) self._note_list.update_search_pagesize_for_height(height) def update_search_pagesize_for_height(self, height: int) -> None: """Recalculate number of results to show on first search page. :param int height: The new window height """ self._note_list.update_search_pagesize_for_height(height) def show_note_conflict_alert(self) -> None: """Let the user know a sync conflict has occurred with the note being edited.""" # Translators: Description, notification toast = Adw.Toast.new(_("Sync conflict with note being edited")) toast.set_timeout(self.BUMPED_OUT_OF_EDITOR_NOTIFICATION_DURATION) self._toast_overlay.add_toast(toast) def show_editing_note_deleted_alert(self) -> None: """Let the user know the note being edited was remotely deleted.""" # Translators: Description, notification toast = Adw.Toast.new(_("The note being edited was remotely deleted")) toast.set_timeout(self.BUMPED_OUT_OF_EDITOR_NOTIFICATION_DURATION) self._toast_overlay.add_toast(toast) def show_secret_service_failure_alert(self) -> None: text = _( # Translators: Description, notification. "Secret Service" and "gnome-keyring" should # likely not be translated. "Failure accessing Secret Service. Ensure you have a provider like gnome-keyring which " "has a default keyring setup that is unlocked." ) self._misc_banner.set_title(text) self._misc_banner.set_revealed(True) def refresh_after_note_closed(self, note: Note) -> None: """Refresh index after note has been closed. :param Note note: The closed note """ if self.__searching(): self.__apply_search() else: self.__invalidate_view(check_older_notes=False) if not self.__handle_emptied_category(note): self._note_list.update_category_labels(self.__category) if self.get_root().using_keyboard_navigation: if not note.locally_deleted: self._note_list.refocus_selected_row() else: self._note_list.clear_selections() def search_from_cli(self, search_term: str) -> None: """Initiate a search, from the CLI. :param str search_term: The search term """ if self.__initialised: self.__start_search_from_cli(search_term) else: self.__search_after_init = search_term @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @active.setter def set_active(self, value: bool) -> None: self.__active = value self.__enable_actions(value) @Gtk.Template.Callback() def _on_reauthenticate(self, _button: Gtk.Button) -> None: self.emit("reauthenticate") @Gtk.Template.Callback() def _on_misc_banner_button(self, _button: Gtk.Button) -> None: if self._misc_banner.get_revealed(): self._misc_banner.set_revealed(False) @Gtk.Template.Callback() def _on_edge_overshot(self, _obj: Gtk.ScrolledWindow, pos: Gtk.PositionType) -> None: if pos == Gtk.PositionType.BOTTOM: if self.__searching(): if self._note_list.have_more_search_results: self._note_list.show_remaining_search_results() else: if not self._note_list.older_notes_displayed: self.__load_older_notes() def __setup_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() action = Gio.SimpleAction.new("toggle-sidebar") action.connect("activate", lambda _a, _p: self.__toggle_sidebar()) action_group.add_action(action) app.set_accels_for_action("index.toggle-sidebar", ["F9"]) action = Gio.SimpleAction.new("category-context-dependent") action.connect("activate", lambda _a, _p: self.__on_category_shortcut()) action_group.add_action(action) app.set_accels_for_action("index.category-context-dependent", ["e"]) action = Gio.SimpleAction.new("create-note") action.connect("activate", lambda _o, _v: self.__create_and_open_note()) action_group.add_action(action) app.set_accels_for_action("index.create-note", ["n"]) action = Gio.SimpleAction.new("create-note-with-content", GLib.VariantType("s")) action.connect("activate", self.__on_create_note_with_content) action_group.add_action(action) action = Gio.SimpleAction.new("delete-from-index") action.connect("activate", lambda _a, _p: self.__delete_note_from_keyboard()) action_group.add_action(action) app.set_accels_for_action("index.delete-from-index", ["Delete"]) action = Gio.SimpleAction.new("load-older-notes") action.connect("activate", lambda _a, _p: self.__load_older_notes()) action_group.add_action(action) action = Gio.SimpleAction.new("show-more") action.connect("activate", lambda _a, _p: self._note_list.show_remaining_search_results()) action_group.add_action(action) action = Gio.SimpleAction.new("enter-search") action.connect("activate", lambda _a, _p: self.__enter_search(clear_text=True)) action_group.add_action(action) app.set_accels_for_action("index.enter-search", ["f"]) action = Gio.SimpleAction.new("select-notes") action.connect("activate", lambda _a, _p: self.__start_selection()) action_group.add_action(action) app.set_accels_for_action("index.select-notes", ["s"]) action = Gio.SimpleAction.new("cancel") action.connect("activate", lambda _a, _p: self.__cancel_out_of_context(False)) action_group.add_action(action) self.__cancel_action = action app.set_accels_for_action("index.cancel", ["Escape", "Left"]) action = Gio.SimpleAction.new("reset-filters") action.connect("activate", lambda _a, _p: self.__cancel_out_of_context(True)) action_group.add_action(action) app.set_accels_for_action( "index.reset-filters", ["BackSpace", "Delete"] ) action = Gio.SimpleAction.new("selection-toggle-favourite") action.connect("activate", lambda _a, _p: self.__on_toggle_favourite()) action_group.add_action(action) app.set_accels_for_action("index.selection-toggle-favourite", ["g"]) action = Gio.SimpleAction.new("show-menu") action.connect("activate", lambda _a, _p: self._menu_button.popup()) action_group.add_action(action) app.set_accels_for_action("index.show-menu", ["F10"]) self.__action_group = action_group app.get_active_window().insert_action_group("index", action_group) def __enable_actions(self, enabled: bool) -> None: """Toggle whether index actions are enabled. :param bool enabled: New value """ actions = self.__action_group.list_actions() for action in actions: self.__action_group.lookup_action(action).set_enabled(enabled) def __on_realize(self, _widget: Gtk.Widget) -> None: # Preset filters to avoid momentarily populating all at startup self.__note_manager.update_filters( self.__category, self._note_list.older_notes_displayed, check_older_notes=False ) self.__note_manager.initiate_model_from_db() self.__category_manager.populate() def __on_create_note_with_content( self, _obj: GObject.Object, param: GObject.ParamSpec, ) -> None: """Create a new note with content and edit it.""" self.__create_and_open_note(param.get_string()) def __on_notes_categories_changed(self, _obj: SelectionHeaderBar) -> None: changeset = self._selection_header_bar.get_categories_changeset() self.__cancel_selection() for note, old_category in changeset: self.__note_manager.persist_note_category(note, old_category) if self.__searching(): self.__apply_search() else: self.__invalidate_view(check_older_notes=False) self.__handle_emptied_category() def __on_notes_clear_favourite(self, _obj: SelectionHeaderBar) -> None: notes = self._selection_header_bar.get_selected() self.__update_favourites(notes, False) self.__cancel_selection() def __on_notes_set_favourite(self, _obj: SelectionHeaderBar) -> None: notes = self._selection_header_bar.get_selected() self.__update_favourites(notes, True) self.__cancel_selection() def __on_notes_deleted(self, _obj: SelectionHeaderBar) -> None: notes = self._selection_header_bar.get_selected() self.__delete_notes(notes) self.__cancel_selection() def __on_note_opened(self, _obj: GObject.Object, note: Note) -> None: self.emit("note-opened", note, False) def __on_note_checkbox_activated(self, _obj: GObject.Object, note: Note) -> None: if not self.__selecting(): self.__start_selection() self._selection_header_bar.set_note_selected(note, True) def __on_category_activated(self, category: Category, close_sidebar: bool = True) -> None: self.__category = category self._note_list.disconnect_older_notes_section() # Handle clicking on category while searching or selecting with a persistent sidebar if self.__searching(): self.__end_search() # return as __end_search itself calls __on_category_activated return elif self.__selecting(): self.__searching_before_selection = False self.__cancel_selection() self._title.set_label(category.display_name) self._note_list_scroll.get_vadjustment().set_value(0) self.__invalidate_view(check_older_notes=True) self._note_list.refresh_section_visibility(self.__category) self._note_list.update_category_labels(self.__category) if close_sidebar: self.__close_sidebar() if self.get_root().using_keyboard_navigation: self._note_list.move_focus_to_list_top() def __on_sync_ready(self, _obj: GObject.Object, new_setup: bool) -> None: if new_setup: self.__import_syncing = True if self.__searching(): self.__end_search() if self._app_id_change_reauthenticate_banner.get_revealed(): self._app_id_change_reauthenticate_banner.set_revealed(False) if self._generic_reauthenticate_banner.get_revealed(): self._generic_reauthenticate_banner.set_revealed(False) def __on_sync_started(self, _obj: GObject.Object) -> None: if self.active and self.__config_manager.show_syncing_debug_notification: # Another toast misuse replacing a revealer notification. Debug only at least. # TODO in future look at replacing this with a (debug only) spinner. # Translators: Description, notification self.__syncing_toast = Adw.Toast.new(_("Syncing")) # A cludge, only passable for this debug functionality. self.__syncing_toast.set_timeout(60.0) self._toast_overlay.add_toast(self.__syncing_toast) def __on_sync_finished(self, _obj: SyncManager, changes: int) -> None: if self.active: if self.__syncing_toast: self.__syncing_toast.dismiss() self.__syncing_toast = None if self.__import_syncing: self.__on_category_activated(self.__category, close_sidebar=True) self.__import_syncing = False elif changes > 0: self.__invalidate_view(check_older_notes=False) self._note_list.update_category_labels(self.__category) # Translators: Description, notification, {} is a number msg = ngettext("{} change", "{} changes", changes).format(changes) toast = Adw.Toast.new(msg) toast.set_timeout(self.SYNC_UPDATE_NOTIFICATION_DURATION) self._toast_overlay.add_toast(toast) def __on_missing_password(self, _obj: GObject.Object) -> None: app = Gio.Application.get_default() previous_version = app.previous_version if self.__sync_manager.configured_but_no_password: if previous_version != "" and previous_version < const.APP_ID_CHANGE_VERSION: self._app_id_change_reauthenticate_banner.set_revealed(True) else: self._generic_reauthenticate_banner.set_revealed(True) def __on_missing_server_notes_capability(self, _obj: GObject.Object) -> None: # Translators: Description, notification msg = _("Sync failure. Is the Nextcloud Notes app installed on the server?") toast = Adw.Toast.new(msg) toast.set_timeout(self.NOTES_APP_MISSING_NOTIFICATION_DURATION) self._toast_overlay.add_toast(toast) def __on_index_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> bool: if keyval in (Gdk.KEY_Down, Gdk.KEY_KP_Down): if self._overlay_view.get_pin_sidebar(): self._note_list.move_focus_to_list_top() else: if self._overlay_view.get_show_sidebar(): # If we have an auto-expanded sidebar use the shortcut to send the focus self.get_root().using_keyboard_navigation = True self._sidebar.take_focus() else: self._note_list.move_focus_to_list_top() return Gdk.EVENT_STOP elif keyval in (Gdk.KEY_Up, Gdk.KEY_KP_Up): self._note_list.move_focus_to_list_top() return Gdk.EVENT_STOP elif not self.__searching() and not self.__selecting(): if self._search_header_bar.check_if_starting(controller, keyval, state): self.__enter_search(clear_text=False) return Gdk.EVENT_STOP elif self.__searching() and not self.__selecting(): if self._search_header_bar.check_if_starting(controller, keyval, state, clear=False): self._search_header_bar.focus_entry() return Gdk.EVENT_STOP elif self._search_header_bar.check_for_open_first_result_shortcut( controller, keyval, state ): # Check that we have some results, a little indirect if self._stack.get_visible_child() == self._note_list_scroll: self._note_list.open_first_search_result() return Gdk.EVENT_STOP return Gdk.EVENT_PROPAGATE def __on_listbox_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> bool: if keyval in (Gdk.KEY_Down, Gdk.KEY_KP_Down): self._note_list.focus_next_list_row(self.__get_focused()) return Gdk.EVENT_STOP elif keyval in (Gdk.KEY_Up, Gdk.KEY_KP_Up): self._note_list.focus_previous_list_row(self.__get_focused()) return Gdk.EVENT_STOP elif not self.__searching() and not self.__selecting(): if self._search_header_bar.check_if_starting(controller, keyval, state): self.__enter_search(clear_text=False) return Gdk.EVENT_STOP elif self.__searching() and not self.__selecting(): if self._search_header_bar.check_if_starting(controller, keyval, state, clear=False): self._search_header_bar.focus_entry() return Gdk.EVENT_STOP return Gdk.EVENT_PROPAGATE def __on_toggle_favourite(self) -> None: if self.__selecting(): self._selection_header_bar.toggle_favourite_on_selection() def __on_category_shortcut(self) -> None: if self.__selecting(): self._selection_header_bar.edit_category_for_selection() else: self.__toggle_sidebar() def __on_breakpoint_apply(self, _bp: Adw.Breakpoint) -> None: if self._overlay_view.get_pin_sidebar(): self._overlay_view.set_pin_sidebar(False) self._overlay_view.set_collapsed(True) self._overlay_view.set_show_sidebar(False) self.__update_header_buttons_for_state() def __on_breakpoint_unapply(self, _bp: Adw.Breakpoint) -> None: if self.__config_manager.pin_sidebar: self._overlay_view.set_pin_sidebar(True) self._overlay_view.set_collapsed(False) self._overlay_view.set_show_sidebar(True) self.__update_header_buttons_for_state() def __load_older_notes(self) -> None: # Somewhat clunky misuse of toast to replace previous revealer notification # Translators: Description, notification toast = Adw.Toast.new(_("Loading")) toast.set_timeout(20.0) self._toast_overlay.add_toast(toast) def load(toast: Adw.Toast) -> None: if self.__note_manager.older_notes_model is None: self.__load_older_notes_worker() else: self._note_list.populate_older_notes(self.__note_manager.older_notes_model) self.__invalidate_view(check_older_notes=False) self._note_list.update_category_labels(self.__category) toast.dismiss() GLib.idle_add(load, toast) def __create_and_open_note(self, content: Optional[str] = None) -> None: note = self.__note_manager.create_note(self.__category) # If we're creating a note from a selection persist it straight away if content is not None and content != "": note.content = content note.update_title_from_top_line() self.__note_manager.persist_note_while_editing(note, update_excerpt=True) self.emit("note-opened", note, False) def __delete_note_from_keyboard(self) -> None: if self.__selecting(): self._selection_header_bar.handle_delete_keyboard_shortcut() else: note = None window = self.get_root() focused = window.get_focus() if isinstance(focused, Gtk.ListBoxRow): note = focused.get_first_child().note if note: self.__delete_notes([note]) def __invalidate_view(self, check_older_notes: bool) -> None: """Refresh the view.""" # Update display of empty state, list, etc if self.__searching(): self.__apply_search() else: self.__note_manager.invalidate_sort() older_loaded = self.__note_manager.update_filters( self.__category, self._note_list.older_notes_displayed, check_older_notes ) if older_loaded: self._note_list.populate_older_notes(self.__note_manager.older_notes_model) count = self.__note_manager.get_filtered_note_count( self._note_list.older_notes_displayed ) if not self.__config_manager.first_start: if count == 0: self._stack.set_visible_child(self._empty) elif self._stack.get_visible_child() in ( self._empty, self._first_start, self._loading, ): self._stack.set_visible_child(self._note_list_scroll) def __start_search_from_cli(self, search_term: str) -> None: self._search_header_bar.text = search_term self.__enter_search(clear_text=False, avoid_select_all=True) def __enter_search(self, clear_text, avoid_select_all: bool = False) -> None: """Enter the search UI.""" if self.__searching(): # Grab focus and select entry text self._note_list.clear_selections() self._search_header_bar.enter(False, not avoid_select_all) return self.__close_sidebar() self._search_header_bar.enter(clear_text, False) all_category = self._sidebar.select_and_fetch_category(None, CategorySpecialPurpose.ALL) assert all_category self.__category = all_category self.__set_search_visible(True) if self.__note_manager.search_model is None: GLib.idle_add(self.__init_search_model) def __init_search_model(self) -> None: model = self.__note_manager.initiate_search_model() self._note_list.populate_search(model) def __apply_search(self, invalidate_scroll_and_expansion: bool = False) -> None: if not self.__searching(): return # If trying to search without caching completed delay the search if self.__note_manager.search_model is None: GLib.timeout_add(500, self.__apply_search, invalidate_scroll_and_expansion) logging.debug("Delaying search due to model not ready") return show_all = ( not invalidate_scroll_and_expansion and self._note_list.showing_expanded_search_set ) result = self._search_header_bar.search(show_all) if result == IndexSearchState.RESULTS: self._stack.set_visible_child(self._note_list_scroll) if invalidate_scroll_and_expansion: self._note_list_scroll.get_vadjustment().set_value(0) elif result == IndexSearchState.EMPTY: self._stack.set_visible_child(self._search_empty) elif result == IndexSearchState.NO_TERM: self._stack.set_visible_child(self._search_info) self._note_list.restrict_for_search_by_ids(None) def __start_selection(self) -> None: self.__close_sidebar() self.__searching_before_selection = self.__searching() self._header_stack.set_visible_child(self._selection_header_bar) # Prevent focus jumping to top row of listbox and resulting scroll if not self.get_root().using_keyboard_navigation: self._content_sidebar_button.grab_focus() self._selection_header_bar.activate() self.__update_enabled_actions(False) def __cancel_selection(self) -> None: if self.__searching_before_selection: self._header_stack.set_visible_child(self._search_header_bar) else: self._header_stack.set_visible_child(self._main_header_bar) self._selection_header_bar.active = False self._note_list.clear_all_checkboxes() self.__update_enabled_actions(True) if self.get_root().using_keyboard_navigation: self._note_list.refocus_selected_row() else: self._note_list.clear_selections() # Prevent focus jumping to top row of listbox and resulting scroll self._content_sidebar_button.grab_focus() def __searching(self) -> bool: return self._search_header_bar.active def __selecting(self) -> bool: return self._selection_header_bar.active def __set_search_visible(self, visible: bool) -> None: self._note_list.refresh_section_visibility(self.__category) if visible: self._header_stack.set_visible_child(self._search_header_bar) self._stack.set_visible_child(self._search_info) else: self._header_stack.set_visible_child(self._main_header_bar) self._stack.set_visible_child(self._note_list_scroll) if self.__note_manager.search_model is not None: self._note_list.restrict_for_search_by_ids(None) def __end_search(self) -> None: self._search_header_bar.exit() note = self._note_list.get_selected_note() self._note_list_scroll.get_vadjustment().set_value(0) self.__set_search_visible(False) # Could look at removing the category updating and filter invalidating parts of this call self.__on_category_activated(self.__category, close_sidebar=True) if self.get_root().using_keyboard_navigation: if note is not None: self._note_list.select_and_focus_note(note) else: self._note_list.move_focus_to_list_top() else: # Prevent focus loss, type to search stopping to work self._content_sidebar_button.grab_focus() def __update_enabled_actions(self, enable: bool) -> None: for action_name in ("toggle-sidebar", "create-note", "enter-search", "select-notes"): action = self.__action_group.lookup(action_name) action.set_property("enabled", enable) def __load_older_notes_worker(self) -> None: model = self.__note_manager.older_notes_model if model is None: model = self.__note_manager.initiate_older_notes_model() self.__note_manager.filter_older_notes_by_date() loaded_notes = self._note_list.populate_older_notes(model) if loaded_notes: if self._stack.get_visible_child() in (self._empty, self._first_start): self._stack.set_visible_child(self._note_list_scroll) def __on_initial_load_from_db_complete(self) -> None: self.__invalidate_view(check_older_notes=True) self._note_list.refresh_section_visibility(self.__category) self._note_list.clear_selections() self.__initialised = True GLib.idle_add(self._note_list.update_category_labels, self.__category) if self.__search_after_init is not None: GLib.idle_add(self.__start_search_from_cli, self.__search_after_init) def __on_new_note_persisted(self, _obj: GObject.Object) -> None: self.__invalidate_view(check_older_notes=False) self._note_list.update_category_labels(self.__category) def __undo_deletion(self) -> None: if self.__note_manager.undo_deletion(): self.__invalidate_view(check_older_notes=False) def __get_focused(self) -> Optional[Gtk.Widget]: window = self.get_root() return window.get_focus() def __handle_emptied_category(self, note: Optional[Note] = None) -> bool: # If we're not filtered by category this won't be an issue if not self.__is_showing_category(): return False # Including "older notes" here as we always show older notes when displaying a category view_empty = self.__note_manager.get_filtered_note_count(include_older_notes=True) == 0 if view_empty: if note is not None and note.category != "": new_category = self._sidebar.select_and_fetch_category(note.category) else: new_category = self._sidebar.select_and_fetch_category( None, CategorySpecialPurpose.ALL ) # Largely form mypy if not new_category: logging.warning("Failed to find category?") return False self.__on_category_activated(new_category, close_sidebar=True) return True return False def __update_favourites(self, notes: list[Note], value: bool) -> None: """Change whether notes are in favourites. :param list[Note] notes: Notes to modify :param bool value: The new value """ if self.__note_manager.set_and_persist_favourite_for_notes(notes, value): self.__sync_manager.sync_now() if self.__searching(): self.__apply_search() else: self.__invalidate_view(check_older_notes=False) def __cancel_out_of_context(self, including_category: bool) -> None: if including_category: if ( self.__category.special_purpose is None or self.__category.special_purpose != CategorySpecialPurpose.ALL ): (category, _) = self.__category_manager.get_special_purpose_category( CategorySpecialPurpose.ALL ) # close_sidebar is False as we're closing it below self.__on_category_activated(category, close_sidebar=False) closed_the_sidebar = self.__close_sidebar() if not closed_the_sidebar: if self.__selecting(): self.__cancel_selection() elif self.__searching(): self.__end_search() def __close_sidebar(self) -> bool: if self.__config_manager.pin_sidebar and self.get_width() >= self.BREAKPOINT_WIDTH: return False elif not self._overlay_view.get_show_sidebar(): return False self._overlay_view.set_show_sidebar(False) if self.get_root().using_keyboard_navigation: self._note_list.grab_focus() self.__update_header_buttons_for_state() return True def __toggle_sidebar(self) -> None: if self.__config_manager.pin_sidebar and self.get_width() >= self.BREAKPOINT_WIDTH: # Pinned sidebar is open, let's just throw the focus around if self._sidebar.has_focus_within(): self.get_root().using_keyboard_navigation = True self._note_list.grab_focus() else: self._sidebar.take_focus() else: if self._overlay_view.get_show_sidebar(): self._overlay_view.set_show_sidebar(False) if self.get_root().using_keyboard_navigation: self._note_list.grab_focus() else: self._overlay_view.set_show_sidebar(True) self._sidebar.take_focus() def __update_for_sidebar_pin_change(self, width: int = -1) -> None: if width == -1: width = self.get_width() if width >= self.BREAKPOINT_WIDTH: pin = self.__config_manager.pin_sidebar self._overlay_view.set_pin_sidebar(pin) self._overlay_view.set_show_sidebar(pin) self._overlay_view.set_collapsed(not pin) else: self._overlay_view.set_pin_sidebar(False) self._overlay_view.set_show_sidebar(False) self._overlay_view.set_collapsed(True) self.__update_header_buttons_for_state(width) def __update_header_buttons_for_state(self, width: int = -1) -> None: if width == -1: width = self.get_width() # Used during initialisation if width == 0: width = self.get_property("width-request") if width >= self.BREAKPOINT_WIDTH and self.__config_manager.pin_sidebar: show_sidebar_close = False show_content_sidebar_button = False show_sidebar_menu = True else: show_sidebar_close = True show_content_sidebar_button = True show_sidebar_menu = False self._content_sidebar_button.set_visible(show_content_sidebar_button) self._sidebar.show_buttons(show_sidebar_close, show_sidebar_menu) self._menu_button.set_visible(not show_sidebar_menu) def __perform_initial_sync(self) -> None: self.__initial_sync_delay_complete = True self.__sync_manager.sync_now() def __delete_notes(self, notes: list[Note]) -> None: """Delete the specified notes, flushing any undo-pending notes first. :param list[Note] notes: Notes to delete """ self.__sync_manager.flush_pending_deletions() self.__note_manager.delete_notes(notes, provide_undo=True) self.update_for_note_deletions(notes) def __is_showing_category(self) -> bool: return self.__category.special_purpose is None iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/index_menu_button.py000066400000000000000000000002741507102636600256240ustar00rootroot00000000000000from gi.repository import Gtk @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/index_menu_button.ui") class IndexMenuButton(Gtk.MenuButton): __gtype_name__ = "IndexMenuButton" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/index_note_list.py000066400000000000000000000473471507102636600253010ustar00rootroot00000000000000from gi.repository import GObject, Gio, Gtk from typing import Any, Callable, Generator, NamedTuple, Optional from iotas.category import Category from iotas.config_manager import ConfigManager from iotas.index_row import IndexRow from iotas.note import Note from iotas.note_list_model import NoteListModelTimeFiltered, NoteListModelSearch from iotas.note_manager import NoteManager class SectionInfo(NamedTuple): model: Gio.ListModel listbox: Gtk.ListBox section: Gtk.Box @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/index_note_list.ui") class IndexNoteList(Gtk.Box): __gtype_name__ = "IndexNoteList" __gsignals__ = { "note-opened": (GObject.SignalFlags.RUN_FIRST, None, (Note,)), "note-checkbox-activated": (GObject.SignalFlags.RUN_FIRST, None, (Note,)), "note-checkbox-deactivated": (GObject.SignalFlags.RUN_FIRST, None, (Note,)), "search-model-emptied": (GObject.SignalFlags.RUN_FIRST, None, ()), } MINIMUM_SEARCH_PAGE_NOTE_COUNT = 15 ROW_HEIGHT = 80 _favourites_listbox: Gtk.ListBox = Gtk.Template.Child() _favourites_section: Gtk.Box = Gtk.Template.Child() _today_listbox: Gtk.ListBox = Gtk.Template.Child() _today_section: Gtk.Box = Gtk.Template.Child() _yesterday_listbox: Gtk.ListBox = Gtk.Template.Child() _yesterday_section: Gtk.Box = Gtk.Template.Child() _week_listbox: Gtk.ListBox = Gtk.Template.Child() _week_section: Gtk.Box = Gtk.Template.Child() _month_listbox: Gtk.ListBox = Gtk.Template.Child() _month_section: Gtk.Box = Gtk.Template.Child() _last_month_listbox: Gtk.ListBox = Gtk.Template.Child() _last_month_section: Gtk.Box = Gtk.Template.Child() _older_notes_loader: Gtk.Box = Gtk.Template.Child() _older_notes_listbox: Gtk.ListBox = Gtk.Template.Child() _older_notes_section: Gtk.Box = Gtk.Template.Child() _show_more_button: Gtk.Box = Gtk.Template.Child() _search_listbox: Gtk.ListBox = Gtk.Template.Child() _search_section: Gtk.Box = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__config_manager = ConfigManager.get_default() self.__selecting = False self.__searching = False self.__search_full_set: list[int] = [] self.__older_notes_displayed = False self.__search_base_note_count = self.MINIMUM_SEARCH_PAGE_NOTE_COUNT self.__main_sections: list[SectionInfo] = [] self.__extra_listboxes: list[Gtk.Listbox] = [] def setup( self, note_manager: NoteManager, listbox_keypress_func: Callable, ) -> None: """Perform initial setup. :param NoteManager note_manager: The note manager :param Callable listbox_keypress_func: Function to call on listbox keypress """ self.__listbox_keypress_func = listbox_keypress_func self.__populate_sections_list(note_manager) self.__older_notes_model: Optional[NoteListModelTimeFiltered] = None self.__search_model: Optional[NoteListModelSearch] = None for section in self.__main_sections: section.listbox.bind_model(section.model, self.__create_row, None) section.model.connect("items-changed", self.__on_model_items_changed, section.section) self.__add_listbox_keypress_controller(section.listbox) def update_search_pagesize_for_height(self, height: int) -> None: """Recalculate number of results to show on first search "page". :param int height: The new window height """ self.__search_base_note_count = max( self.MINIMUM_SEARCH_PAGE_NOTE_COUNT, int((height / self.ROW_HEIGHT) + 5) ) def clear_selections(self) -> None: """Clear all selections in the list.""" self.__clear_selections_excluding(None) def populate_older_notes(self, model: NoteListModelTimeFiltered) -> bool: """Populate and display notes older than two months. Populates the remaining notes which haven't been shown in the index as they are beyond the two month old mark. :param NoteListModelTimeFiltered model: Model for the older notes :return: Whether the model contains any notes after population :rtype: bool """ if self.__older_notes_model is None: self.__older_notes_model = model self.__extra_listboxes.append(self._older_notes_listbox) self.__add_listbox_keypress_controller(self._older_notes_listbox) return self.__display_older_notes() def populate_search(self, model: NoteListModelSearch) -> None: """Populate search model, binding to list box etc. :param NoteListModelSearch model: Search model """ if not self.__search_model: self.__search_model = model self._search_listbox.bind_model(model, self.__create_row, None) self.__extra_listboxes.append(self._search_listbox) self.__add_listbox_keypress_controller(self._search_listbox) model.connect("items-changed", self.__on_search_items_changed) def refresh_section_visibility(self, category: Category) -> None: """Refresh visibility of list sections. :param Category category: The current category """ if self.searching: for section in self.__main_sections: section.section.set_visible(False) self._older_notes_section.set_visible(False) self._older_notes_loader.set_visible(False) self._search_section.set_visible(True) else: for section in self.__main_sections: section.section.set_visible(len(section.model) > 0) self._older_notes_section.set_visible( self.older_notes_displayed and self.__older_notes_model is not None and len(self.__older_notes_model) > 0 ) self._older_notes_loader.set_visible(not self.older_notes_displayed) self._search_section.set_visible(False) def get_selected_note(self) -> Optional[Note]: """Fetch the currently selected note. :return: The selected note, if applicable :rtype: Optional[Note] """ selected = None for listbox in self.__visible_listboxes(): row = listbox.get_selected_row() if row: selected = row.get_child().note break return selected def move_focus_to_list_top(self) -> None: """Move focus to the top of the first visible section.""" self.get_root().using_keyboard_navigation = True for listbox in self.__visible_listboxes(): row = listbox.get_row_at_index(0) if row is None: return row.grab_focus() listbox.select_row(row) break def refocus_selected_row(self) -> bool: """Refocus the selected row. :return: Whether a selected row was found :rtype: bool """ focused = False for listbox in self.__visible_listboxes(): row = listbox.get_selected_row() if row: row.grab_focus() focused = True break return focused def grab_focus(self) -> None: """Pull the focus back to the list.""" if not self.refocus_selected_row(): self.move_focus_to_list_top() def clear_all_checkboxes(self): """Clear all row checkboxes.""" for listbox in self.__all_listboxes(): child = listbox.get_first_child() while child is not None: index_row = child.get_first_child() index_row.set_checkbox_value(False) child = child.get_next_sibling() def update_category_labels(self, index_category: Category) -> None: """Update category labels for each row. :param Category index_category: The current category """ style = self.__config_manager.index_category_style for listbox in self.__visible_listboxes(): category = None if listbox == self._search_listbox else index_category child = listbox.get_first_child() while child is not None: index_row = child.get_first_child() index_row.update_category_label(category, style) child = child.get_next_sibling() def select_and_focus_note(self, note: Note) -> None: """Attempt to select and focus the provided note. :param Note note: The note """ self.clear_selections() found = False for listbox in self.__visible_listboxes(): child = listbox.get_first_child() while child is not None and not found: if child.get_first_child().note == note: listbox.select_row(child) child.grab_focus() found = True child = child.get_next_sibling() if found: break def focus_next_list_row(self, focused_row: Gtk.Widget) -> None: """Focus the next list row, moving to another section if necessary. :param Gtk.Widget focused_row: The currently focused row """ listbox = focused_row.get_parent() bottom_row = listbox.get_last_child() if focused_row == bottom_row: self.__focus_next_list_box(listbox) else: next_row = focused_row.get_next_sibling() listbox.select_row(next_row) next_row.grab_focus() def focus_previous_list_row(self, focused_row: Gtk.Widget) -> None: """Focus the previous list row, moving to another section if necessary. :param Gtk.Widget focused_row: The currently focused row """ listbox = focused_row.get_parent() top_row = listbox.get_first_child() if focused_row == top_row: self.__focus_previous_list_box(listbox) else: previous_row = focused_row.get_prev_sibling() listbox.select_row(previous_row) previous_row.grab_focus() def restrict_for_search_by_ids(self, ids: Optional[list[int]], show_all: bool = False) -> None: """Restrict by identifiers while searching. :param Optional[list[int]] ids: Identifiers :param bool show_all: Whether to show the full result set (instead of the most recent with an expandable section) """ assert self.__search_model is not None if not show_all and ids and len(ids) > self.__search_base_note_count: self.__search_full_set = ids self._show_more_button.set_visible(True) ids = ids[: self.__search_base_note_count] else: self.__search_full_set = [] self._show_more_button.set_visible(False) self.__search_model.invalidate(ids) def show_remaining_search_results(self) -> None: """Show remaining search results below first "page".""" assert self.__search_model is not None if len(self.__search_full_set) > 0: self.__search_model.invalidate(self.__search_full_set) self.__search_full_set = [] self._show_more_button.set_visible(False) def open_first_search_result(self) -> None: """Open the top search result.""" listbox = self._search_listbox if listbox.get_visible(): row = listbox.get_row_at_index(0) if row is None: return row.grab_focus() listbox.select_row(row) note = row.get_child().note self.emit("note-opened", note) def disconnect_older_notes_section(self) -> None: """Disconnect listbox and signal for notes older than two months.""" if not self.older_notes_displayed: return assert self.__older_notes_model is not None self.__older_notes_model.disconnect_by_func(self.__on_older_notes_items_changed) self._older_notes_listbox.bind_model(None, self.__create_row, None) self.older_notes_displayed = False @GObject.Property(type=bool, default=False) def older_notes_displayed(self) -> bool: return self.__older_notes_displayed @older_notes_displayed.setter def set_older_notes_displayed(self, value: bool) -> None: self.__older_notes_displayed = value @GObject.Property(type=bool, default=False) def searching(self) -> bool: return self.__searching @searching.setter def set_searching(self, value: bool) -> None: self.__searching = value @GObject.Property(type=bool, default=False) def selecting(self) -> bool: return self.__selecting @selecting.setter def set_selecting(self, value: bool) -> None: self.__selecting = value @GObject.Property(type=bool, default=False) def have_more_search_results(self) -> bool: return len(self.__search_full_set) > 0 @GObject.Property(type=bool, default=False) def showing_expanded_search_set(self) -> bool: """Whether search is active showing a set which has been expanded. As in Show More has already been pressed. :return: Whether searching and expanded :rtype: bool """ return ( self.searching and not self._show_more_button.get_visible() and self.__search_model is not None and self.__search_model.get_n_items() > self.__search_base_note_count ) def __create_row(self, note: Note, _user_data: Any) -> Gtk.Widget: row = IndexRow() style = self.__config_manager.index_category_style row.populate(note, style) row.connect("context-click", self.__on_row_context_click) row.connect("checkbox-toggled", self.__on_row_checkbox_toggled) self.bind_property("selecting", row, "child-revealed", GObject.BindingFlags.SYNC_CREATE) return row def __focus_next_list_box(self, previous_listbox: Gtk.ListBox) -> None: found = False for listbox in self.__all_listboxes(): if not found and listbox == previous_listbox: found = True continue if found and listbox.get_parent().get_visible(): row = listbox.get_row_at_index(0) row.grab_focus() listbox.select_row(row) previous_listbox.unselect_all() break def __focus_previous_list_box(self, previous_listbox: Gtk.ListBox) -> None: found = False for listbox in reversed(list(self.__all_listboxes())): if not found and listbox == previous_listbox: found = True continue if found and listbox.get_parent().get_visible(): row = listbox.get_last_child() row.grab_focus() listbox.select_row(row) previous_listbox.unselect_all() break def __on_row_activated(self, listbox: Gtk.ListBox, row: Gtk.ListBoxRow) -> None: """Open the note in the selected row in the editor. :param Gtk.ListBox listbox: Listbox for activated row :param Gtk.ListBoxRow row: The row """ note = row.get_child().note if row else None if self.selecting: row.get_child().toggle_selected() else: self.emit("note-opened", note) self.__clear_selections_excluding(listbox) def __on_row_selected(self, listbox: Gtk.ListBox, row: Optional[Gtk.ListBoxRow]) -> None: if row: self.__clear_selections_excluding(listbox) def __on_row_context_click(self, row: IndexRow) -> None: if self.selecting: row.toggle_selected() else: note = row.get_parent().get_first_child().note self.select_and_focus_note(note) row.set_checkbox_value(True) def __on_row_checkbox_toggled(self, row: IndexRow, enabled: bool) -> None: if enabled: self.emit("note-checkbox-activated", row.note) else: self.emit("note-checkbox-deactivated", row.note) def __on_model_items_changed( self, model: Gio.ListModel, _position: int, _removed: int, _added: int, section: Gtk.Widget, ) -> None: section.set_visible(not self.searching and len(model) > 0) def __on_older_notes_items_changed( self, model: Gio.ListModel, _position: int, _removed: int, _added: int ) -> None: self._older_notes_section.set_visible( not self.searching and self.older_notes_displayed and len(model) > 0 ) def __on_search_items_changed( self, model: Gio.ListModel, _position: int, _removed: int, _added: int ) -> None: if self.searching and len(model) > 0: self.emit("search-model-emptied") def __clear_selections_excluding(self, excluding: Optional[Gtk.ListBox]) -> None: for listbox in self.__all_listboxes(): if excluding is None or listbox is not excluding: listbox.unselect_all() def __add_listbox_keypress_controller(self, listbox: Gtk.ListBox) -> None: controller = Gtk.EventControllerKey() controller.connect("key-pressed", self.__listbox_keypress_func) listbox.add_controller(controller) listbox.connect("row-activated", self.__on_row_activated) listbox.connect("row-selected", self.__on_row_selected) def __bind_older_notes(self) -> None: assert self.__older_notes_model is not None self._older_notes_listbox.bind_model(self.__older_notes_model, self.__create_row, None) self.__older_notes_model.connect("items-changed", self.__on_older_notes_items_changed) def __populate_sections_list(self, note_manager: NoteManager) -> None: self.__main_sections.append( SectionInfo( note_manager.favourites_model, self._favourites_listbox, self._favourites_section, ) ) self.__main_sections.append( SectionInfo( note_manager.today_model, self._today_listbox, self._today_section, ) ) self.__main_sections.append( SectionInfo( note_manager.yesterday_model, self._yesterday_listbox, self._yesterday_section, ) ) self.__main_sections.append( SectionInfo( note_manager.week_model, self._week_listbox, self._week_section, ) ) self.__main_sections.append( SectionInfo( note_manager.month_model, self._month_listbox, self._month_section, ) ) self.__main_sections.append( SectionInfo( note_manager.last_month_model, self._last_month_listbox, self._last_month_section, ) ) def __visible_listboxes(self) -> Generator[Gtk.ListBox, None, None]: for listbox in self.__all_listboxes(): if listbox.get_parent().get_visible(): yield listbox def __all_listboxes(self) -> Generator[Gtk.ListBox, None, None]: for section in self.__main_sections: yield section.listbox for listbox in self.__extra_listboxes: yield listbox def __display_older_notes(self) -> bool: if self.older_notes_displayed: return True elif self.__older_notes_model is None: return False self.older_notes_displayed = True self.__bind_older_notes() self._older_notes_loader.set_visible(False) if len(self.__older_notes_model) > 0: self._older_notes_section.set_visible(True) return True else: return False iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/index_row.py000066400000000000000000000131521507102636600240730ustar00rootroot00000000000000from gi.repository import GObject, Gtk import re from typing import Optional from iotas.category import Category from iotas.config_manager import ConfigManager from iotas.note import Note @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/index_row.ui") class IndexRow(Gtk.Box): __gtype_name__ = "IndexRow" __gsignals__ = { "checkbox-toggled": (GObject.SignalFlags.RUN_FIRST, None, (bool,)), "context-click": (GObject.SignalFlags.RUN_FIRST, None, ()), } _title: Gtk.Label = Gtk.Template.Child() _excerpt: Gtk.Label = Gtk.Template.Child() _category: Gtk.Label = Gtk.Template.Child() _revealer: Gtk.Revealer = Gtk.Template.Child() _selection_checkbox: Gtk.CheckButton = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__note: Optional[Note] = None self.__signal_ids: list[int] = [] self.__index_category: Category | None = None self.connect("unrealize", lambda _o: self.__disconnect_signals()) def populate(self, note: Note, category_style: str) -> None: """Populate the row. :param Note note: The note :param str category_style: The category style """ if not note or self.__note == note: return if self.__note is not None: self.__disconnect_signals() self.__note = note self.__refresh_title_label() self.__category_style = category_style self.__set_default_category_label() note.bind_property("excerpt", self._excerpt, "label", GObject.BindingFlags.SYNC_CREATE) self.__signal_ids.append( note.connect("notify::category", lambda _o, _v: self.__refresh_category_label_style()) ) self.__signal_ids.append( note.connect("notify::dirty", lambda _o, _v: self.__refresh_title_label()) ) self.__signal_ids.append( note.connect("notify::title", lambda _o, _v: self.__refresh_title_label()) ) def set_checkbox_value(self, value) -> None: """Toggle the selected checkbox value. :param bool value: The new value """ self._selection_checkbox.set_active(value) def toggle_selected(self) -> None: """Toggle the selected checkbox.""" self._selection_checkbox.set_active(not self._selection_checkbox.get_active()) def update_category_label( self, index_category: Category, # TODO Use StrEnum style: str, ) -> None: """Update the category label. :param Category category: The index category :param str category_style: The category style """ self.__index_category = index_category self.__category_style = style self.__refresh_category_label_style() @GObject.Property(type=Note, default=None) def note(self) -> Optional[Note]: return self.__note @GObject.Property(type=bool, default=False) def child_revealed(self) -> bool: return self._revealer.get_reveal_child() @child_revealed.setter def set_child_revealed(self, revealed: bool) -> None: self._revealer.set_reveal_child(revealed) @Gtk.Template.Callback() def _on_selection_checkbox_toggled(self, button: Gtk.CheckButton) -> None: self.emit("checkbox-toggled", button.get_active()) @Gtk.Template.Callback() def _on_longpress(self, _gesture: Gtk.GestureLongPress, _x: float, _y: float) -> None: self.emit("context-click") @Gtk.Template.Callback() def _on_right_click( self, _gesture: Gtk.GestureClick, _n_press: int, _x: float, _y: float ) -> None: self.emit("context-click") def __refresh_title_label(self) -> None: assert self.__note txt = self.__note.title remote_syncing = ConfigManager.get_default().nextcloud_sync_configured if self.__note.dirty and remote_syncing: txt = "• " + txt self._title.set_text(txt) def __refresh_category_label_style(self) -> None: visible = self.__determine_category_visibility() self._category.set_visible(visible) if visible: category = self.__build_formatted_relative_category_name() self._category.set_label(category) def __determine_category_visibility(self) -> bool: assert self.__note if self.__category_style == "none": visible = False elif self.__note.category == "": visible = False elif ( self.__index_category is not None and self.__index_category.special_purpose is None and self.__index_category.name == self.__note.category ): visible = False else: visible = True return visible def __build_formatted_relative_category_name(self) -> str: assert self.__note category = self.__note.category if self.__index_category is not None and self.__index_category.special_purpose is None: category = re.sub(r"^" + re.escape(self.__index_category.name) + "/", "", category) if "/" in category: category = " / ".join(category.split("/")) return category def __set_default_category_label(self) -> None: assert self.__note category = self.__note.category if category != "": if "/" in category: category = " / ".join(category.split("/")) self._category.set_label(category) self._category.set_visible(True) def __disconnect_signals(self) -> None: for sig_id in self.__signal_ids: self.note.disconnect(sig_id) self.__signal_ids = [] iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/index_search_header_bar.py000066400000000000000000000107661507102636600266750ustar00rootroot00000000000000from gi.repository import Adw, Gdk, GObject, Gtk from enum import IntEnum, auto from iotas.index_note_list import IndexNoteList from iotas.note_manager import NoteManager from iotas.ui_utils import check_for_search_starting, check_for_open_first_result_shortcut class IndexSearchState(IntEnum): NO_TERM = auto() EMPTY = auto() RESULTS = auto() @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/index_search_header_bar.ui") class IndexSearchHeaderBar(Adw.Bin): __gtype_name__ = "IndexSearchHeaderBar" __gsignals__ = { "changed": (GObject.SignalFlags.RUN_FIRST, None, ()), } _entry: Gtk.SearchEntry = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__active = False def setup(self, note_list: IndexNoteList, note_manager: NoteManager) -> None: """Perform initial setup. :param IndexNoteList note_list: The note list :param NoteManager note_manager: The note manager """ self.__note_list = note_list self.__note_manager = note_manager def check_if_starting( self, controller: Gtk.EventControllerKey, keyval: int, state: Gdk.ModifierType, clear: bool = True, ) -> bool: """Check if starting search via type to search. :param Gtk.EventControllerKey controller: The key controller :param int keyval: The key value :param Gdk.ModifierType state: Any modifier state :param bool clear: Whether to clear the entry :return: Whether search is starting :rtype: bool """ if not check_for_search_starting(controller, keyval, state): return False if clear: self._entry.set_text("") if controller.forward(self._entry.get_delegate()): return True return False def check_for_open_first_result_shortcut( self, controller: Gtk.EventControllerKey, keyval: int, state: Gdk.ModifierType ) -> bool: """Check keyboard shortcut to activate first result has been pressed. :param Gtk.EventControllerKey controller: The key controller :param int keyval: The key value :param Gdk.ModifierType state: Any modifier state :return: Whether pressed :rtype: bool """ # Clunky way to determine if we have input focus window = self.get_root() focus_widget = window.get_property("focus-widget") if focus_widget.is_ancestor(self._entry): return check_for_open_first_result_shortcut(keyval, state) else: return False def enter(self, clear_text: bool, select_all: bool) -> None: """Enter search. :param bool clear_text: Whether to clear existing text :param bool select_all: Whether to select all text (when not clearing) """ self._entry.grab_focus() if clear_text: self._entry.set_text("") elif select_all: self._entry.select_region(0, -1) self.active = True def search(self, show_all: bool) -> IndexSearchState: """Perform a search. :param bool show_all: Whether to show the full result set (instead of the most recent with an expandable section) :return: The resulting search state :rtype: IndexSearchState """ search_text = self.text if len(search_text) > 0: found_ids = self.__note_manager.search_notes(search_text, sort=True) if len(found_ids) > 0: self.__note_list.restrict_for_search_by_ids(found_ids, show_all) return IndexSearchState.RESULTS else: return IndexSearchState.EMPTY else: return IndexSearchState.NO_TERM def exit(self) -> None: """Exit search. :param bool value: New value """ self.active = False def focus_entry(self) -> None: """Focus the text entry.""" self._entry.grab_focus() @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @active.setter def set_active(self, value: bool) -> None: self.__active = value @GObject.Property(type=str) def text(self) -> str: return self._entry.get_text().strip() @text.setter def set_text(self, value: str) -> str: return self._entry.set_text(value) @Gtk.Template.Callback() def _on_entry_changed(self, _entry: Gtk.Editable) -> None: self.emit("changed") iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/link_dialog.py000066400000000000000000000056571507102636600243640ustar00rootroot00000000000000from gettext import gettext as _ from gi.repository import Adw, Gio, GLib, GObject, Gtk from iotas.formatter import LinkStateInfo @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/link_dialog.ui") class LinkDialog(Adw.Dialog): """Link editing/creating dialog.""" __gtype_name__ = "LinkDialog" __gsignals__ = { "apply": (GObject.SignalFlags.RUN_FIRST, None, (LinkStateInfo,)), } _url_entry: Adw.EntryRow = Gtk.Template.Child() _text_entry: Adw.EntryRow = Gtk.Template.Child() _button: Gtk.Button = Gtk.Template.Child() def __init__(self) -> None: super().__init__() action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() action = Gio.SimpleAction.new("submit") action.connect("activate", lambda _a, _p: self.__apply()) action_group.add_action(action) app.set_accels_for_action("link-dialog.submit", ["Return"]) app.get_active_window().insert_action_group("link-dialog", action_group) self.__action_group = action_group self.connect("closed", lambda _o: self.__cleanup()) def show(self, info: LinkStateInfo, window: Gtk.Window) -> None: """Show dialog. :param LinkStateInfo info: Link state in buffer :param Gtk.Window window: Parent window """ if info.creating: # Translators: Title title = _("Insert Link") # Translators: Button button_label = _("Create") else: # Translators: Title title = _("Edit Link") # Translators: Button button_label = _("Apply") self._url_entry.set_text(info.link) self._text_entry.set_text(info.text) self.set_title(title) self._button.set_label(button_label) self.__info = info for action in self.__action_group.list_actions(): self.__action_group.lookup_action(action).set_enabled(True) self.present(window) # Can't directly call grab_focus from idle_add otherwise its returning of True will retain, # and repeat, the event def focus_url_entry(): self._url_entry.grab_focus() GLib.idle_add(focus_url_entry) @Gtk.Template.Callback() def _on_url_activated(self, _entry: Gtk.Entry) -> None: self._text_entry.grab_focus() @Gtk.Template.Callback() def _on_text_activated(self, _entry: Gtk.Entry) -> None: self.__apply() @Gtk.Template.Callback() def _on_button_clicked(self, _button: Gtk.Button) -> None: self.__apply() def __apply(self) -> None: self.__info.link = self._url_entry.get_text() self.__info.text = self._text_entry.get_text() self.emit("apply", self.__info) self.close() def __cleanup(self) -> None: for action in self.__action_group.list_actions(): self.__action_group.lookup_action(action).set_enabled(False) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/list_formatter.py000066400000000000000000000243601507102636600251360ustar00rootroot00000000000000from gi.repository import Gtk, GtkSource import re from typing import Callable, Optional from iotas.ordered_list_utils import ( check_line_for_ordered_list_item, calculate_ordered_list_index, format_ordered_list_item, ) # k is the token, v is the continuation _BULLET_LIST_TOKENS = { "- [ ] ": "- [ ] ", "- [x] ": "- [ ] ", "+ [ ] ": "+ [ ] ", "+ [x] ": "+ [ ] ", "* [ ] ": "* [ ] ", "* [x] ": "* [ ] ", "- ": "- ", "+ ": "+ ", "* ": "* ", } def check_and_extend_list(buffer: GtkSource.Buffer) -> bool: """Extend any list after a newline is inserted. :param GtkSource.Buffer buffer: Buffer to work on """ handled = False mark = buffer.get_insert() insert_iter = buffer.get_iter_at_mark(mark) line_start = insert_iter.copy() line_start.set_line_offset(0) previous_line = line_start.get_text(insert_iter) # TODO look at changing to use the GtkSourceLanguage context? regex_match = _check_line_for_bullet_list_item(previous_line) if regex_match is not None: handled = _extend_bullet_list(buffer, regex_match.group(), insert_iter, line_start) else: regex_match = check_line_for_ordered_list_item(previous_line) if regex_match is not None: handled = _extend_ordered_list(buffer, regex_match.groups(), insert_iter, line_start) return handled def increase_indentation(buffer: GtkSource.Buffer) -> None: """Increase indentation on a buffer line or selection. :param Gtk.Buffer buffer: Buffer to work on """ _handle_tab(buffer, True) def decrease_indentation(buffer: GtkSource.Buffer) -> None: """Decrease indentation on a buffer line or selection. :param Gtk.Buffer buffer: Buffer to work on """ _handle_tab(buffer, False) def _handle_tab(buffer: GtkSource.Buffer, increase: bool) -> None: buffer.begin_user_action() if buffer.get_has_selection(): begin, end = buffer.get_selection_bounds() begin.order(end) multi_line = "\n" in buffer.get_text(begin, end, False) if multi_line: line_iter = begin.copy() line_mark = buffer.create_mark(None, line_iter) end_mark = buffer.create_mark(None, end) while line_iter.compare(end) < 0: _modify_single_line_indent(buffer, line_iter, increase, multi_line) line_iter = buffer.get_iter_at_mark(line_mark) line_iter.forward_line() buffer.delete_mark(line_mark) line_mark = buffer.create_mark(None, line_iter) end = buffer.get_iter_at_mark(end_mark) buffer.delete_mark(line_mark) buffer.delete_mark(end_mark) else: _modify_single_line_indent(buffer, begin, increase, multi_line) else: mark = buffer.get_insert() begin = buffer.get_iter_at_mark(mark) _modify_single_line_indent(buffer, begin, increase, False) buffer.end_user_action() def _extend_bullet_list( buffer: GtkSource.Buffer, matched_list_item: str, insert_iter: Gtk.TextIter, line_start: Gtk.TextIter, ) -> bool: previous_line = line_start.get_text(insert_iter) # If the list already continues after our newline, don't add the next item markup. # Caters for accidentally deleting a line break in the middle of a list and then # pressing enter to revert that. cur_line_end = insert_iter.copy() if not cur_line_end.ends_line(): cur_line_end.forward_to_line_end() cur_line_text = insert_iter.get_text(cur_line_end) if _check_line_for_bullet_list_item(cur_line_text) is not None: return False def generate_sequence_previous_item() -> Optional[str]: return matched_list_item buffer.begin_user_action() empty_list_line = _inserted_empty_item_at_end_of_list( previous_line, matched_list_item, line_start, generate_sequence_previous_item ) if empty_list_line: # An empty list line has been entered, remove it from the list end buffer.delete(line_start, insert_iter) buffer.insert_at_cursor("\n") else: dict_key = matched_list_item.lstrip() spacing = matched_list_item[0 : len(matched_list_item) - len(dict_key)] new_entry = f"\n{spacing}{_BULLET_LIST_TOKENS[dict_key]}" buffer.insert_at_cursor(new_entry) buffer.end_user_action() return True def _extend_ordered_list( buffer: GtkSource.Buffer, regex_groups: tuple, insert_iter: Gtk.TextIter, line_start: Gtk.TextIter, ) -> bool: spacing = regex_groups[0] index = regex_groups[1] marker = regex_groups[2] previous_line = line_start.get_text(insert_iter) def generate_sequence_previous_item() -> Optional[str]: # Verify there's more than one list item. This allows inserting lines with list start # tokens and nothing else. previous_index = calculate_ordered_list_index(index, -1) if previous_index is None: return None else: return format_ordered_list_item(spacing, previous_index, marker) buffer.begin_user_action() empty_list_line = _inserted_empty_item_at_end_of_list( previous_line, "".join(regex_groups), line_start, generate_sequence_previous_item ) if empty_list_line: # An empty list line has been entered, remove it from the list end buffer.delete(line_start, insert_iter) buffer.insert_at_cursor("\n") buffer.end_user_action() else: sequence_next = calculate_ordered_list_index(index, 1) # Handle value of Z, ending sequence if sequence_next is None: buffer.end_user_action() return False new_entry = "\n" + format_ordered_list_item(spacing, sequence_next, marker) buffer.insert(insert_iter, new_entry) _increment_any_following_ordered_list_items( buffer, insert_iter, sequence_next, marker, spacing ) buffer.end_user_action() return True def _increment_any_following_ordered_list_items( buffer: GtkSource.Buffer, insert_iter: Gtk.TextIter, index: str, marker: str, spacing: str ) -> None: cursor_mark = buffer.create_mark(None, insert_iter) current_entry = format_ordered_list_item(spacing, index, marker) while True: # Check if the next line continues the list if not insert_iter.forward_line(): break line_end = insert_iter.copy() line_end.forward_to_line_end() text = buffer.get_text(insert_iter, line_end, include_hidden_chars=False) if not text.startswith(current_entry): break next_index = calculate_ordered_list_index(index, 1) # Handle value of Z, ending sequence if not next_index: break index = next_index entry_next = format_ordered_list_item(spacing, index, marker) # Delete existing end = insert_iter.copy() end.forward_chars(len(current_entry)) buffer.delete(insert_iter, end) # Insert new buffer.insert(insert_iter, entry_next) current_entry = entry_next buffer.place_cursor(buffer.get_iter_at_mark(cursor_mark)) buffer.delete_mark(cursor_mark) def _modify_single_line_indent( buffer: GtkSource.Buffer, location: Gtk.TextIter, increase: bool, multi_line: bool ) -> None: line_start = location.copy() line_start.set_line_offset(0) line_end = location.copy() if not line_end.ends_line(): line_end.forward_to_line_end() line_contents = buffer.get_text(line_start, line_end, False) # Don't process empty lines if multi_line and line_contents == "": return list_item = ( _check_line_for_bullet_list_item(line_contents) is not None or check_line_for_ordered_list_item(line_contents) is not None ) indent_chars = " " if list_item else "\t" if increase: if multi_line or list_item: buffer.insert(line_start, indent_chars) else: buffer.insert(location, indent_chars) else: if line_contents.startswith(indent_chars): end_deletion = line_start.copy() end_deletion.forward_chars(len(indent_chars)) buffer.delete(line_start, end_deletion) def _inserted_empty_item_at_end_of_list( line_text: str, matched_list_item: str, previous_line_start: Gtk.TextIter, fetch_sequence_previous: Callable[[], Optional[str]], ) -> bool: """Determine whether we have inserted an empty item at the end of a list The list needs to have at least one previous item. :param str line_text: The full line text :param str matched_list_item: Our matched list marker :param Gtk.TextIter previous_line_start: The start of the previous line :param Callable[], Optional[str]] fetch_sequence_previous: A function to fetch a previous line's marker :return: Whether we've inserted an empty line :rtype: bool """ # Check if entered line contains only the list item markup if line_text.strip() != matched_list_item.strip(): return False # Fetch what a previous item in the sequence would have been, for the check below. The # callable is used to prevent calculating this before we even know if match above will # pass (while sharing logic for bullet and ordered lists). sequence_previous_item = fetch_sequence_previous() if sequence_previous_item is None: return False # Verify there's more than one list item. This allows inserting lines with list start # tokens and nothing else. two_prev_start = previous_line_start.copy() two_prev_start.backward_line() two_prev_start.set_line_offset(0) two_prev_line = two_prev_start.get_text(previous_line_start) return two_prev_line.startswith(sequence_previous_item) def _check_line_for_bullet_list_item(linetext: str) -> Optional[re.Match[str]]: # Avoid misidentifying our horizontal rule markup as an ordered list line. This should be made # to handle other valid horizontal rule forms, and be integrated into the regex below. if linetext == "- - -": return None term = r"^\s*(" escaped_tokens = [] for token in _BULLET_LIST_TOKENS.keys(): escaped_tokens.append(re.escape(token)) term += "|".join(escaped_tokens) term += ")" return re.search(term, linetext) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/main.py.in000077500000000000000000000025621507102636600234340ustar00rootroot00000000000000#!@PYTHON@ import gettext from gi.repository import Gio, GLib import locale import os import sys import iotas.const as const def install_excepthook(): """Make sure we exit when an unhandled exception occurs.""" old_hook = sys.excepthook def new_hook(etype, evalue, etb): old_hook(etype, evalue, etb) app = Gio.Application.get_default() if app is not None: app.quit() sys.exit() sys.excepthook = new_hook def main(): install_excepthook() try: locale.bindtextdomain(const.GETTEXT_PACKAGE, const.LOCALEDIR) locale.textdomain(const.GETTEXT_PACKAGE) except AttributeError as e: # Python built without gettext support doesn't have bindtextdomain() and textdomain() print( "Couldn't bind the gettext translation domain. Some translations won't work.\n{}".format( e ) ) gettext.bindtextdomain(const.GETTEXT_PACKAGE, const.LOCALEDIR) gettext.textdomain(const.GETTEXT_PACKAGE) resource = Gio.resource_load(os.path.join(const.PKGDATADIR, "resources.gresource")) Gio.resources_register(resource) GLib.set_application_name("Iotas" + const.SUFFIX) from iotas.application import Application app = Application() exit_status = app.run(sys.argv) sys.exit(exit_status) if __name__ == "__main__": main() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/markdown_helpers.py000066400000000000000000000156521507102636600254500ustar00rootroot00000000000000import os from typing import Optional from urllib.parse import quote, urlparse, unquote from uuid import uuid4 from markdown_it import MarkdownIt from markdown_it.token import Token from mdit_py_plugins.attrs import attrs_plugin from mdit_py_plugins.dollarmath import dollarmath_plugin from markdown_it_modified_tasklists_plugin.mdit_tasklists_with_elements_plugin import ( tasklists_with_elements_plugin, ) from markdown_it_img_figures_plugin.mdit_img_figures_plugin import img_figures_plugin from iotas.attachment import Attachment from iotas.note import Note def parse_to_tokens( note: Note, exporting: bool, tex_support: bool, ) -> tuple[MarkdownIt, list[Token]]: """Generate parser tokens for note. :param Note note: Note :param bool exporting: Whether for export :param bool tex_support: Whether to support TeX equations :return: Parser and list of parser tokens :rtype: tuple[MarkdownIt, list[Token]] """ parser = ( MarkdownIt("gfm-like") .use(tasklists_with_elements_plugin, enabled=not note.read_only, div=True) .use(attrs_plugin, after=["image"], allowed=["height", "width"]) .enable("table") ) parser.use(img_figures_plugin, lazyload=not exporting) if tex_support: parser.use(dollarmath_plugin, renderer=__render_tex) if exporting: content = get_note_export_content(note, prefix_note_id=False) else: content = note.content return (parser, parser.parse(content)) def get_note_export_content(note: Note, prefix_note_id: bool) -> str: """Get note content with image paths updated for export. :param Note note: Note :param bool prefix_note_id: Whether to prefix the note id :return: Updated content :rtype: str """ attachments = get_image_attachments_from_note_content(note) note_id_prefix = f"{note.id}." if prefix_note_id else "" content = note.content for attachment in attachments: old_path = attachment.path new_path = f"attachments/{note_id_prefix}{os.path.basename(old_path)}" content = update_image_path_in_markup(content, old_path, new_path) return content def get_image_attachments_from_tokens(note: Note, tokens: list[Token]) -> list[Attachment]: """Get list of attachments from parser tokens. :param Note note: Note :param list[Token] tokens: Parser tokens :return: Attachments :rtype: list[Attachment] """ images = filter_image_tokens(tokens) attachments = [] for img in images: src = img.attrs["src"] if not urlparse(src).netloc and not src.strip().startswith("/"): path = unquote(src) attachment = create_attachment_for_markup_path(note, path) attachments.append(attachment) return attachments def get_image_attachments_from_note_content(note: Note) -> list[Attachment]: """Get list of attachments from note contents. :param Note note: Note :return: Attachments :rtype: list[Attachment] """ _parser, tokens = parse_to_tokens(note, exporting=False, tex_support=False) return get_image_attachments_from_tokens(note, tokens) def filter_image_tokens(tokens: list[Token]) -> list[Token]: """Filter list of parser tokens to images. :param list[Token] tokens: Parser tokens :return: Image tokens :rtype: list[Token] """ images = [] def add_images_from_children(tokens: list[Token]) -> None: for token in tokens: if token.children: add_images_from_children(token.children) if token.type == "image" and "src" in token.attrs: images.append(token) add_images_from_children(tokens) return images def create_attachment_for_markup_path(note: Note, path: str) -> Attachment: """Create an attachment with the provided markup path. :param Note note: Note :param str path: Attachment markup path, unquoted :return: Attachment :rtype: Attachment """ attachment = Attachment() attachment.note_id = note.id attachment.path = path attachment.note_remote_id = note.remote_id return attachment def update_image_path_in_markup(content: str, old_path: str, new_path: str) -> str: """Update image path in note content. :param str content: Note content :param str old_path: Previous path, unquoted :param str new_path: New path, unquoted :return: Updated note content :rtype: str """ old_path = quote(old_path) new_path = quote(new_path) search = f"]({old_path}" start_index = content.find(search) while start_index >= 0: path_start = start_index + 2 path_end = path_start + len(old_path) image_end = __get_image_end_index(content, path_end) if image_end is not None: # Ensure we haven't matched a link. Clunky but in theory a little less brittle than a # weak regex. element_start = content.rfind("![", 0, start_index) if element_start != -1: full_markup = content[element_start:image_end] if string_is_image(full_markup): content = content[0:path_start] + new_path + content[path_end:] path_end = path_start + len(new_path) start_index = content.find(search, path_end) return content def string_is_image(input: str) -> bool: """Whether provided string is markdown for an image. :param str input: Markdown string :return: Whether an image :rtype: bool """ parser = MarkdownIt("gfm-like") tokens = parser.parseInline(input) if len(tokens) != 1: return False elif len(tokens[0].children) != 1: return False elif tokens[0].children[0].type != "image": return False else: return True def __render_tex(equation: str, options: dict) -> str: """Render TeX markdown into HTML element. :param str equation: Equation :param dict options: Render options :return: Generated HTML :rtype: str """ span_id = f"tex-{uuid4()}" equation = equation.replace("\\", "\\\\") js_options = f'{{displayMode: {str(options["display_mode"]).lower()}}}' katex_cmd = ( f"var equation = `{equation}`; " + f"katex.render(equation, document.getElementById('{span_id}'), {js_options});" ) return f'' def __get_image_end_index(content: str, path_end: int) -> Optional[int]: index = path_end found = False in_title = False while not found: if index >= len(content): break char = content[index] if char == "\n": break elif char == "\r": break elif char == '"': if in_title: in_title = False else: in_title = True elif char == ")" and not in_title: found = True index += 1 if found: return index else: return None iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/markdown_render_view.py000066400000000000000000000320471507102636600263140ustar00rootroot00000000000000import gi gi.require_version("WebKit", "6.0") from gi.repository import Adw, Gdk, GLib, GObject, WebKit, JavaScriptCore import json import logging from typing import Callable, Optional import webbrowser from markdown_it.token import Token from iotas.attachment import Attachment from iotas.attachment_helpers import ( get_attachment_disk_states, get_attachment_filesystem_uri, set_attachment_filesystem_uris_on_tokens, ) from iotas.markdown_helpers import filter_image_tokens from iotas.config_manager import ConfigManager from iotas.html_generator import HtmlGenerator from iotas.markdown_helpers import parse_to_tokens from iotas.note import Note class MarkdownRenderView(WebKit.WebView): __gtype_name__ = "MarkdownRenderView" __gsignals__ = { "checkbox-toggled": (GObject.SignalFlags.RUN_FIRST, None, (int, bool)), "loaded": (GObject.SignalFlags.RUN_FIRST, None, ()), } def __init__(self) -> None: super().__init__() self.__user_stylesheet = None self.__scroll_position = 0.0 self.__engine_initialised = False self.__searching = False self.__exporting = False self.__loading_attachments: dict[str, Attachment] = {} self.__note: Note self.__config_manager: Optional[ConfigManager] self.__download_attachments: Optional[Callable[[dict[str, Attachment], bool], None]] = None def setup( self, html_generator: HtmlGenerator, config_manager: Optional[ConfigManager], track_timing: bool, ) -> None: """Setup for new WebKit instance.""" self.__html_generator = html_generator self.__config_manager = config_manager self.__track_timing = track_timing self.connect("decide-policy", self.on_decide_policy) self.connect("load-changed", self.__on_load_changed) self.connect("load-failed", lambda _v, _e, _u, _f: self.__clear_exporting()) self.connect("context-menu", self.on_context_click) content_manager = self.get_user_content_manager() content_manager.register_script_message_handler("toPython") content_manager.connect("script-message-received", self.__handle_js_message) self.__content_manager = content_manager if config_manager: config_manager.connect_changed(ConfigManager.FONT_SIZE, self.update_style) config_manager.connect_changed( ConfigManager.MARKDOWN_RENDER_MONOSPACE_FONT_RATIO, self.update_style, ) config_manager.connect_changed(ConfigManager.LINE_LENGTH, self.update_style) config_manager.connect_changed( ConfigManager.EDITOR_HEADER_BAR_VISIBILTY, self.update_style, ) config_manager.connect_changed( ConfigManager.EDITOR_FORMATTING_BAR_VISIBILTY, self.update_style, ) style_manager = Adw.StyleManager.get_default() style_manager.connect("notify::high-contrast", lambda _o, _v: self.update_style()) self.connect("web-process-terminated", self.__log_termination) # self.get_settings().set_enable_developer_extras(True) def render( self, note: Note, export_format: Optional[str], attachment_download_func: Optional[Callable[[dict[str, Attachment], bool], None]] = None, scroll_position: Optional[float] = None, ) -> None: """Render view with new markdown. :param Note note: Note to render :param bool export_format: Export format if exporting, optional :param Callable[[dict[str, Attachment], bool], None] attachment_download_func: Function to download missing attachments, optional :param float scroll_position: Position to scroll to, optional """ self.update_style() if export_format is not None: self.exporting = True parser, tokens = parse_to_tokens( note, exporting=self.exporting, tex_support=self.__get_support_tex() ) attachments_states = get_attachment_disk_states(note, tokens) if attachments_states.exists: set_attachment_filesystem_uris_on_tokens(tokens, attachments_states.exists) if attachments_states.missing and attachment_download_func: self.__loading_attachments = attachments_states.missing hide_loading_images(tokens, self.__loading_attachments) else: self.__loading_attachments = {} render_func = parser.renderer.render content = self.__html_generator.generate( note, tokens, render_func, parser.options, self.__searching, export_format, scroll_position, ) self.scroll_position = scroll_position if scroll_position else 0 self.__parser_tokens = tokens self.__download_attachments = attachment_download_func self.__load_started_at = GLib.get_monotonic_time() self.load_html(content, "file://localhost/") def render_retaining_scroll( self, note: Note, export_format: Optional[str], attachment_download_func: Optional[Callable[[dict[str, Attachment], bool], None]] = None, ) -> None: """Render view with new markdown retaining scroll position. :param Note note: Note to render :param bool export_format: Export format if exporting or None :param Callable[[dict[str, Attachment], bool], None] attachment_download_func: Function to download missing attachments, optional """ self.render(note, export_format, attachment_download_func, self.scroll_position) def update_style(self) -> None: """Update the configurable style used in the render.""" stylesheet = self.__html_generator.generate_user_stylesheet(self.__searching) if self.__user_stylesheet is not None: self.__content_manager.remove_style_sheet(self.__user_stylesheet) self.__user_stylesheet = WebKit.UserStyleSheet( stylesheet, WebKit.UserContentInjectedFrames.ALL_FRAMES, WebKit.UserStyleLevel.USER, None, None, ) self.__content_manager.add_style_sheet(self.__user_stylesheet) def scroll_to_heading(self, line_number: int) -> None: """Scroll to heading. :param int line_number: Line the heading in source markdown """ script = f""" element = document.querySelector('[data-map="{line_number}"]'); if (element) element.scrollIntoView(); """ self.evaluate_javascript( script, length=-1, world_name=None, source_uri=None, cancellable=None, callback=None ) def show_attached_image(self, attachment: Attachment) -> None: """Call Javascript to show downloaded image in render. :param Attachment attachment: Attachment """ script = f""" elements = document.querySelectorAll('img[src="{attachment.path_quoted}"]'); for (let i = 0; i < elements.length; i++) {{ elements[i].src = '{get_attachment_filesystem_uri(attachment)}'; elements[i].className = ''; }} """ self.evaluate_javascript( script, length=-1, world_name=None, source_uri=None, cancellable=None, callback=None ) @staticmethod def on_decide_policy( _web_view: WebKit.WebView, decision: WebKit.PolicyDecision, decision_type: WebKit.PolicyDecisionType, ) -> bool: if ( decision_type == WebKit.PolicyDecisionType.NAVIGATION_ACTION and decision.get_navigation_action().is_user_gesture() ): uri = decision.get_navigation_action().get_request().get_uri() webbrowser.open(uri) decision.ignore() return True return False @staticmethod def on_context_click( _web_view: WebKit.WebView, menu: WebKit.ContextMenu, _event: Gdk.Event, ) -> None: for item in menu.get_items(): if item.get_stock_action() in [ WebKit.ContextMenuAction.DOWNLOAD_LINK_TO_DISK, WebKit.ContextMenuAction.GO_BACK, WebKit.ContextMenuAction.GO_FORWARD, WebKit.ContextMenuAction.OPEN_LINK, WebKit.ContextMenuAction.OPEN_LINK_IN_NEW_WINDOW, WebKit.ContextMenuAction.RELOAD, WebKit.ContextMenuAction.STOP, ]: menu.remove(item) @GObject.Property(type=bool, default=False) def exporting(self) -> bool: return self.__exporting @exporting.setter def set_exporting(self, value: bool) -> None: self.__exporting = value @GObject.Property(type=float) def scroll_position(self) -> float: return self.__scroll_position @scroll_position.setter def set_scroll_position(self, value: float) -> None: self.__scroll_position = value @GObject.Property(type=bool, default=False) def searching(self) -> bool: return self.__searching @searching.setter def set_searching(self, value: bool) -> None: self.__searching = value self.update_style() def __on_load_changed(self, _web_view: WebKit.WebView, load_event: WebKit.LoadEvent) -> None: if load_event == WebKit.LoadEvent.FINISHED: if self.__track_timing: duration = GLib.get_monotonic_time() - self.__load_started_at if self.__engine_initialised: logging.debug(f"Render took {duration/1000:.2f}ms") else: logging.debug(f"WebKit initialisation and render took {duration/1000:.2f}ms") self.__engine_initialised = True self.emit("loaded") if self.__loading_attachments: if self.__download_attachments: logging.debug("Start missing images download") on_thread = True self.__download_attachments(self.__loading_attachments, on_thread) else: logging.warning(f"Missing {len(self.__loading_attachments)} attachments") def __clear_exporting(self) -> None: self.exporting = False def __handle_js_message( self, _manager: WebKit.UserContentManager, result: JavaScriptCore.Value ) -> None: js = result.to_json(2) message = json.loads(js) if message["type"] == "checkbox": self.__handle_checkbox_toggle(message) elif message["type"] == "scrollPosition": if "position" not in message or message["position"] is None: logging.warning("Received scroll position message with no position") return self.scroll_position = message["position"] def __handle_checkbox_toggle(self, message: dict) -> None: search_id = message["id"] new_value = message["checked"] def match(token: Token, search_id: str) -> bool: search_str = f'id="{search_id}"' return token.type == "html_inline" and search_str in token.content def handle_match(line: int, new_value: bool) -> None: self.emit("checkbox-toggled", line, new_value) line: int | None = None for token in self.__parser_tokens: if token.map is not None: line = token.map[0] if match(token, search_id): logging.debug( f'Setting checkbox on line {line} with id "{search_id}" to {new_value}' ) assert line is not None handle_match(line, new_value) return if token.children is not None: for child in token.children: if match(child, search_id): if token.map is not None: line = token.map[0] logging.debug( f'Setting checkbox on line {line} with id "{search_id}" to {new_value}' ) assert line is not None handle_match(line, new_value) return def __log_termination( self, _web_view: WebKit.WebView, reason: WebKit.WebProcessTerminationReason ) -> None: if self.__track_timing: logging.debug(f"WebKit process terminated for {reason}") self.__engine_initialised = False def __get_support_tex(self) -> bool: if not self.__config_manager: return False else: return self.__config_manager.markdown_tex_support def hide_loading_images(tokens: list[Token], transferring: dict[str, Attachment]) -> None: """Hide server transferring images in parser tokens. :param list[Token] tokens: Parser tokens :param dict[str, Attachment] transferring: Transferring attachments """ images = filter_image_tokens(tokens) for img in images: src = img.attrs["src"] if src in transferring: img.attrs["class"] = "transferring" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/meson.build000066400000000000000000000016661507102636600236740ustar00rootroot00000000000000conf = configuration_data() conf.set('APPID', application_id) conf.set('GETTEXT_PACKAGE', meson.project_name()) conf.set('LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale')) conf.set('NAME', project_name) conf.set('PYTHON', python_bin.full_path()) conf.set('DATA_DIR', DATA_DIR) conf.set('PROFILE', profile) conf.set('VERSION', iotas_version + version_suffix) configure_file( input: 'const.py.in', output: 'const.py', configuration: conf, install_dir: join_paths(python_dir, 'iotas'), install: true ) main_conf = configuration_data() main_conf.set('PYTHON', python_bin.full_path()) configure_file( input: 'main.py.in', output: 'iotas', configuration: conf, install_dir: bindir, install: true ) install_subdir( meson.current_source_dir(), exclude_directories: ['.mypy_cache', '__pycache__'], exclude_files: ['main.py.in', 'const.py.in', 'meson.build', '.flake8'], install_dir: python_dir, ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/migration_assistant.py000066400000000000000000000115241507102636600261600ustar00rootroot00000000000000from gi.repository import GLib, GObject from collections import OrderedDict import logging from packaging.version import Version, InvalidVersion from iotas.config_manager import ConfigManager, HeaderBarVisibility import iotas.const as const from iotas.note import DirtyFields from iotas.note_database import NoteDatabase from iotas.ui_utils import have_window_with_width, is_likely_mobile_device class MigrationAssistant(GObject.Object): def __init__(self, db: NoteDatabase) -> None: self.__db = db self.__config_manager = ConfigManager.get_default() self.__migrations = OrderedDict() self.__migrations["0.1.14"] = self.__make_keeping_webkit_in_memory_default self.__migrations["0.9.0"] = self.__v090_preference_migrations self.__ui_dependent_migrations = OrderedDict() self.__ui_dependent_migrations["0.9.0"] = self.__set_formatting_bar_style_based_on_device version = self.__config_manager.last_launched_version try: self.__previous_version = Version(version) except InvalidVersion: logging.warning(f"Unexpected last version {version}") self.__previous_version = None def migrate(self) -> None: current_version = self.__get_current_version() if self.__previous_version != current_version: if self.__previous_version is not None: if current_version > self.__previous_version: logging.info("Updating to v{}".format(current_version)) self.__run_migrations(self.__migrations) self.__wait_and_run_ui_dependent_migrations() else: logging.info( "Downgrading to v{}? Not running migrations.".format(current_version) ) self.__regenerate_excerpts() self.__config_manager.last_launched_version = str(current_version) def __wait_and_run_ui_dependent_migrations(self) -> None: # Another location (ala FirstStart) using this pattern as a result of not yet # discovering the clean way to be notified when a window has obtained its initial size def wait_and_run(): if not have_window_with_width(): GLib.timeout_add(250, wait_and_run) else: self.__run_migrations(self.__ui_dependent_migrations) wait_and_run() def __run_migrations(self, migrations: OrderedDict) -> None: for version, function in migrations.items(): if Version(version) > self.__previous_version: function() def __get_current_version(self) -> Version: version = const.VERSION # Handle development suffixes if "-" in version: version = version.split("-")[0] return Version(version) def __regenerate_excerpts(self) -> None: notes = self.__db.get_all_notes(load_content=True) for note in notes: if note.regenerate_excerpt(): changed_fields = DirtyFields() changed_fields.excerpt = True self.__db.persist_note_selective(note, changed_fields) def __make_keeping_webkit_in_memory_default(self) -> None: logging.info("Setting WebKit process to be retained in memory after first use") self.__config_manager.markdown_keep_webkit_process = True def __v090_preference_migrations(self) -> None: logging.info("Running v0.9.0 preference migrations") if not self.__config_manager.markdown_syntax_hightlighting_enabled: logging.info( "Syntax highlighting was previous disabled, migrating to syntax detection enabled " "with unstyled theme" ) self.__config_manager.markdown_detect_syntax = True self.__config_manager.editor_theme = "iotas-unstyled" if self.__config_manager.hide_editor_headerbar: visibility = HeaderBarVisibility.AUTO_HIDE elif self.__config_manager.hide_editor_headerbar_when_fullscreen: visibility = HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY else: visibility = HeaderBarVisibility.ALWAYS_VISIBLE logging.info( f"Migrated previous header bar preferences to '{str(visibility)}' header bar visibility" ) self.__config_manager.editor_header_bar_visibility = visibility def __set_formatting_bar_style_based_on_device(self) -> None: if is_likely_mobile_device(): logging.info("Likely on mobile device, setting formatting bar to stay visible") visibility = HeaderBarVisibility.ALWAYS_VISIBLE else: logging.info("Likely not on mobile device, setting formatting bar to auto hide") visibility = HeaderBarVisibility.AUTO_HIDE self.__config_manager.editor_formatting_bar_visibility = visibility iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/nextcloud_login_dialog.py000066400000000000000000000210631507102636600266110ustar00rootroot00000000000000from gettext import gettext as _ from gi.repository import Adw, Gdk, Gio, GLib, Gtk from enum import IntEnum, auto from threading import Thread from typing import Optional from iotas.config_manager import ConfigManager from iotas.nextcloud_sync_worker import LoginRequestResult from iotas.sync_manager import SyncManager class LoginDialogMode(IntEnum): NORMAL = auto() REAUTHENTICATE = auto() SECRET_SERVICE_FAILURE = auto() @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/nextcloud_login_dialog.ui") class NextcloudLoginDialog(Adw.Dialog): __gtype_name__ = "NextcloudLoginDialog" CHECK_LOGIN_INTERVAL = 1000 _toolbar_view: Adw.ToolbarView = Gtk.Template.Child() _stack: Gtk.Stack = Gtk.Template.Child() _intro: Adw.StatusPage = Gtk.Template.Child() _secret_service_failure: Adw.StatusPage = Gtk.Template.Child() _entry: Adw.ToastOverlay = Gtk.Template.Child() _self_signed_certificate_handling: Adw.StatusPage = Gtk.Template.Child() _loading: Adw.StatusPage = Gtk.Template.Child() _finished: Adw.StatusPage = Gtk.Template.Child() _url_continue_button: Gtk.Button = Gtk.Template.Child() _url_entry: Adw.EntryRow = Gtk.Template.Child() _instance_label: Gtk.Label = Gtk.Template.Child() def __init__(self, sync_manager: SyncManager, mode: LoginDialogMode) -> None: super().__init__() self.__sync_manager = sync_manager self.__config_manager = ConfigManager.get_default() self.__mode = mode self.__timeout_id = None if mode == LoginDialogMode.SECRET_SERVICE_FAILURE: self._stack.set_visible_child(self._secret_service_failure) elif mode == LoginDialogMode.REAUTHENTICATE: endpoint = self.__config_manager.nextcloud_endpoint if endpoint != "": self._url_entry.set_text(endpoint) self.__attempt_login() self.__sync_manager.connect("finished", self.__on_initial_sync_finished) self.connect("closed", lambda _o: self.__on_close()) @Gtk.Template.Callback() def _on_intro_continue_clicked(self, _button: Gtk.Button) -> None: self._stack.set_visible_child(self._entry) self._url_continue_button.set_sensitive(False) endpoint = self.__config_manager.nextcloud_endpoint if endpoint != "": self._url_entry.set_text(endpoint) self._url_entry.grab_focus() self._url_entry.set_position(-1) @Gtk.Template.Callback() def _on_entry_continue_clicked(self, _button: Gtk.Button) -> None: self.__attempt_login() @Gtk.Template.Callback() def _on_url_entry_changed(self, _entry: Gtk.Editable) -> None: self._url_continue_button.set_sensitive(self.__url_entry_valid()) @Gtk.Template.Callback() def _on_url_entry_activated(self, _entry: Gtk.Entry) -> None: if self.__url_entry_valid(): self.__attempt_login() @Gtk.Template.Callback() def _open_faq(self, _button: Gtk.Button) -> None: app = Gio.Application.get_default() if not app: return None window = app.get_active_window() Gtk.show_uri( window, "https://gitlab.gnome.org/World/iotas/-/wikis/nextcloud-notes", Gdk.CURRENT_TIME, ) @Gtk.Template.Callback() def _on_done_clicked(self, _button: Gtk.Button) -> None: self.close() def __on_close(self) -> None: if self.__timeout_id is not None: GLib.source_remove(self.__timeout_id) self.__timeout_id = None self.__sync_manager.disconnect_by_func(self.__on_initial_sync_finished) def __on_login_success(self, storage_success: bool) -> None: if storage_success: if self._stack.get_visible_child() == self._loading: self._loading.set_description("") if self.__mode == LoginDialogMode.REAUTHENTICATE: # Translators: Title self._loading.set_title(_("Updating Notes")) else: self.__config_manager.first_start = False # Translators: Title self._loading.set_title(_("Performing Initial Transfer")) else: self._stack.set_visible_child(self._secret_service_failure) def __on_initial_sync_finished(self, _obj: SyncManager, _changes: int) -> None: self._stack.set_visible_child(self._finished) self._toolbar_view.set_reveal_top_bars(False) def removeprefix(instr, prefix): return instr[len(prefix) :] if instr.startswith(prefix) else instr clean_url = removeprefix(self.__server_url, "https://") clean_url = removeprefix(clean_url, "http://") self._instance_label.set_text(clean_url) def __url_entry_valid(self) -> bool: valid = False entry_text = self.__get_sanitised_url_entry() try: valid = GLib.uri_is_valid(entry_text, GLib.UriFlags.NONE) except GLib.GError: pass # GLib's Uri.is_valid appears to allow eg. http:someurl.com if valid: scheme = GLib.uri_peek_scheme(entry_text) if scheme not in ("http", "https") or not entry_text.startswith(f"{scheme}://"): valid = False return valid def __wait_and_check_success(self) -> None: self.__timeout_id = GLib.timeout_add(self.CHECK_LOGIN_INTERVAL, self.__check_success) def __check_success(self) -> None: self.__timeout_id = None def thread_do() -> None: assert self.__endpoint assert self.__token ( login_success, storage_success, ) = self.__sync_manager.check_for_login_success(self.__endpoint, self.__token) if login_success: GLib.idle_add(self.__on_login_success, storage_success) else: GLib.idle_add(self.__wait_and_check_success) thread = Thread(target=thread_do) thread.daemon = True thread.start() def __attempt_login(self) -> None: self._stack.set_visible_child(self._loading) self._loading.set_description("") # Translators: Title self._loading.set_title(_("Connecting")) self.__server_url = self.__get_sanitised_url_entry() self.__config_manager.nextcloud_endpoint = self.__server_url def thread_do() -> None: # Using instead of getting parent due to __attempt_login being called in constructor # for reauthentication app = Gio.Application.get_default() window = app.get_active_window() (result, endpoint, token) = self.__sync_manager.start_login(self.__server_url, window) GLib.idle_add(self.__handle_login_initialisation, result, endpoint, token) thread = Thread(target=thread_do) thread.daemon = True thread.start() def __handle_login_initialisation( self, result: LoginRequestResult, endpoint: Optional[str], token: Optional[str] ) -> None: if result == LoginRequestResult.SUCCESS: # Translators: Title self._loading.set_title(_("Waiting for Login")) # Translators: Description self._loading.set_description(_("Complete the authentication in your browser")) self.__endpoint = endpoint self.__token = token self.__wait_and_check_success() elif result == LoginRequestResult.FAILURE_SELF_SIGNED_SSL: self._stack.set_visible_child(self._self_signed_certificate_handling) else: self._stack.set_visible_child(self._entry) # Set the failed URL back into try text entry. This is to make any URI scheme # prefixing that has been done clear to the user. self._url_entry.set_text(self.__server_url) self._url_entry.set_position(-1) self._url_entry.grab_focus() if result == LoginRequestResult.FAILURE_CERTIFICATE: # Translators: Description, notification msg = _("Failed to start login with possible certificate issue") else: # Translators: Description, notification msg = _("Failed to start login. Wrong address?") toast = Adw.Toast.new(msg) self._entry.add_toast(toast) def __get_sanitised_url_entry(self) -> str: entry_text = self._url_entry.get_text().strip().strip("/") scheme = GLib.uri_peek_scheme(entry_text) if entry_text != "" and scheme is None: entry_text = f"https://{entry_text}" return entry_text iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/nextcloud_sync_worker.py000066400000000000000000000525751507102636600265430ustar00rootroot00000000000000import gi gi.require_version("Secret", "1") from gi.repository import Gdk, GObject, GLib, Gtk, Secret import datetime from email.utils import parsedate_to_datetime from enum import IntEnum, auto from json.decoder import JSONDecodeError import logging import os import requests from threading import Thread from typing import Optional from ssl import SSLCertVerificationError import iotas.const as const from iotas.attachment import Attachment from iotas.nextcloud_sync_worker_configuration import NextcloudSyncWorkerConfiguration from iotas.note import Note from iotas.sync_result import SyncResult, ContentPushSyncResult class LoginRequestResult(IntEnum): SUCCESS = auto() FAILURE_GENERIC = auto() FAILURE_SELF_SIGNED_SSL = auto() FAILURE_CERTIFICATE = auto() class NextcloudSyncWorker(GObject.Object): __gsignals__ = { "ready": (GObject.SignalFlags.RUN_FIRST, None, (bool,)), "api-check-finished": (GObject.SignalFlags.RUN_FIRST, None, ()), "settings-fetched": (GObject.SignalFlags.RUN_FIRST, None, (str,)), "secret-service-failure": (GObject.SignalFlags.RUN_FIRST, None, ()), "missing-password": (GObject.SignalFlags.RUN_FIRST, None, ()), "notes-capability-missing": (GObject.SignalFlags.RUN_FIRST, None, ()), } ENDPOINT_V_1_0 = "/index.php/apps/notes/api/v1/" ENDPOINT_V_1_4 = "/index.php/apps/notes/api/v1.4/" EXPECTED_API_VERSION = "1.4" LOGIN_ENDPOINT = "/index.php/login/v2" CAPABILITIES_ENDPOINT = "/ocs/v2.php/cloud/capabilities" SECRET_ATTRIBUTES = {"service": "nextcloud"} SECRET_SCHEMA = Secret.Schema.new( "org.gnome.World.Iotas", Secret.SchemaFlags.NONE, {"service": Secret.SchemaAttributeType.STRING}, ) USER_AGENT = f"Iotas/{const.VERSION}" CA_CHAIN_FILE = os.path.join(GLib.get_user_data_dir(), "iotas", "server_ssl_ca_chain.pem") # From openssl/x509_vfy.h OPENSSL_SELF_SIGNED_CERTIFICATE_ERROR_CODES = (18, 19) def __init__(self, config_manager: NextcloudSyncWorkerConfiguration) -> None: super().__init__() self.__config_manager = config_manager self.__app_password: Optional[str] = None self.__secret_service_failed = False self.authenticated = False self.__timeout = 10 self.__api_version = "" self.__server = self.__config_manager.nextcloud_endpoint self.__username = self.__config_manager.nextcloud_username self.__prune_threshold = self.__config_manager.nextcloud_prune_threshold if os.path.exists(self.CA_CHAIN_FILE): logging.info("Using SSL CA chain file at {}".format(self.CA_CHAIN_FILE)) self.verify: str | bool = self.CA_CHAIN_FILE else: self.verify = True self.__headers = { "User-Agent": self.USER_AGENT, "Cache-Control": "no-cache", } def init_auth(self) -> None: """Initialise Nextcloud authentication details from the Secret Service.""" thread = Thread(target=self.__init_secrets) thread.daemon = True thread.start() def start_login( self, server_uri: str, window: Gtk.Window ) -> tuple[LoginRequestResult, Optional[str], Optional[str]]: """Initiate a new login. :param str server_uri: Server instance URI :param Gtk.Window window: Main window :return: tuple with LoginRequestResult before endpoint URI and auth token (or Nones on failures) :rtype: tuple[LoginRequestResult, Optional[str], Optional[str]] """ uri = "{}{}".format(server_uri, self.LOGIN_ENDPOINT) try: res = requests.post( uri, headers=self.__headers, verify=self.verify, timeout=self.__timeout, ) except requests.exceptions.SSLError as e: if self.exception_is_for_self_signed_certificate(e): logging.warning("Login found self-signed certificate: {} for {}".format(e, uri)) return (LoginRequestResult.FAILURE_SELF_SIGNED_SSL, None, None) elif self.get_ssl_verification_error(e) is not None: logging.warning( "Login POST encountered SSL certificate problem: {} for {}".format(e, uri) ) return (LoginRequestResult.FAILURE_CERTIFICATE, None, None) else: logging.warning("Login POST request error: {} for {}".format(e, uri)) return (LoginRequestResult.FAILURE_GENERIC, None, None) except Exception as e: logging.warning("Login POST request error: {} for {}".format(e, uri)) return (LoginRequestResult.FAILURE_GENERIC, None, None) if res is None: logging.warning("Login POST response is null") return (LoginRequestResult.FAILURE_GENERIC, None, None) if res.status_code != 200: logging.warning( "Login POST request failed with status code: {}".format(res.status_code) ) return (LoginRequestResult.FAILURE_GENERIC, None, None) try: response = res.json() except requests.exceptions.JSONDecodeError as e: logging.warning("Failed to decode login request to JSON: {} for {}".format(e, res.text)) return (LoginRequestResult.FAILURE_GENERIC, None, None) # TODO change this to not need the window passed in def open_url_in_browser(window: Gtk.Window, response: dict) -> None: Gtk.show_uri(window, response["login"], Gdk.CURRENT_TIME) GLib.idle_add(open_url_in_browser, window, response) return (LoginRequestResult.SUCCESS, response["poll"]["endpoint"], response["poll"]["token"]) def check_endpoint_for_auth_token(self, endpoint: str, token: str) -> tuple[bool, bool]: """Poll endpoint for authorisation success. :param str endpoint: Endpoint URI :param str token: Request token :return: Whether authenticated and whether auth. storage succeeded :rtype: tuple[bool, bool] """ data = {"token": token} try: res = requests.post( endpoint, headers=self.__headers, data=data, verify=self.verify, timeout=self.__timeout, ) except Exception: return (False, False) if res.status_code != 200: return (False, False) response = res.json() stored = self.__store_password(response["loginName"], response["appPassword"]) if stored: self.__authenticated_and_password_stored( response["server"], response["loginName"], response["appPassword"] ) else: self.__handle_secret_service_failure(emit=False) return (True, stored) def sign_out(self) -> None: """Clear credentials." """ logging.debug("Nextcloud signout") self.__clear_password() self.reset_prune_threshold() def check_capabilities(self) -> None: """Check server API version.""" assert self.__username is not None assert self.__app_password is not None url = self.__server + "/" + self.CAPABILITIES_ENDPOINT headers = self.__headers.copy() headers["OCS-APIRequest"] = "true" headers["Accept"] = "application/json" try: res = requests.get( url, headers=headers, auth=(self.__username, self.__app_password), verify=self.verify, timeout=self.__timeout, ) except Exception as e: logging.warning(f"GET request for capabilities failed: {e}") return response = self.__parse_get_response_to_json(res, "capabilities") if response is None: return try: capabilities = response["ocs"]["data"]["capabilities"]["notes"] api_version = capabilities["api_version"] app_version = capabilities["version"] except KeyError: logging.warning( "Couldn't access version elements in server capabilities response. " "Is the Nextcloud Notes app installed within Nextcloud?" ) GLib.idle_add(self.emit, "notes-capability-missing") return logging.info( f"Running against Nextcloud Notes server app v{app_version} " f"with API versions: {', '.join(api_version)}" ) if self.EXPECTED_API_VERSION not in api_version: logging.warning( f"Expected API version {self.EXPECTED_API_VERSION} not found in server API " f"versions ({', '.join(api_version)})" ) self.__api_version = max(api_version) GLib.idle_add(self.emit, "api-check-finished") def fetch_settings(self) -> None: """Fetch settings from server.""" res = self.__request_get("settings", {}, self.__timeout) if res is None: logging.warning("Couldn't fetch settings from server") return response = self.__parse_get_response_to_json(res, "settings") if response is None: return try: file_suffix = response["fileSuffix"] except KeyError: logging.warning("Couldn't access file suffix setting in server response") return file_suffix = file_suffix.strip() file_suffix = file_suffix.strip(".") GLib.idle_add(self.emit, "settings-fetched", file_suffix) def get_notes(self) -> SyncResult: """Fetch notes from server. :return: Sync result object :rtype: SyncResult """ params = {} if self.__prune_threshold > 0: params["pruneBefore"] = self.__prune_threshold # Bump network timeout for initial imports, long breaks between syncs and timestamp resets two_weeks_ago = (datetime.datetime.now() - datetime.timedelta(weeks=2)).timestamp() if self.__prune_threshold > two_weeks_ago: timeout = self.__timeout else: # Two minutes, based on default 10 second timeout timeout = self.__timeout * 12 reason = "Over two weeks since sync" if self.__prune_threshold else "Fetching all notes" logging.info( f"{reason}, using longer network timeout for potential longer sync ({timeout:.2f}s)" ) res = self.__request_get("notes", params, timeout) ret = SyncResult.from_requests_response(res) if not ret.success: return ret if res and "Last-Modified" in res.headers: dt = parsedate_to_datetime(res.headers["Last-Modified"]) self.__prune_threshold = int(dt.timestamp()) return ret def update_note(self, note: Note) -> ContentPushSyncResult: """Update a note. :param Note note: Note to update :return: Result of operation :rtype: ContentPushSyncResult """ headers = {"If-Match": '"' + note.etag + '"'} headers.update(self.__headers) path = f"notes/{note.remote_id}" sent_content = note.content data = { "title": note.title, "content": sent_content, "category": note.category, "favorite": 1 if note.favourite else 0, } res = self.__request_put(path, headers, data) return ContentPushSyncResult.from_requests_response(res, sent_content) def create_note(self, note: Note) -> ContentPushSyncResult: """Create a note. :param Note note: Note to create :return: Result of operation :rtype: ContentPushSyncResult """ path = "notes" sent_content = note.content data = {"title": note.title, "content": sent_content, "category": note.category} res = self.__request_post(path, data) return ContentPushSyncResult.from_requests_response(res, sent_content) def delete_note(self, note: Note) -> SyncResult: """Delete a note. :param Note note: Note to delete :return: Result of operation :rtype: SyncResult """ path = "notes/{}".format(note.remote_id) res = self.__request_delete(path) return SyncResult.from_requests_response(res) def get_attachment(self, attachment: Attachment) -> Optional[bytes]: """Fetch an attachment from the server. :param Attachment attachment: Attachment :return: Data :rtype: bytes, optional """ params = {} params["path"] = attachment.path res = self.__request_get(f"attachment/{attachment.note_remote_id}", params, self.__timeout) if not res or res.status_code != 200: return None else: return res.content def reset_prune_threshold(self) -> None: """Reset the sync threshold.""" self.__prune_threshold = 0 self.__config_manager.nextcloud_prune_threshold = self.__prune_threshold @GObject.Property(type=str) def server(self) -> str: return self.__server @server.setter def set_server(self, value: str) -> None: value = value.strip() value = GLib.uri_escape_string(value, None, True) value = value.strip("/") self.__server = value @GObject.Property(type=bool, default=False) def authenticated(self) -> bool: return self.__authenticated @authenticated.setter def set_authenticated(self, value: bool) -> None: self.__authenticated = value @GObject.Property(type=int) def prune_threshold(self) -> int: return self.__prune_threshold @GObject.Property(type=bool, default=False) def secret_service_failed(self) -> bool: return self.__secret_service_failed @GObject.Property(type=int) def timeout(self) -> int: return self.__timeout @timeout.setter def set_timeout(self, value: int) -> None: self.__timeout = value @GObject.Property(type=str) def api_version(self) -> str: return self.__api_version @api_version.setter def set_api_version(self, value: str) -> None: self.__api_version = value def __init_secrets(self) -> None: # Doing this sync fetch works around some type of libsecret flatpak issue (... so we may # as well use the result) self.__app_password = self.__fetch_password() if self.__app_password is None: self.emit("missing-password") else: self.__check_setup() logging.debug("Nextcloud sync setup: {}".format(self.__authenticated)) def __check_setup(self) -> None: if ( self.__server.strip() != "" and self.__username.strip() != "" and self.__app_password is not None ): self.authenticated = True self.emit("ready", False) def __authenticated_and_password_stored( self, endpoint: str, username: str, app_password: str ) -> None: self.__server = endpoint self.__username = username self.__app_password = app_password self.__config_manager.nextcloud_endpoint = self.__server self.__config_manager.nextcloud_username = self.__username self.reset_prune_threshold() self.authenticated = True GLib.idle_add(self.emit, "ready", True) logging.debug("Nextcloud login successful") def __request_get(self, path: str, params: dict, timeout: float) -> Optional[requests.Response]: assert self.__username is not None assert self.__app_password is not None url = self.__get_url(path) try: return requests.get( url, headers=self.__headers, auth=(self.__username, self.__app_password), params=params, verify=self.verify, timeout=timeout, ) except Exception as e: logging.warning(f"GET request failed: {e}") return None def __request_put(self, path: str, headers: dict, data: dict) -> Optional[requests.Response]: assert self.__username is not None assert self.__app_password is not None url = self.__get_url(path) try: return requests.put( url, headers=headers, auth=(self.__username, self.__app_password), data=data, verify=self.verify, timeout=self.__timeout, ) except Exception as e: logging.warning(f"PUT request failed: {e}") return None def __request_post( self, path: str, data: dict, files: Optional[dict] = None ) -> Optional[requests.Response]: assert self.__username is not None assert self.__app_password is not None url = self.__get_url(path) try: return requests.post( url, headers=self.__headers, auth=(self.__username, self.__app_password), data=data, files=files, verify=self.verify, timeout=self.__timeout, ) except Exception as e: logging.warning(f"POST request failed: {e}") return None def __request_delete(self, path: str) -> Optional[requests.Response]: assert self.__username is not None assert self.__app_password is not None url = self.__get_url(path) try: return requests.delete( url, headers=self.__headers, auth=(self.__username, self.__app_password), verify=self.verify, timeout=self.__timeout, ) except Exception as e: logging.warning(f"DELETE request failed: {e}") return None def __get_url(self, path: str) -> str: endpoint = self.ENDPOINT_V_1_4 if "attachment" in path else self.ENDPOINT_V_1_0 return self.__server + "/" + endpoint + path def __store_password(self, login: str, password: str) -> bool: success = False try: item_id = "org.gnome.World.Iotas: {}".format(login) success = Secret.password_store_sync( self.SECRET_SCHEMA, self.SECRET_ATTRIBUTES, Secret.COLLECTION_DEFAULT, item_id, password, None, ) except Exception as e: logging.error(f"Failed to store password: {e}") return success def __fetch_password(self) -> Optional[str]: pwd = None try: pwd = Secret.password_lookup_sync(self.SECRET_SCHEMA, self.SECRET_ATTRIBUTES, None) except GLib.Error as e: if "ServiceUnknown" in e.message: self.__handle_secret_service_failure(emit=True) else: logging.error(f"Failed to fetch password: {e}") return pwd def __handle_secret_service_failure(self, emit: bool): self.__secret_service_failed = True msg = ( "Could not connect with the Secret Service. Without the service Nextcloud " "authentication details cannot be stored. Look into GNOME Keyring. Restart " "the app to try again." ) logging.warning(msg) if emit: self.emit("secret-service-failure") def __clear_password(self) -> None: logging.debug("Clearing Nextcloud credentials") self.authenticated = False self.__app_password = None try: Secret.password_clear_sync(self.SECRET_SCHEMA, self.SECRET_ATTRIBUTES, None) except Exception as e: logging.warning(f"Failed to clear password: {e}") def __parse_get_response_to_json( self, res: Optional[requests.Response], purpose: str ) -> Optional[dict]: if res is None: logging.warning(f"Response for {purpose} is null") return None if res.status_code != 200: logging.warning( "Request for {} failed with status code: {}".format(purpose, res.status_code) ) return None try: response = res.json() except JSONDecodeError as e: logging.warning( "Failed to decode {} request to JSON: {} for {}".format(purpose, e, res.text) ) return None return response @staticmethod def exception_is_for_self_signed_certificate(e: requests.exceptions.SSLError) -> bool: ssl_verification_error = NextcloudSyncWorker.get_ssl_verification_error(e) if ssl_verification_error is None: return False return ( ssl_verification_error.verify_code in NextcloudSyncWorker.OPENSSL_SELF_SIGNED_CERTIFICATE_ERROR_CODES ) @staticmethod def get_ssl_verification_error( e: requests.exceptions.SSLError, ) -> Optional[SSLCertVerificationError]: # Get the requests SSLError if type(e.args) is not tuple or len(e.args) != 1: return None max_retry_error = e.args[0] ssl_error = max_retry_error.reason # Get the ssl.SSLCertVerificationError if type(ssl_error.args) is not tuple or len(ssl_error.args) != 1: return None if not isinstance(ssl_error.args[0], SSLCertVerificationError): return None return ssl_error.args[0] iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/nextcloud_sync_worker_configuration.py000066400000000000000000000027001507102636600314530ustar00rootroot00000000000000from abc import ABC, abstractmethod class NextcloudSyncWorkerConfiguration(ABC): """Nextcloud sync worker configuration interface.""" @property @abstractmethod def nextcloud_endpoint(self) -> str: """Get Nextcloud endpoint. :return: Endpoint :rtype: str """ raise NotImplementedError() @nextcloud_endpoint.setter @abstractmethod def nextcloud_endpoint(self, value: str) -> None: """Set Nextcloud endpoint. :param str value: New value """ raise NotImplementedError() @property @abstractmethod def nextcloud_username(self) -> str: """Get Nextcloud username. :return: Username :rtype: str """ raise NotImplementedError() @nextcloud_username.setter @abstractmethod def nextcloud_username(self, value: str) -> None: """Set Nextcloud username. :param str value: New value """ raise NotImplementedError() @property @abstractmethod def nextcloud_prune_threshold(self) -> int: """Get Nextcloud prune threshold. :return: Threshold :rtype: int """ raise NotImplementedError() @nextcloud_prune_threshold.setter @abstractmethod def nextcloud_prune_threshold(self, value: int) -> None: """Set Nextcloud prune threshold. :param int value: New value """ raise NotImplementedError() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/note.py000066400000000000000000000400401507102636600230360ustar00rootroot00000000000000from __future__ import annotations from gi.repository import GObject import logging import re import time from typing import Optional, Self from iotas.text_utils import sanitise_path class DirtyFields: title = False content = False excerpt = False favourite = False category = False etag = False remote_id = False last_modified = False locally_deleted = False read_only = False def empty(self) -> bool: """Whether no fields have been modified. :return: Whether there are modifications :rtype: bool """ return ( not self.title and not self.content and not self.excerpt and not self.favourite and not self.category and not self.etag and not self.remote_id and not self.last_modified and not self.locally_deleted and not self.read_only ) class _RecentETagList: """ List of recent known ETags. """ SIZE = 50 def __init__(self) -> None: self.__tags: list[str] = [] def add(self, tag: str) -> None: """Add an ETag. :param str tag: ETag """ if not tag.strip(): return self.__trim() self.__tags.append(tag) def contains(self, tag: str) -> bool: """Check if ETag is in list. :param str tag: ETag :return: Whether in list :rtype: bool """ return tag in self.__tags def __trim(self) -> None: while len(self.__tags) >= self.SIZE: del self.__tags[0] class Note(GObject.Object): __gsignals__ = { "remote-content-update": (GObject.SignalFlags.RUN_FIRST, None, ()), } EXCERPT_LENGTH = 200 EXCERPT_LINE_SEPARATOR = " " def __init__(self, new_note: bool = False) -> None: super().__init__() self.__title = "" self.__excerpt = "" self.__content: Optional[str] = None self.__category = "" self.__favourite = False self.__id = -1 self.__last_modified = 0 self.__read_only = False self.__dirty = False self.__dirty_while_saving = False self.__server_sanitised_title: Optional[str] = None self.__etag = "" self.__remote_id = -1 self.__title_is_top_line = new_note self.__saving = False self.__locally_deleted = False self.__handling_conflict = False self.__recent_tags = _RecentETagList() def duplicate(self) -> Self: """Duplicate note. :return: Duplicate note :rtype: Self """ n = Note() n.title = self.title n.excerpt = self.excerpt n.content = self.content n.favourite = self.favourite n.category = self.category return n def flag_changed(self, update_last_modified: bool = True) -> None: """Flag that the note has changed. dirty, last_modified and dirty_while_saving will be updated as applicable. """ if not self.dirty: self.dirty = True if update_last_modified: self.last_modified = int(time.time()) if self.saving: self.dirty_while_saving = True def regenerate_excerpt(self) -> bool: """Regenerates the excerpt from the content. :return: Whether the excerpt has changed :rtype: bool """ if self.__content is None: logging.warning( "Can't generate excerpt without content populated ({})".format(self.__title) ) return False new_excerpt = self.__content.strip() if new_excerpt != "": # Remove any heading markdown before first line new_excerpt = re.sub(r"^#* ", "", new_excerpt).strip() title = self.__title.strip() if len(title) and new_excerpt.startswith(title): # Remove title from start of content new_excerpt = new_excerpt[len(title) :] new_excerpt = re.sub(r"^\s*[-*+] \[ \]", "☐", new_excerpt, flags=re.MULTILINE) new_excerpt = re.sub(r"^\s*[-*+] \[x\]", "☑", new_excerpt, flags=re.MULTILINE) new_excerpt = re.sub(r"^\s*[-*+] (?![-*+[])", "• ", new_excerpt, flags=re.MULTILINE) new_excerpt = new_excerpt.replace("\n", self.EXCERPT_LINE_SEPARATOR).strip() if len(new_excerpt) > self.EXCERPT_LENGTH: new_excerpt = new_excerpt[: self.EXCERPT_LENGTH] changed = new_excerpt != self.excerpt if changed: self.excerpt = new_excerpt return changed def repopulate_meta_from_sync_update(self, update_dict: dict) -> None: """Repopulate note metadata from update over REST API JSON. :param dict update_dict: Nextcloud Notes API JSON """ self.__last_modified = update_dict["modified"] self.etag = update_dict["etag"] self.__remote_id = update_dict["id"] # Handle title and category updates from sanitisation on server side if self.title != update_dict["title"]: if self.title_is_top_line: self.server_sanitised_title = update_dict["title"] else: self.title = update_dict["title"] if self.category != update_dict["category"]: self.category = update_dict["category"] def update_from_remote_sync(self, note_dict: dict) -> DirtyFields: """Update from remote sync JSON dict and flag which fields are updated. :param dict note_dict: Nextcloud Notes API JSON :return: Which fields were updated :rtype: DirtyFields """ f = DirtyFields() if self.__last_modified != note_dict["modified"]: self.last_modified = note_dict["modified"] f.last_modified = True if self.__etag != note_dict["etag"]: self.etag = note_dict["etag"] f.etag = True if self.__read_only != note_dict["readonly"]: self.read_only = note_dict["readonly"] f.read_only = True if self.__favourite != note_dict["favorite"]: self.favourite = note_dict["favorite"] f.favourite = True if self.__category != note_dict["category"]: self.category = note_dict["category"] f.category = True if self.__title != note_dict["title"]: self.title = note_dict["title"] f.title = True if "ignore-content" not in note_dict and self.__content != note_dict["content"]: self.content = note_dict["content"] f.content = True # Always called on UI thread self.emit("remote-content-update") if (f.title or f.content) and self.content: self.regenerate_excerpt() f.excerpt = True return f def update_title_from_top_line(self) -> None: """Update the title from the top line of the content.""" if not self.__title_is_top_line: return if self.__content is not None and self.__content.strip() != "": lines = self.__content.strip().split("\n") title = lines[0].strip() title = title.strip("#") title = title.strip() title = sanitise_path(title) if len(title) > 200: title = title[:200] self.title = title def identical_excepting_sync_meta(self, note2: Note) -> bool: """Check whether notes are identical, apart from sync meta fields. :param Note note2: Note to compare to :return: Whether matching :rtype: bool """ return self.identical_non_sync_meta(note2) and self.content == note2.content def identical_to(self, note2: Note) -> bool: """Check whether notes are identical. :param Note note2: Note to compare to :return: Whether identical :rtype: bool """ return ( self.identical_excepting_sync_meta(note2) and self.last_modified == note2.last_modified and self.dirty == note2.dirty and self.etag == note2.etag ) def identical_non_sync_meta(self, note2: Note) -> bool: """Check whether notes have identical meta fields, excluding sync meta. :param Note note2: Note to compare to :return: Whether matching :rtype: bool """ return ( self.title == note2.title and self.favourite == note2.favourite and self.category == note2.category and self.locally_deleted == note2.locally_deleted and self.remote_id == note2.remote_id ) def etag_is_recent(self, etag: str) -> bool: """Check whether etag matches a known recent push. :param str etag: ETag to compare :return: Whether known :rtype: bool """ return self.__recent_tags.contains(etag) def to_nextcloud_dict(self) -> dict: """Create an API dict object for the note, for debugging. :return: Note as API results dict :rtype: dict """ return { "id": self.remote_id, "title": self.title, "content": self.content, "category": self.category, "favorite": self.favourite, "modified": self.last_modified, "etag": self.etag, "readonly": self.read_only, } @staticmethod def from_backup(meta: dict, content: str, include_sync_attributes: bool) -> Optional[Note]: """Create note from backup dict. :param dict meta: Backup metadata :param str content: Content :param bool include_sync_attributes: Whether to include sync attributes :return: The note or None on failure :rtype: Optional[Self] """ note = Note() try: note.title = meta["Title"] note.content = content note.regenerate_excerpt() note.category = meta["Category"] note.favourite = meta["Favourite"] note.last_modified = meta["LastModified"] note.locally_deleted = meta["LocallyDeleted"] note.dirty = meta["Dirty"] if include_sync_attributes: note.etag = meta["ETag"] note.remote_id = meta["RemoteId"] except KeyError: return None return note @staticmethod def from_nextcloud(note_dict: dict) -> Note: """Create note from dict originating from REST API JSON. :param dict note_dict: Nextcloud Notes API JSON :return: The note :rtype: Self """ note = Note() note.title = note_dict["title"] note.content = note_dict["content"] note.regenerate_excerpt() note.category = note_dict["category"] note.favourite = note_dict["favorite"] note.last_modified = note_dict["modified"] note.etag = note_dict["etag"] note.remote_id = note_dict["id"] note.read_only = note_dict["readonly"] return note @GObject.Property(type=str, default="") def title(self) -> str: return self.__title @title.setter def set_title(self, value: str) -> None: self.__title = value self.__server_sanitised_title = None @GObject.Property(type=str, default="") def excerpt(self) -> str: return self.__excerpt @excerpt.setter def set_excerpt(self, value: str) -> None: self.__excerpt = value @GObject.Property(type=str) def content(self) -> Optional[str]: return self.__content @content.setter def set_content(self, value: str) -> None: self.__content = value @GObject.Property(type=bool, default=False) def content_loaded(self) -> bool: """Whether the note's contents are populated. :return: Whether populated :rtype: bool """ return self.__content is not None @GObject.Property(type=bool, default=False) def favourite(self) -> bool: return self.__favourite @favourite.setter def set_favourite(self, value: bool) -> None: self.__favourite = value @GObject.Property(type=str) def category(self) -> str: return self.__category @category.setter def set_category(self, value: str) -> None: self.__category = value @GObject.Property(type=bool, default=False) def has_id(self) -> bool: """Whether the note has an id (as a result of being persisted to the database). :return: Whether the note has been persisted to the database :rtype: bool """ return self.__id != -1 @GObject.Property(type=int, default=-1) def id(self) -> int: return self.__id @id.setter def set_id(self, value: int) -> None: self.__id = value @GObject.Property(type=int, default=0) def last_modified(self) -> int: return self.__last_modified @last_modified.setter def set_last_modified(self, value: int) -> None: self.__last_modified = value @GObject.Property(type=bool, default=False) def read_only(self) -> bool: return self.__read_only @read_only.setter def set_read_only(self, value: bool) -> None: self.__read_only = value @GObject.Property(type=bool, default=False) def dirty(self) -> bool: return self.__dirty @dirty.setter def set_dirty(self, value: bool) -> None: self.__dirty = value @GObject.Property(type=bool, default=False) def dirty_while_saving(self) -> bool: return self.__dirty_while_saving @dirty_while_saving.setter def set_dirty_while_saving(self, value: bool) -> None: self.__dirty_while_saving = value @GObject.Property(type=bool, default=False) def saving(self) -> bool: return self.__saving @saving.setter def set_saving(self, value: bool) -> None: self.__saving = value @GObject.Property(type=bool, default=False) def locally_deleted(self) -> bool: return self.__locally_deleted @locally_deleted.setter def set_locally_deleted(self, value: bool) -> None: self.__locally_deleted = value @GObject.Property(type=bool, default=False) def handling_conflict(self) -> bool: return self.__handling_conflict @handling_conflict.setter def set_handling_conflict(self, value: bool) -> None: self.__handling_conflict = value @GObject.Property(type=str, default="") def server_sanitised_title(self) -> Optional[str]: return self.__server_sanitised_title @server_sanitised_title.setter def set_server_sanitised_title(self, value: str) -> None: self.__server_sanitised_title = value @GObject.Property(type=str, default="") def etag(self) -> str: return self.__etag @etag.setter def set_etag(self, value: str) -> None: self.__etag = value self.__recent_tags.add(value) @GObject.Property(type=int, default=-1) def remote_id(self) -> int: return self.__remote_id @remote_id.setter def set_remote_id(self, value: int) -> None: self.__remote_id = value @GObject.Property(type=bool, default=False) def has_remote_id(self) -> bool: """Whether the note has a remote id (as a result of being synced to a remote server). :return: Whether the note has, at some point, been synced to a remote server :rtype: bool """ return self.__remote_id >= 0 @GObject.Property(type=bool, default=False) def title_is_top_line(self) -> bool: return self.__title_is_top_line @title_is_top_line.setter def set_title_is_top_line(self, value: bool) -> None: self.__title_is_top_line = value @GObject.Property(type=bool, default=False) def new_and_empty(self) -> bool: """Check if the note is new and has no content or title. :return: Whether new and empty :rtype: bool """ return ( self.id == -1 and self.title.strip() == "" and self.content is not None and self.content.strip() == "" ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/note_database.py000066400000000000000000000441051507102636600246700ustar00rootroot00000000000000import itertools from typing import Optional from iotas.backup_storage import BackupStorage from iotas.category import Category, CategorySpecialPurpose from iotas.category_storage import CategoryStorage from iotas.database import Database, DbCursor from iotas.note import Note, DirtyFields class NoteDatabase(BackupStorage, CategoryStorage): def __init__(self, db_base: Database) -> None: self.__db_base = db_base def add_note(self, note: Note) -> None: """Add a new note to the database. :param Note note: Note to add """ with DbCursor(self.__db_base, True) as sql: result = sql.execute( "INSERT INTO note (title, content, last_modified, remote_id," " dirty, etag, locally_deleted, favourite," " category, excerpt, read_only)" "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ( note.title, note.content, note.last_modified, note.remote_id, note.dirty, note.etag, False, note.favourite, note.category, note.excerpt, note.read_only, ), ) note.id = result.lastrowid def populate_note_content(self, note: Note) -> None: """Load note content for provided note. :param Note note: Note to load for """ if note.content_loaded: return if note.id < 0: return with DbCursor(self.__db_base) as sql: request = "SELECT content FROM note WHERE rowid=?" result = sql.execute(request, (note.id,)) row = result.fetchone() if row is not None: note.content = row[0] def create_duplicate_note(self, note: Note, reason: str) -> Note: """Create a duplicate note with a prefixed title. :param Note note: The note to duplicate :param str reason: The reason for the duplication, which is prefixed on the title """ new_note = note.duplicate() new_note.title = f"{reason} - {note.title}" new_note.flag_changed() self.add_note(new_note) return new_note def delete_all_clean_synced_notes(self) -> None: """Delete all notes which are on the server and don't have local updates.""" with DbCursor(self.__db_base, True) as sql: sql.execute("DELETE FROM note WHERE remote_id <> -1 AND DIRTY=0") def delete_note(self, note_id: int) -> None: """Delete a note. :param int note_id: The note identifier (row id, not remote id) """ with DbCursor(self.__db_base, True) as sql: sql.execute("DELETE FROM note WHERE rowid=?", (note_id,)) def get_all_notes(self, load_content: bool = False) -> list[Note]: """Fetch all notes from the database. :param bool load_content: Whether to load the content for each note :return: List of notes :rtype: list[Note] """ with DbCursor(self.__db_base) as sql: request = ( "SELECT title, excerpt, last_modified, favourite, category, remote_id," " dirty, etag, rowid, locally_deleted, read_only" ) if load_content: request += ", content" request += " FROM note" result = sql.execute(request) return [NoteDatabase.db_row_to_note(row) for row in result] def get_all_categories(self) -> list[Category]: """Fetch all categories from the database. :return: List of categories :rtype: list[Category] """ with DbCursor(self.__db_base) as sql: request = ( "SELECT category, count() AS count " "FROM note " "WHERE locally_deleted=0 " "GROUP BY category " "ORDER BY LOWER(category)" ) result = sql.execute(request) categories = [NoteDatabase.db_row_to_category(row) for row in result] total = 0 uncategorised_found = False for category in categories: total += category.note_count if category.name == Category.UNCATEGORISED_TITLE: uncategorised_found = True all_category = Category(Category.ALL_TITLE, total) all_category.special_purpose = CategorySpecialPurpose.ALL categories.insert(0, all_category) # Create an empty uncategorised entry if we don't have any uncategorised notes # (most commonly happening for new users) if not uncategorised_found: uncategorised_category = Category(Category.UNCATEGORISED_TITLE, 0) uncategorised_category.special_purpose = CategorySpecialPurpose.UNCATEGORISED categories.insert(1, uncategorised_category) return categories def get_all_notes_count(self, include_locally_deleted: bool = True) -> int: """Fetch the number of notes in the database. :param bool include_locally_deleted: Whether to include locally deleted notes in the count :return: The count :rtype: int """ with DbCursor(self.__db_base) as sql: request = "SELECT count() FROM note" if not include_locally_deleted: request += " locally_deleted=0" result = sql.execute(request) row = result.fetchone() return row[0] def get_notes_by_ids(self, db_ids: list[int]) -> list[Note]: """Fetch notes from the database by db ids. :param list[int] db_ids: Database id of the note :return: The notes, in the same order as the provided ids :rtype: list[Note] """ if len(db_ids) == 0: return [] with DbCursor(self.__db_base) as sql: request = ( "SELECT title, excerpt, last_modified, favourite, category, remote_id," " dirty, etag, rowid, locally_deleted, content " f"FROM note WHERE id IN ({','.join(['?']*len(db_ids))})" ) result = sql.execute(request, db_ids) as_dict = {row[8]: NoteDatabase.db_row_to_note(row) for row in result} return [as_dict[note_id] for note_id in db_ids] def get_all_notes_remote_ids(self) -> list[int]: """Fetch remote ids for all remotely synced notes. :return: List of ids :rtype: list[int] """ with DbCursor(self.__db_base) as sql: request = "SELECT remote_id FROM note WHERE remote_id <> -1" result = sql.execute(request) return list(itertools.chain(*result)) def get_note_by_remote_id(self, remote_id: int) -> Optional[Note]: """Fetch note from the database by remote id. :param int remote_id: Remote id of the note :return: The note, or None :rtype: Optional[Note] """ with DbCursor(self.__db_base) as sql: request = ( "SELECT title, excerpt, last_modified, favourite, category, remote_id," " dirty, etag, rowid, locally_deleted, content " "FROM note WHERE remote_id=? " ) result = sql.execute(request, (remote_id,)) row = result.fetchone() if row is not None: i = NoteDatabase.db_row_to_note(row) return i return None def get_note_by_title(self, title: str) -> Optional[Note]: """Fetch note from the database by title. :param str title: Search title :return: The note, or None :rtype: Optional[Note] """ with DbCursor(self.__db_base) as sql: request = ( "SELECT title, excerpt, last_modified, favourite, category, remote_id," " dirty, etag, rowid, locally_deleted, content " "FROM note WHERE title=? " ) result = sql.execute(request, (title,)) row = result.fetchone() if row is not None: i = NoteDatabase.db_row_to_note(row) return i return None def get_note_failed_pushes(self, note: Note) -> Optional[str]: """Fetch note failed pushes from the database. :param Note note: The note :return: Failed pushes as JSON string, or None :rtype: str, optional """ with DbCursor(self.__db_base) as sql: request = "SELECT failed_pushes FROM note WHERE id = ?" result = sql.execute(request, (note.id,)) row = result.fetchone() if row is None: return None else: return row[0] def note_needs_update(self, remote_id: int, etag: str) -> bool: """Whether a note needs updating from a remote update. :param int remote_id: The remote id for the note :param str etag: The etag in the update :return: Whether an update is required :rtype: bool """ with DbCursor(self.__db_base) as sql: request = "SELECT 1 FROM note WHERE remote_id=? AND etag<>?" result = sql.execute( request, ( remote_id, etag, ), ) return result.fetchone() is not None def persist_note_category(self, note: Note) -> None: """Persist category field for note to database. :param Note note: Note to update """ with DbCursor(self.__db_base, True) as sql: sql.execute( "UPDATE note SET dirty=?, category=? WHERE rowid=?", (note.dirty, note.category, note.id), ) def persist_note_dirty(self, note: Note) -> None: """Persist dirty field for note to database. :param Note note: Note to update """ with DbCursor(self.__db_base, True) as sql: sql.execute( "UPDATE note SET dirty=? WHERE rowid=?", (note.dirty, note.id), ) def persist_note_editable(self, note: Note) -> None: """Save editable fields for provided note to the database. Updates title, content, category, excerpt, last_modified, favourite and dirty :param Note note: Note to update """ with DbCursor(self.__db_base, True) as sql: sql.execute( "UPDATE note " "SET title=?, content=?, excerpt=?," " last_modified=?, favourite=?, dirty=?, " " category=? " "WHERE rowid=?", ( note.title, note.content, note.excerpt, note.last_modified, note.favourite, note.dirty, note.category, note.id, ), ) def persist_note_favourite(self, note: Note) -> None: """Persist favourite field for note to database. :param Note note: Note to update """ with DbCursor(self.__db_base, True) as sql: sql.execute( "UPDATE note SET dirty=?, favourite=? WHERE rowid=?", (note.dirty, note.favourite, note.id), ) def persist_note_etag(self, note: Note) -> None: """Persist etag field for note to database. :param Note note: Note to update """ with DbCursor(self.__db_base, True) as sql: sql.execute( "UPDATE note SET etag=? WHERE rowid=?", (note.etag, note.id), ) def persist_note_locally_deleted(self, note: Note, value: bool) -> None: """Persist whether a note is locally deleted. :param Note note: The note to update :param bool value: The value to set """ with DbCursor(self.__db_base, True) as sql: sql.execute( "UPDATE note SET locally_deleted=?, dirty=1 WHERE rowid=?", (value, note.id), ) def persist_note_remote_meta_and_sanitisable_fields( self, note: Note, clear_dirty: bool ) -> None: """Persist remote metadata and server sanitisable fields to database for provided note. :param Note note: Note to update :param bool clear_dirty: Whether to clear the dirty flag """ with DbCursor(self.__db_base, True) as sql: request = "UPDATE note SET last_modified=?, remote_id=?, etag=?, title=?, category=?" request += ", failed_pushes=NULL" if clear_dirty: request += ", dirty=0" request += " WHERE rowid=?" sql.execute( request, ( note.last_modified, note.remote_id, note.etag, note.title, note.category, note.id, ), ) def persist_note_selective(self, note: Note, updated_fields: DirtyFields) -> None: """Persist local note based on remote changes. :param Note note: The note to update :param DirtyFields updated_fields: Which fields to update """ if updated_fields.empty(): return with DbCursor(self.__db_base, True) as sql: request = "UPDATE note SET" fields = [] if updated_fields.title: request += " title=?" fields.append(note.title) if updated_fields.content: if len(fields) > 0: request += "," request += " content=?" fields.append(note.content) if updated_fields.excerpt: if len(fields) > 0: request += "," request += " excerpt=?" fields.append(note.excerpt) if updated_fields.favourite: if len(fields) > 0: request += "," request += " favourite=?" fields.append(note.favourite) if updated_fields.category: if len(fields) > 0: request += "," request += " category=?" fields.append(note.category) if updated_fields.etag: if len(fields) > 0: request += "," request += " etag=?" fields.append(note.etag) if updated_fields.last_modified: if len(fields) > 0: request += "," request += " last_modified=?" fields.append(note.last_modified) if updated_fields.read_only: if len(fields) > 0: request += "," request += " read_only=?" fields.append(note.read_only) if updated_fields.remote_id: if len(fields) > 0: request += "," request += " remote_id=?" fields.append(note.remote_id) if updated_fields.locally_deleted: if len(fields) > 0: request += "," request += " locally_deleted=?" fields.append(note.locally_deleted) request += " WHERE id=?" fields.append(note.id) sql.execute(request, fields) def persist_note_failed_pushes(self, note: Note, failed_pushes: Optional[str]) -> None: """Persist note failed pushes to database. :param Note note: Note to update :param Optional[str] failed_pushes: Failed pushes, as JSON string """ with DbCursor(self.__db_base, True) as sql: sql.execute( "UPDATE note SET failed_pushes=? WHERE rowid=?", (failed_pushes, note.id), ) def search_notes(self, term: str, restrict_to: list[int] = [], sort: bool = False) -> list[int]: """Search the notes. :param str term: The search term :param list[int] restrict_to: Database ids for notes to restrict to :return: A list of ids for any matching notes :rtype: list[int] """ with DbCursor(self.__db_base) as sql: filters = [] search = term.replace('"', '""') search = search.replace("'", "''") request = "SELECT i.rowid FROM note_fts_idx i " if sort: request += " INNER JOIN note n ON i.rowid = n.id AND n.locally_deleted = 0 " request += " WHERE " if len(restrict_to) > 0: request += f" id IN ({','.join(['?']*len(restrict_to))}) AND" filters.extend(restrict_to) request += f" note_fts_idx MATCH '\"{search}\"*' " if sort: request += " ORDER BY last_modified DESC" result = sql.execute(request, filters) return list(itertools.chain(*result)) @staticmethod def db_row_to_note(row: tuple) -> Note: """Create Note from database row. :param tuple row: The database row :return: The note :rtype: Note """ i = Note() i.title = row[0] i.excerpt = row[1] i.last_modified = row[2] i.favourite = row[3] i.category = row[4] i.remote_id = row[5] i.dirty = row[6] i.etag = row[7] i.id = row[8] i.locally_deleted = row[9] i.read_only = row[10] if len(row) > 11: i.content = row[11] return i @staticmethod def db_row_to_category(row: tuple) -> Category: """Create Category from database row. :param tuple row: The database row :return: The category :rtype: Category """ i = Category(row[0], row[1]) if i.name == "": i.name = Category.UNCATEGORISED_TITLE i.special_purpose = CategorySpecialPurpose.UNCATEGORISED return i iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/note_list_model.py000066400000000000000000000154161507102636600252620ustar00rootroot00000000000000from gi.repository import Gtk, Gio import logging from typing import Any, Optional from iotas.category import Category from iotas.note import Note class NoteListModelBase(Gtk.SortListModel): def __init__(self) -> None: self.__store_note_id_map: dict[int, Note] = {} self.__store_remote_id_map: dict[int, Note] = {} self.__list_store = Gio.ListStore(item_type=Note) self.__sorter = Gtk.CustomSorter() self.invalidate_sort() super().__init__(model=self.__list_store, sorter=self.__sorter) def invalidate_sort(self) -> None: """Invalidate the sorter.""" self.__sorter.set_sort_func(NoteListModelBase.__sort_func) def add_notes(self, notes: list[Note]) -> None: """Add new notes to store. :param list[Note] notes: The notes to add """ for note in notes: self.__list_store.append(note) if note.id != -1: self.__store_note_id_map[note.id] = note else: logging.warning("add_notes seeing -1 note id") continue if note.has_remote_id: self.__store_remote_id_map[note.remote_id] = note def remove_notes(self, notes: list[Note]) -> None: """Remove notes from the store. :param list[Note] notes: The notes to remove """ for note in notes: for index in range(len(self.__list_store)): if note == self.__list_store[index]: self.__list_store.remove(index) break if note.id in self.__store_note_id_map: del self.__store_note_id_map[note.id] if note.has_remote_id and note.remote_id in self.__store_remote_id_map: del self.__store_remote_id_map[note.remote_id] def fetch_note_by_db_id(self, db_id: int) -> Optional[Note]: """Fetch a note by database id" :param int db_id: The database id of the note """ if db_id not in self.__store_note_id_map: return None return self.__store_note_id_map[db_id] def ensure_remote_map_entry(self, note: Note) -> None: """Ensure the provided note has an entry in the remote id to note map. :param Note note: The note """ if note.has_remote_id and note.remote_id not in self.__store_remote_id_map: self.__store_remote_id_map[note.remote_id] = note def fetch_note_by_remote_id(self, remote_id: int) -> Optional[Note]: """Fetch a note by remote id" :param int remote_id: The remote id of the note """ if remote_id not in self.__store_remote_id_map: return None return self.__store_remote_id_map[remote_id] @staticmethod def __sort_func(note1: Note, note2: Note, _data: Any) -> int: """Sort notes. :param Note note1: First note :param Note note2: Second note :param _data: Unused :return: -1 if note1 earlier, 1 if later, 0 unused :rtype: int """ if note1.favourite != note2.favourite: return -1 if note1.favourite else 1 return -1 if note1.last_modified > note2.last_modified else 1 class NoteListModelCategoryFiltered(Gtk.FilterListModel): def __init__(self, model: Gio.ListModel) -> None: self.__filter = Gtk.CustomFilter() self.__filter.set_filter_func(self.__filter_func) self.__category: Optional[Category] = None super().__init__(model=model, filter=self.__filter) def invalidate_filter(self, category: Category) -> None: """Invalidate the filter. :param Category: Category to display """ self.__category = category self.__filter.set_filter_func(self.__filter_func) def __filter_func(self, note: Note) -> bool: res = not note.locally_deleted if self.__category is not None: res = res and self.__category.includes_note(note) return res class NoteListModelFavourites(Gtk.FilterListModel): def __init__(self, model: Gio.ListModel) -> None: self.__filter = Gtk.CustomFilter() self.invalidate_filter() super().__init__(model=model, filter=self.__filter) def invalidate_filter(self) -> None: """Invalidate the filter.""" self.__filter.set_filter_func(NoteListModelFavourites.__filter_func) @staticmethod def __filter_func(note: Note) -> bool: """Filter for favourites. :param Note note: The note to filter """ return note.favourite class NoteListModelTimeFiltered(Gtk.FilterListModel): def __init__(self, model: Gio.ListModel) -> None: self.__filter = Gtk.CustomFilter() self.__time_min: Optional[int] = None self.__time_max: Optional[int] = None super().__init__(model=model, filter=self.__filter) def invalidate_filter( self, time_min: Optional[float] = None, time_max: Optional[float] = None ) -> None: """Invalidate the filter. :param Optional[float] time_min: Minimum date/time threshold timestamp :param Optional[float] time_max: Maximum date/time threshold timestamp """ if time_min is not None: self.__time_min = int(time_min) else: self.__time_min = None if time_max is not None: self.__time_max = int(time_max) else: self.__time_max = None self.__filter.set_filter_func(self.__filter_func) def __filter_func(self, note: Note) -> bool: if note.favourite: include = False else: if self.__time_min is not None: include = note.last_modified > self.__time_min else: include = True if self.__time_max is not None: include = include and note.last_modified <= self.__time_max return include class NoteListModelSearch(Gtk.FilterListModel): def __init__(self, model: Gio.ListModel) -> None: self.__filter = Gtk.CustomFilter() self.__filter.set_filter_func(self.__filter_func) self.__filter_to_ids: Optional[list[int]] = None super().__init__(model=model, filter=self.__filter) def invalidate(self, ids: Optional[list[int]]) -> None: """Invalidate filter, restricting by the provided note ids. :param Optional[list[int]] ids: The note ids (row primary key, not remote id) to be filtered by. """ self.__filter_to_ids = ids self.__filter.set_filter_func(self.__filter_func) def __filter_func(self, note: Note) -> bool: if note.locally_deleted: include = False elif not self.__filter_to_ids: include = False else: include = note.id in self.__filter_to_ids return include iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/note_manager.py000066400000000000000000000530311507102636600245340ustar00rootroot00000000000000from gi.repository import GObject, GLib from datetime import datetime, timedelta import json import logging from threading import Thread import time from typing import Optional from iotas.attachment_helpers import delete_attachments_for_note from iotas.category import Category from iotas.category_manager import CategoryManager from iotas.config_manager import ConfigManager from iotas.note import Note, DirtyFields from iotas.note_database import NoteDatabase from iotas.note_list_model import ( NoteListModelBase, NoteListModelCategoryFiltered, NoteListModelFavourites, NoteListModelTimeFiltered, NoteListModelSearch, ) from iotas.sync_result import ContentPushSyncResult, FailedPush class NoteManager(GObject.Object): __gtype_name__ = "NoteManager" __gsignals__ = { "initial-load-complete": (GObject.SignalFlags.RUN_FIRST, None, ()), "new-note-persisted": (GObject.SignalFlags.RUN_FIRST, None, ()), "sync-requested": (GObject.SignalFlags.RUN_FIRST, None, ()), } LOAD_ALL_NOTES_TOTAL_THRESHOLD = 50 LOAD_ALL_NOTES_LAST_TWO_MONTHS_THRESHOLD = 6 EDITING_NOTE_SAVE_INTERVAL = 1000 def __init__( self, db: NoteDatabase, category_manager: CategoryManager, ) -> None: super().__init__() self.__db = db self.__category_manager = category_manager self.__base_model = NoteListModelBase() self.__category_filtered_model = NoteListModelCategoryFiltered(self.__base_model) self.__favourites_model = NoteListModelFavourites(self.__category_filtered_model) self.__today_model = NoteListModelTimeFiltered(self.__category_filtered_model) self.__yesterday_model = NoteListModelTimeFiltered(self.__category_filtered_model) self.__week_model = NoteListModelTimeFiltered(self.__category_filtered_model) self.__month_model = NoteListModelTimeFiltered(self.__category_filtered_model) self.__last_month_model = NoteListModelTimeFiltered(self.__category_filtered_model) self.__older_notes_model: Optional[NoteListModelTimeFiltered] = None self.__search_model: Optional[NoteListModelSearch] = None self.__save_timeout_id = None self.__deleted_notes: list[Note] = [] def initiate_model_from_db(self) -> None: """Populate the models from the database.""" def add_to_model(notes: list[Note]) -> None: start_time = time.time() self.add_notes_to_model(notes) logging.debug("Add to model took %.2fs", time.time() - start_time) self.emit("initial-load-complete") def thread_do() -> None: start_time = time.time() notes = self.__db.get_all_notes() GLib.idle_add(add_to_model, notes) logging.debug("Get from DB took %.2fs", time.time() - start_time) thread = Thread(target=thread_do) thread.daemon = True thread.start() def initiate_older_notes_model(self) -> NoteListModelTimeFiltered: """Initiate the older notes model.""" self.__older_notes_model = NoteListModelTimeFiltered(self.__category_filtered_model) return self.__older_notes_model def initiate_search_model(self) -> NoteListModelSearch: """Initiate the search model.""" self.__search_model = NoteListModelSearch(self.__base_model) return self.__search_model def add_notes_to_model(self, notes: list[Note]) -> None: """Add new notes to model. :param list[Note] notes: The notes to add """ self.__base_model.add_notes(notes) def remove_notes_from_model(self, notes: list[Note]) -> None: """Remove notes from the model. :param list[Note] notes: The notes to remove """ self.__base_model.remove_notes(notes) def create_note(self, current_category: Category) -> Note: """Create a new note. :param Category category: The category currently active in the index """ note = Note(True) note.content = "" note.flag_changed() if current_category.special_purpose is None: note.category = current_category.name config_manager = ConfigManager.get_default() if config_manager.first_start: config_manager.first_start = False self.__category_manager.note_added(note.category) return note def delete_notes(self, notes: list[Note], provide_undo: bool) -> None: """Delete notes from the database and model. :param list[Note] notes: The notes :param bool provide_undo: Whether to provide ability to undo """ if provide_undo: for note in self.__deleted_notes: delete_attachments_for_note(note) self.__deleted_notes = [] for note in notes: if provide_undo and not note.content_loaded: self.__db.populate_note_content(note) note.locally_deleted = True if note.remote_id >= 0 and provide_undo: self.__db.persist_note_locally_deleted(note, True) else: self.__db.delete_note(note.id) self.remove_notes_from_model([note]) if provide_undo: self.__deleted_notes.append(note) self.__category_manager.note_deleted(note.category) # Delay attachment removal for local deletions, allowing for the undo period if not provide_undo: delete_attachments_for_note(note) def fetch_note_by_remote_id(self, remote_id: int) -> Optional[Note]: """Fetch a note by remote id" :param int remote_id: The remote id of the note """ return self.__base_model.fetch_note_by_remote_id(remote_id) def fetch_note_by_id(self, db_id: int) -> Optional[Note]: """Fetch a note by database id" :param int db_id: The database id of the note """ return self.__base_model.fetch_note_by_db_id(db_id) def invalidate_sort(self) -> None: """Invalidate the sorter.""" self.__base_model.invalidate_sort() def update_note_post_sync(self, note: Note, sync_result: ContentPushSyncResult) -> None: """Update note after remote sync. :param Note note: The note :param ContentPushSyncResult sync_result: The sync result """ note.dirty = False note.repopulate_meta_from_sync_update(sync_result.data) clear_dirty = not note.dirty_while_saving self.__db.persist_note_remote_meta_and_sanitisable_fields(note, clear_dirty) self.__base_model.ensure_remote_map_entry(note) def on_deletion_undo_elapsed(self) -> None: """Push local deletions to server and flush local queue upon undo lapse.""" had_remote = False for note in self.__deleted_notes: delete_attachments_for_note(note) if note.has_remote_id: had_remote = True self.__deleted_notes = [] if had_remote: self.emit("sync-requested") def undo_deletion(self) -> bool: """Undo a pending deletion. :return: Whether any notes were restored :rtype: bool """ if not self.__deleted_notes: return False for note in self.__deleted_notes: note.locally_deleted = False if note.remote_id >= 0: self.__db.persist_note_locally_deleted(note, False) else: note.id = -1 note.last_modified = int(time.time()) self.__db.add_note(note) self.add_notes_to_model([note]) self.__category_manager.note_added(note.category) self.__deleted_notes = [] return True def apply_deleted_notes_attachment_deletion(self) -> None: """Delete attachments for any locally deleted notes awaiting undo timeout. Ensures the removal of attachments for deleted notes if exiting before the undo toast has lapsed. """ for note in self.__deleted_notes: delete_attachments_for_note(note) self.__deleted_notes = [] def persist_note_while_editing(self, note: Note, update_excerpt: bool) -> None: """Persist note to database on separate thread while editing. :param Note note: The note :param bool update_excerpt: Whether to update excerpt """ if self.__save_timeout_id is None: if note.new_and_empty: return self.__save_timeout_id = GLib.timeout_add( self.EDITING_NOTE_SAVE_INTERVAL, self.__persist_note_on_thread, note, update_excerpt, ) def persist_note_sync( self, note: Note, allow_empty: bool = False, force_update_excerpt: bool = False ) -> None: """Persist note to database on main thread. :param Note note: The note :param bool allow_empty: Whether to store even when new and empty :param bool force_update_excerpt: Whether to update the excerpt, even if the note isn't "dirty" """ # Cancel any queued save if self.__save_timeout_id is not None: GLib.source_remove(self.__save_timeout_id) self.__save_timeout_id = None # Persist any changes update = note.dirty or force_update_excerpt if update and not note.handling_conflict and (allow_empty or not note.new_and_empty): note.regenerate_excerpt() new_note = not note.has_id self.__persist_note_to_db(note) if new_note: self.add_notes_to_model([note]) elif note.new_and_empty: self.__category_manager.note_deleted(note.category) else: self.apply_any_server_sanitised_title(note) note.handling_conflict = False def persist_note_category(self, note: Note, old_category: str) -> None: """Persist note category to database. :param Note note: The note :param str old_category: The old category """ def remote_sync_and_integrate_to_models(is_new: bool) -> None: if not is_new: self.emit("sync-requested") def thread_do() -> None: is_new = not note.has_id if not is_new: self.__db.persist_note_category(note) GLib.idle_add(remote_sync_and_integrate_to_models, is_new) thread = Thread(target=thread_do) thread.daemon = True thread.start() self.__category_manager.note_category_changed(old_category, note.category) def set_and_persist_favourite_for_notes(self, notes: list[Note], value: bool) -> bool: """Set and persist the favourite flag on the provided notes. :param list[Note] notes: The notes :param bool value: The new value :return: Whether any notes were updated :rtype: bool """ updates = False for note in notes: if note.favourite == value: continue updates = True note.favourite = value note.flag_changed(update_last_modified=False) self.__db.persist_note_favourite(note) return updates def search_notes(self, term: str, restrict_to: list[int] = [], sort: bool = False) -> list[int]: """Search database for notes with provided term. :param str term: The search term :param list[int] restrict_to: List of ids of notes to restrict to :param bool sort: Whether the results should be datetime sorted :return: A list of ids for any matching notes :rtype: list[int] """ return self.__db.search_notes(term, restrict_to, sort) def get_filtered_note_count(self, include_older_notes: bool) -> int: """Fetch filtered note count. :param bool include_older_notes: Whether to include the "older notes" model :return: The count :rtype: int """ if include_older_notes: return len(self.__category_filtered_model) else: count = 0 for model in ( self.__favourites_model, self.__today_model, self.__yesterday_model, self.__week_model, self.__month_model, self.__last_month_model, ): count += len(model) return count def update_filters( self, category: Category, older_notes_displayed: bool, check_older_notes: bool ) -> bool: """Update model filters. If told to check whether older notes should be loaded the total number of notes in the category and within the last two months are compared to thresholds to determine whether to show the section automatically or not. :param Category category: Current category :param bool older_notes_displayed: Whether the notes older than two months section has been displayed :param bool check_older_notes: Whether to check if notes older than two months should be loaded :return: Whether the filter was opened to notes older than two months :rtype: bool """ self.__category_filtered_model.invalidate_filter(category) self.__favourites_model.invalidate_filter() now = get_now() today_dt = now.replace(hour=0, minute=0, second=0, microsecond=0) today = today_dt.timestamp() yesterday = (today_dt - timedelta(days=1)).timestamp() monday = (today_dt - timedelta(days=now.weekday())).timestamp() start_of_month = now.replace(hour=0, minute=0, second=0, day=1).timestamp() start_of_last_month = get_start_of_last_month() self.__today_model.invalidate_filter(time_min=today) self.__yesterday_model.invalidate_filter(time_min=yesterday, time_max=today) self.__week_model.invalidate_filter(time_min=monday, time_max=yesterday) # If today is the first day of the month, or if the start of the week is earlier than the # start of the month don't show the rest of this month. Also ensures last month doesn't # have overlap content with the week. if today == start_of_month or monday < start_of_month: start_of_month = monday # Account for yesterday when setting rest of month end point month_end = yesterday if yesterday < monday else monday self.__month_model.invalidate_filter(time_min=start_of_month, time_max=month_end) # Account for yesterday when setting last month end point last_month_end = yesterday if yesterday < start_of_month else start_of_month self.__last_month_model.invalidate_filter( time_min=start_of_last_month, time_max=last_month_end ) older_loaded = False if check_older_notes and not older_notes_displayed and self.__should_load_older_notes(): if self.__older_notes_model is None: self.initiate_older_notes_model() older_loaded = True if older_notes_displayed or older_loaded: assert self.__older_notes_model is not None self.__older_notes_model.invalidate_filter(time_max=start_of_last_month) return older_loaded def filter_older_notes_by_date(self) -> None: """Filter older notes model to notes older than two months.""" if self.__older_notes_model is None: return start_of_last_month = get_start_of_last_month() self.__older_notes_model.invalidate_filter(time_max=start_of_last_month) def get_deleted_notes_pending_undo(self) -> list[Note]: """Fetch any notes queued for deletion. :return: The notes :rtype: list[Note] """ return self.__deleted_notes def set_deleted_notes_pending_undo(self, notes: list[Note]) -> None: """Set the notes queued for deletion. :param list[Note] notes: The notes """ self.__deleted_notes = notes def apply_any_server_sanitised_title(self, note: Note) -> None: """Persist to the database any sanitised title received from the server while editing. During note creation we ignore sanitised titles returning from the server (to avoid replacing a title which is being edited via the first buffer line with something the server returns). :param Note note: The note to work on """ if not note or note.server_sanitised_title is None: return logging.info("Applying sanitised title provided by server while creating note") note.title = note.server_sanitised_title note.server_sanitised_title = None changed_fields = DirtyFields() changed_fields.title = True self.__db.persist_note_selective(note, changed_fields) def get_note_failed_pushes(self, note: Note) -> list[FailedPush]: """Fetch any failed pushes for a note. :return: List of failed pushes :rtype: list[FailedPush] """ pushes_as_str = self.__db.get_note_failed_pushes(note) if not pushes_as_str: return [] try: pushes = json.loads(pushes_as_str) except json.JSONDecodeError as e: logging.warning(f"Failed to load failed pushes: {e}") return [] if type(pushes) is not list: logging.warning("Failed to load failed pushes: not a list") return [] ret = [] for push_json in pushes: if not set(push_json.keys()) == {"hash", "length", "timestamp"}: logging.warning(f"Invalid push: {push_json}") continue ret.append(FailedPush(push_json["hash"], push_json["length"], push_json["timestamp"])) return ret def add_failed_push(self, note: Note, push: FailedPush) -> None: """Add a failed push to the database. :param Note note: The note to add for :param FailedPush push: The failed push info """ pushes = self.get_note_failed_pushes(note) pushes.append(push) out = [] for push in pushes: out.append(push._asdict()) pushes_json = json.dumps(out) self.__db.persist_note_failed_pushes(note, pushes_json) @GObject.Property(type=NoteListModelBase, default=None) def base_model(self) -> NoteListModelBase: return self.__base_model @GObject.Property(type=NoteListModelFavourites, default=None) def favourites_model(self) -> NoteListModelFavourites: return self.__favourites_model @GObject.Property(type=NoteListModelTimeFiltered, default=None) def today_model(self) -> NoteListModelTimeFiltered: return self.__today_model @GObject.Property(type=NoteListModelTimeFiltered, default=None) def yesterday_model(self) -> NoteListModelTimeFiltered: return self.__yesterday_model @GObject.Property(type=NoteListModelTimeFiltered, default=None) def week_model(self) -> NoteListModelTimeFiltered: return self.__week_model @GObject.Property(type=NoteListModelTimeFiltered, default=None) def month_model(self) -> NoteListModelTimeFiltered: return self.__month_model @GObject.Property(type=NoteListModelTimeFiltered, default=None) def last_month_model(self) -> NoteListModelTimeFiltered: return self.__last_month_model @GObject.Property(type=NoteListModelTimeFiltered, default=None) def older_notes_model(self) -> Optional[NoteListModelTimeFiltered]: return self.__older_notes_model @GObject.Property(type=NoteListModelSearch, default=None) def search_model(self) -> Optional[NoteListModelSearch]: return self.__search_model def __persist_note_on_thread(self, note: Note, update_excerpt: bool) -> None: # Updated here (instead of in Note content setter) to reduce occurrence if update_excerpt: note.regenerate_excerpt() def remote_sync_and_integrate_new_note(note: Note, is_new: bool) -> None: if is_new: self.add_notes_to_model([note]) self.emit("new-note-persisted") self.emit("sync-requested") def thread_do() -> None: is_new = not note.has_id self.__persist_note_to_db(note) GLib.idle_add(remote_sync_and_integrate_new_note, note, is_new) self.__save_timeout_id = None thread = Thread(target=thread_do) thread.daemon = True thread.start() def __should_load_older_notes(self) -> bool: total_note_count = len(self.__category_filtered_model) last_two_month_count = self.get_filtered_note_count(include_older_notes=False) if total_note_count == last_two_month_count: return True elif len(self.__category_filtered_model) < self.LOAD_ALL_NOTES_TOTAL_THRESHOLD: return True elif last_two_month_count < self.LOAD_ALL_NOTES_LAST_TWO_MONTHS_THRESHOLD: return True else: return False def __persist_note_to_db(self, note: Note) -> None: if note.id == -1: self.__db.add_note(note) else: self.__db.persist_note_editable(note) def get_start_of_last_month() -> float: now = get_now() start_of_month_dt = now.replace(hour=0, minute=0, second=0, day=1) if start_of_month_dt.month > 1: start_of_last_month = start_of_month_dt.replace( month=start_of_month_dt.month - 1 ).timestamp() else: start_of_last_month = start_of_month_dt.replace( month=12, year=start_of_month_dt.year - 1 ).timestamp() return start_of_last_month def get_now() -> datetime: return datetime.now() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/ordered_list_utils.py000066400000000000000000000031151507102636600257720ustar00rootroot00000000000000import re from typing import Optional def check_line_for_ordered_list_item(line: str) -> Optional[re.Match]: """Check whether string representing line of text contains an ordered list item. :param str line: Line of text to search :return: Regular expression match object, if matched :rtype: re.Match, optional """ term = r"^(\s*)([a-zA-Z]{1}|[0-9]+)([\.\)]){1}[ ]+" return re.search(term, line) def calculate_ordered_list_index(reference: str, direction: int) -> Optional[str]: """Calculate an item in an ordered list sequence. :param str reference: The element to start from :param int direction: The direction, 1 or -1 :return: The item :rtype: str, optional """ sequence_next = None if reference.isdigit(): sequence_next = str(int(reference) + direction) if sequence_next == 0: sequence_next = None else: try: char_ord = ord(reference) except TypeError: pass else: if direction > 0 and reference.upper() != "Z": sequence_next = chr(char_ord + 1) elif direction < 0 and reference.upper() != "A": sequence_next = chr(char_ord - 1) return sequence_next def format_ordered_list_item(spacing: str, index: str, delimiter: str) -> str: """Generate string for list item. :param str spacing: Pre marker spacing :param str index: Item index :param str delimiter: The delimiter before the item text :return: The built string :rtype: str """ return f"{spacing}{index}{delimiter} " iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/outline_dialog.py000066400000000000000000000166451507102636600251050ustar00rootroot00000000000000from gi.repository import Adw, Gdk, Gio, GLib, GObject, Gtk from typing import Any from iotas.outline_generator import OutlineHeading from iotas.ui_utils import check_for_search_starting, check_for_open_first_result_shortcut class _HeadingRow(Adw.ActionRow): """Row for outline dialog headings. :param str label: Text :param int line: Markdown line number """ def __init__(self, label: str, line: int) -> None: super().__init__() self.set_title(label) self.line = line self.set_activatable(True) class _SizeReportingListbox(Gtk.ListBox): __gsignals__ = { "new-height": (GObject.SignalFlags.RUN_FIRST, None, (int,)), } def __init__(self) -> None: super().__init__() self.set_selection_mode(Gtk.SelectionMode.NONE) self.set_activate_on_single_click(True) self.add_css_class("boxed-list") def do_size_allocate(self, width: int, height: int, baseline: int) -> None: Gtk.ListBox.do_size_allocate(self, width, height, baseline) self.emit("new-height", height) @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/outline_dialog.ui") class OutlineDialog(Adw.Dialog): """Note outline dialog.""" __gtype_name__ = "OutlineDialog" __gsignals__ = { "jump-to": (GObject.SignalFlags.RUN_FIRST, None, (int,)), } _header_stack: Gtk.Stack = Gtk.Template.Child() _main_headerbar: Adw.HeaderBar = Gtk.Template.Child() _filter_headerbar: Adw.HeaderBar = Gtk.Template.Child() _stack: Gtk.Stack = Gtk.Template.Child() _spinner: Adw.Spinner = Gtk.Template.Child() _list: Gtk.ScrolledWindow = Gtk.Template.Child() _no_headings: Adw.StatusPage = Gtk.Template.Child() _filter_entry: Gtk.SearchEntry = Gtk.Template.Child() _zero_filtered: Adw.StatusPage = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__store = Gio.ListStore(item_type=OutlineHeading) self.__filter_term = "" self.__filter_model = Gtk.FilterListModel() self.__filter = Gtk.CustomFilter() self.__filter_model.set_filter(self.__filter) self.__filter.set_filter_func(self.__filter_heading) self.__filter_model.set_model(self.__store) self.__listbox = _SizeReportingListbox() self.__listbox.connect( "new-height", lambda _o, height: self.__update_for_list_height(height) ) self.__listbox.connect("row-activated", lambda _o, row: self.__activate_row(row)) self._list.set_child(self.__listbox) controller = Gtk.EventControllerKey() controller.connect("key-pressed", self.__on_listbox_key_pressed) self.__listbox.add_controller(controller) controller = Gtk.EventControllerKey() controller.connect("key-pressed", self.__on_entry_key_pressed) self._filter_entry.add_controller(controller) self.__listbox.bind_model(self.__filter_model, self.__create_row, None) def populate(self, headings: list[OutlineHeading], rtl: bool) -> None: """Populate headings. :param list[OutlineHeading] headings: Headings to populate :param bool rtl: Whether direction is right-to-left """ self._spinner.set_visible(False) if not headings: self._stack.set_visible_child(self._no_headings) return self.__rtl = rtl for heading in headings: self.__store.append(heading) self._main_headerbar.add_css_class("list-matched") self._stack.set_visible_child(self._list) self.__listbox.grab_focus() @Gtk.Template.Callback() def _on_close_clicked(self, _button: Gtk.Button) -> None: self.close() @Gtk.Template.Callback() def _on_filter_changed(self, entry: Gtk.Editable) -> None: if not list(self.__store): return self.__filter_term = entry.get_text() self.__filter.set_filter_func(self.__filter_heading) if self.__filter_term != "" and not list(self.__listbox): self._stack.set_visible_child(self._zero_filtered) elif self._stack.get_visible_child() != self._list: self._stack.set_visible_child(self._list) @Gtk.Template.Callback() def _on_stop_filter(self, entry: Gtk.Editable) -> None: entry.set_text("") self.__filter_term = "" self.__filter.set_filter_func(self.__filter_heading) self.__listbox.grab_focus() self._header_stack.set_visible_child(self._main_headerbar) def __on_listbox_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> bool: if self.__check_if_filter_starting(controller, keyval, state, clear=False): self.__show_filter() return Gdk.EVENT_STOP if not self.__listbox.is_focus(): return Gdk.EVENT_PROPAGATE if keyval in (Gdk.KEY_Down, Gdk.KEY_KP_Down): row = self.__listbox.get_row_at_index(0) row.grab_focus() return Gdk.EVENT_STOP elif keyval in (Gdk.KEY_Up, Gdk.KEY_KP_Up): count = len(list(self.__listbox)) row = self.__listbox.get_row_at_index(count - 1) row.grab_focus() return Gdk.EVENT_STOP return Gdk.EVENT_PROPAGATE def __on_entry_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> bool: if keyval in (Gdk.KEY_Down, Gdk.KEY_KP_Down): row = self.__listbox.get_row_at_index(0) row.grab_focus() return Gdk.EVENT_STOP elif check_for_open_first_result_shortcut(keyval, state): if list(self.__listbox): row = self.__listbox.get_row_at_index(0) self.__activate_row(row) return Gdk.EVENT_PROPAGATE def __update_for_list_height(self, height: int) -> None: window_height = self.get_root().get_height() threshold = window_height * 0.9 if height > threshold: height = threshold GLib.idle_add(self._stack.set_property, "height-request", height) def __show_filter(self) -> None: self._header_stack.set_visible_child(self._filter_headerbar) self._filter_entry.grab_focus() def __check_if_filter_starting( self, controller: Gtk.EventControllerKey, keyval: int, state: Gdk.ModifierType, clear: bool = True, ) -> bool: if not check_for_search_starting(controller, keyval, state): return False if clear: self._filter_entry.set_text("") if controller.forward(self._filter_entry.get_delegate()): return True return False def __create_row(self, heading: OutlineHeading, _user_data: Any) -> Gtk.Widget: row = _HeadingRow(heading.text, heading.line) if heading.indent_level: row.add_prefix padding = Gtk.Label() padding.set_text(" " * heading.indent_level) if self.__rtl: row.add_suffix(padding) else: row.add_prefix(padding) return row def __filter_heading(self, heading: OutlineHeading) -> bool: return self.__filter_term.lower() in heading.text.lower() def __activate_row(self, row: _HeadingRow) -> None: self.emit("jump-to", row.line) self.close() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/outline_generator.py000066400000000000000000000041121507102636600256160ustar00rootroot00000000000000from gi.repository import GLib, GObject from threading import Thread from typing import Callable import markdown_it from markdown_it.tree import SyntaxTreeNode from iotas.note import Note class OutlineHeading(GObject.Object): """Heading details for outline.""" def __init__(self, text: str, line: int, level: int) -> None: super().__init__() self.text = text self.line = line self.level = level self.indent_level = 0 class OutlineGenerator(GObject.Object): """Generate outline from note headings.""" def generate(self, note: Note, callback: Callable) -> None: """Generator outline for note. :param Note note: Note to render :param Callable callback: Method to call on completion """ def thread_do(): md = markdown_it.MarkdownIt("gfm-like") parser_tokens = md.parse(note.content) node = SyntaxTreeNode(parser_tokens) headings = [] levels = [] def add_children(in_node): if not in_node.is_root and in_node.type == "heading": level = len(in_node.markup) content = "" for child in in_node.children: content += child.content headings.append(OutlineHeading(content, in_node.map[0], level)) levels.append(level) else: for child in in_node.children: add_children(child) add_children(node) # Squash the indentation levels, eg. a note with only h1 and h5 headings will show # as first and second level indentation indentation = {} i = 0 for level in sorted(set(levels)): indentation[level] = i i += 1 for heading in headings: heading.indent_level = indentation[heading.level] GLib.idle_add(callback, headings) thread = Thread(target=thread_do) thread.daemon = True thread.start() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/pdf_exporter.py000066400000000000000000000013411507102636600245730ustar00rootroot00000000000000from abc import ABC, abstractmethod from typing import Callable from iotas.note import Note class PdfExporter(ABC): """PDF export interface.""" @abstractmethod def set_callbacks(self, finished_callback: Callable, error_callback: Callable) -> None: """Set functions to be called upon export result. :param Callable finished_callback: Finished callback :param Callable error_callback: Error callback """ raise NotImplementedError() @abstractmethod def export(self, note: Note, location: str) -> None: """Export PDF of note. :param Note note: Note to export :param str location: Destination location """ raise NotImplementedError() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/preferences_dialog.py000066400000000000000000000507071507102636600257240ustar00rootroot00000000000000from gettext import gettext as _ import gi gi.require_version("GtkSource", "5") from gi.repository import Adw, Gio, GLib, GObject, Gtk, GtkSource, Pango from iotas.config_manager import ConfigManager, HeaderBarVisibility from iotas.ui_utils import add_mouse_button_accel, is_likely_mobile_device from iotas.ui_utils import ComboRowHelper @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/preferences_dialog.ui") class PreferencesDialog(Adw.PreferencesDialog): __gtype_name__ = "PreferencesDialog" __gsignals__ = { "start-onboarding": (GObject.SignalFlags.RUN_FIRST, None, ()), } CLICKS_FOR_EXTENDED = 6 SHORTER_TOAST = 2 LONGER_TOAST = 5 _index_group: Adw.PreferencesGroup = Gtk.Template.Child() _editor_theme_combo: Adw.ComboRow = Gtk.Template.Child() _index_category_style_combo: Adw.ComboRow = Gtk.Template.Child() _editor_formatting_bar_visibility_combo: Adw.ComboRow = Gtk.Template.Child() _editor_header_bar_visibility_combo: Adw.ComboRow = Gtk.Template.Child() _editor_detect_syntax: Adw.SwitchRow = Gtk.Template.Child() _connect_sync_row: Adw.ActionRow = Gtk.Template.Child() _disconnect_sync_row: Adw.ActionRow = Gtk.Template.Child() _reset_database_row: Adw.ActionRow = Gtk.Template.Child() _debug_page: Adw.PreferencesPage = Gtk.Template.Child() _enable_render_view: Adw.SwitchRow = Gtk.Template.Child() _markdown_default_to_render: Adw.SwitchRow = Gtk.Template.Child() _enable_markdown_maths: Adw.SwitchRow = Gtk.Template.Child() _keep_webkit_process: Adw.SwitchRow = Gtk.Template.Child() _markdown_use_monospace_font: Adw.SwitchRow = Gtk.Template.Child() _markdown_monospace_font_ratio: Adw.SpinRow = Gtk.Template.Child() _editor_line_length: Adw.SwitchRow = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__app = Gio.Application.get_default() self.__config_manager = ConfigManager.get_default() self.__dependent_on_markdown_render = [ self._markdown_default_to_render, self._enable_markdown_maths, self._markdown_use_monospace_font, self._markdown_monospace_font_ratio, self._keep_webkit_process, ] self.__build_actions() scheme_manager = GtkSource.StyleSchemeManager.get_default() options = {} scheme_ids = scheme_manager.get_scheme_ids() # Preference and order internal schemes def add_preferenced_scheme(scheme_id, name): if scheme_id not in scheme_ids: return options[scheme_id] = name # Exposing scheme names for translation here as attempt to translate via scheme XML files # wasn't fruitful preferenced_schemes = { # Translators: Description, a style name "iotas-mono": _("Monochrome"), # Translators: Description, a style name "iotas-alpha-muted": _("Muted Markup"), # Translators: Description, a style name "iotas-alpha-bold": _("Bold Markup"), # Translators: Description, a style name "iotas-unstyled": _("Disabled"), } for scheme_id, name in preferenced_schemes.items(): add_preferenced_scheme(scheme_id, name) # Add other schemes (eg. in user data) for scheme_id in scheme_ids: if scheme_id in preferenced_schemes.keys(): continue if scheme_id.endswith("-dark") or scheme_id.endswith("-high-contrast"): continue # Only Iotas-specific schemes, prefixed with "iotas-", are supported if scheme_id.startswith("iotas-"): scheme = scheme_manager.get_scheme(scheme_id) options[scheme_id] = scheme.get_name() helper = ComboRowHelper( self._editor_theme_combo, options, self.__config_manager.editor_theme, ) helper.connect("changed", lambda _o, value: self.__apply_editor_theme_change(value)) options = { # Translators: Description, a visual style (for category labels in index) "monochrome": _("Monochrome"), # Translators: Description, a visual style (for category labels in index) "muted": _("Muted"), # Translators: Description, a visual style (for category labels in index) "blue": _("Blue"), # Translators: Description, a visual style (for category labels in index) "orange": _("Orange"), # Translators: Description, a visual style (for category labels in index) "red": _("Red"), # Translators: Description, a visual style (for category labels in index) "none": _("None"), } helper = ComboRowHelper( self._index_category_style_combo, options, self.__config_manager.index_category_style, ) helper.connect("changed", lambda _o, value: self.__apply_index_category_style_change(value)) options = { # Translators: Description, for preference option - a description of visibility "always-visible": _("Always Visible"), # Translators: Description, for preference option - a description of visibility "auto-hide": _("Automatically Hide"), # Translators: Description, for preference option - a description of visibility "auto-hide-fullscreen-only": _("Auto Hide When Fullscreen"), # Translators: Description, for preference option - a description of visibility "disabled": _("Disabled"), } helper = ComboRowHelper( self._editor_formatting_bar_visibility_combo, options, str(self.__config_manager.editor_formatting_bar_visibility), ) helper.connect( "changed", lambda _o, value: self.__on_formatting_visibility_change(value), ) options = { # Translators: Description, for preference option - a description of visibility "always-visible": _("Always Visible"), # Translators: Description, for preference option - a description of visibility "auto-hide": _("Automatically Hide"), # Translators: Description, for preference option - a description of visibility "auto-hide-fullscreen-only": _("Auto Hide When Fullscreen"), } helper = ComboRowHelper( self._editor_header_bar_visibility_combo, options, str(self.__config_manager.editor_header_bar_visibility), ) helper.connect( "changed", lambda _o, value: self.__on_header_bar_visibility_change(value), ) self._markdown_monospace_font_ratio.connect( "notify::value", lambda _o, _v: self.__apply_font_ratio_change() ) self.__config_manager.connect_changed( ConfigManager.MARKDOWN_RENDER_MONOSPACE_FONT_RATIO, self.__update_markdown_font_ratio_from_config, ) self.__update_markdown_font_ratio_from_config() self._connect_sync_row.set_visible(not self.__config_manager.nextcloud_sync_configured) self._disconnect_sync_row.set_visible(self.__config_manager.nextcloud_sync_configured) self._reset_database_row.set_visible(not self.__config_manager.nextcloud_sync_configured) if not (self.__app.debug_session or self.__app.development_mode): self.remove(self._debug_page) self.__config_manager.connect_changed( ConfigManager.MARKDOWN_RENDER, self.__update_disabled_markdown_render_items, ) self.__update_disabled_markdown_render_items() self.__init_excessive_preferences_handling() self.__toast = None self.__setup_temporary_combo_factories() def __build_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() key = ConfigManager.USE_MONOSPACE_FONT monospace_font_action = self.__config_manager.create_action(key) action_group.add_action(monospace_font_action) key = ConfigManager.PERSIST_SIDEBAR persist_sidebar_action = self.__config_manager.create_action(key) action_group.add_action(persist_sidebar_action) key = ConfigManager.SPELLING_ENABLED spelling_action = self.__config_manager.create_action(key) action_group.add_action(spelling_action) key = ConfigManager.MARKDOWN_DETECT_SYNTAX syntax_action = self.__config_manager.create_action(key) action_group.add_action(syntax_action) key = ConfigManager.MARKDOWN_RENDER render_action = self.__config_manager.create_action(key) action_group.add_action(render_action) key = ConfigManager.MARKDOWN_DEFAULT_TO_RENDER default_render_action = self.__config_manager.create_action(key) action_group.add_action(default_render_action) key = ConfigManager.MARKDOWN_TEX_SUPPORT tex_action = self.__config_manager.create_action(key) action_group.add_action(tex_action) key = ConfigManager.MARKDOWN_USE_MONOSPACE_FONT markdown_monospace_action = self.__config_manager.create_action(key) action_group.add_action(markdown_monospace_action) key = ConfigManager.MARKDOWN_KEEP_WEBKIT_PROCESS keep_webkit_action = self.__config_manager.create_action(key) action_group.add_action(keep_webkit_action) key = ConfigManager.LINE_LENGTH setting_maximum = self.__config_manager.line_length_max init_state = self.__config_manager.line_length < setting_maximum action = Gio.SimpleAction.new_stateful(key, None, GLib.Variant("b", init_state)) action.connect("change-state", self.__on_line_length_state_change) action_group.add_action(action) self.insert_action_group("settings", action_group) def __init_excessive_preferences_handling(self) -> None: """An experiment in providing configurability for more technical users while retaining simplicity for those less savvy. This is an experiment, and may get removed. """ self.__extended_only = [ self._index_category_style_combo, self._enable_render_view, self._markdown_default_to_render, self._enable_markdown_maths, self._keep_webkit_process, self._markdown_use_monospace_font, self._markdown_monospace_font_ratio, self._editor_line_length, self._editor_detect_syntax, ] self.__update_contextual() self.__config_manager.connect_changed( ConfigManager.SHOW_EXTENDED_PREFERENCES, self.__update_contextual, ) self.__config_manager.connect_changed( ConfigManager.MARKDOWN_DETECT_SYNTAX, self.__update_contextual, ) # Ouch, hacky. Going to hell for this one. Fetch a bunch of widgets to add click listeners # to as a method for toggling the visibility of the extended preferences. box = self._index_group.get_parent() clamp = box.get_parent() for widget in box, clamp: add_mouse_button_accel( widget, self.__on_preferences_background_click, Gtk.PropagationPhase.TARGET ) def __on_preferences_background_click( self, gesture: Gtk.GestureClick, n_press: int, _x: float, _y: float ) -> None: extended = self.__config_manager.show_extended_preferences if gesture.get_current_button() != 1: return if n_press > 1 and n_press < self.CLICKS_FOR_EXTENDED: clicks = self.CLICKS_FOR_EXTENDED - n_press if extended: # Translators: Description, notification, {0} is a number text = _("Reducing in {0} presses").format(clicks) else: # Translators: Description, notification, {0} is a number text = _("Extending in {0} presses").format(clicks) self.__make_toast(text) elif n_press == self.CLICKS_FOR_EXTENDED: if extended: # Translators: Description, notification self.__make_toast(_("Extended hidden")) else: # Translators: Description, notification self.__make_toast(_("Extended shown")) self.__config_manager.show_extended_preferences = not extended def __on_header_bar_visibility_change(self, value: str) -> None: visibility = HeaderBarVisibility(value) self.__config_manager.editor_header_bar_visibility = visibility self.__discourage_mobile_toolbar_autohiding(visibility) def __on_formatting_visibility_change(self, value: str) -> None: visibility = HeaderBarVisibility(value) self.__config_manager.editor_formatting_bar_visibility = visibility self.__discourage_mobile_toolbar_autohiding(visibility) def __on_line_length_state_change(self, action: Gio.SimpleAction, state: bool) -> None: action.set_state(state) setting_maximum = self.__config_manager.line_length_max new_value = self.__config_manager.default_line_length if state else setting_maximum self.__config_manager.line_length = new_value def __discourage_mobile_toolbar_autohiding(self, visibility: HeaderBarVisibility) -> None: if not is_likely_mobile_device(): return if visibility in ( HeaderBarVisibility.AUTO_HIDE, HeaderBarVisibility.AUTO_HIDE_FULLSCREEN_ONLY, ): self.__make_toast( # Translators: Description, notification. Needs to be short for toast. _("Hiding discouraged on mobile"), long=True, ) def __make_toast(self, text: str, long: bool = False) -> None: if self.__toast is not None: self.__toast.dismiss() toast = Adw.Toast.new(text) toast.set_priority(Adw.ToastPriority.HIGH) toast.set_timeout(self.LONGER_TOAST if long else self.SHORTER_TOAST) toast.connect("dismissed", lambda _o: self.__flag_toast_dismissed()) self.__toast = toast self.add_toast(toast) def __flag_toast_dismissed(self) -> None: self.__toast = None @Gtk.Template.Callback() def _reset_database(self, _button: Gtk.Button) -> None: # Translators: Title title = _("Reset Database?") # Translators: Description body = _("All notes will be deleted. Continue with the reset?") dialog = Adw.AlertDialog.new(title, body) # Translators: Button dialog.add_response("close", _("Cancel")) # Translators: Button dialog.add_response("reset", _("Reset")) dialog.set_response_appearance("reset", Adw.ResponseAppearance.DESTRUCTIVE) def handle_response(_o: Adw.AlertDialog, response: str) -> None: if response == "reset": self.close() self.__app.reset_database() dialog.connect("response", handle_response) dialog.present(self) @Gtk.Template.Callback() def _connect_nextcloud(self, _button: Gtk.Button) -> None: GLib.idle_add(self.emit, "start-onboarding") @Gtk.Template.Callback() def _disconnect_nextcloud(self, _button: Gtk.Button) -> None: # Translators: Title title = _("Disconnect Nextcloud?") # Translators: Description body = _("All notes will be removed. Do you want to sign out?") dialog = Adw.AlertDialog.new(title, body) # Translators: Button dialog.add_response("close", _("Cancel")) # Translators: Button dialog.add_response("disconnect", _("Disconnect")) dialog.set_response_appearance("disconnect", Adw.ResponseAppearance.DESTRUCTIVE) def handle_response(_o: Adw.AlertDialog, response: str) -> None: if response == "disconnect": self.close() self.__app.disconnect_nextcloud() dialog.connect("response", handle_response) dialog.present(self) @Gtk.Template.Callback() def _reset_prune_threshold(self, _button: Gtk.Button) -> None: self.__app.reset_sync_marker() def __update_markdown_font_ratio_from_config(self) -> None: self._markdown_monospace_font_ratio.set_value( self.__config_manager.markdown_render_monospace_font_ratio ) def __update_disabled_markdown_render_items(self) -> None: enabled = self.__config_manager.markdown_render_enabled for widget in self.__dependent_on_markdown_render: widget.set_sensitive(enabled) def __update_contextual(self) -> None: showing_extended = self.__config_manager.show_extended_preferences for obj in self.__extended_only: obj.set_visible(showing_extended) syntax_enabled = self.__config_manager.markdown_detect_syntax # If markdown syntax is disabled always show the preference as it disables others if not syntax_enabled: self._editor_detect_syntax.set_visible(True) self._editor_theme_combo.set_sensitive(syntax_enabled) self._editor_formatting_bar_visibility_combo.set_sensitive(syntax_enabled) def __apply_editor_theme_change(self, value: str) -> None: self.__config_manager.editor_theme = value def __apply_font_ratio_change(self) -> None: self.__config_manager.markdown_render_monospace_font_ratio = ( self._markdown_monospace_font_ratio.get_value() ) def __apply_index_category_style_change(self, value: str) -> None: self.__config_manager.index_category_style = value # Quick fix for this release (due to already being in string freeze) by using a combo row # factory to accommodate for long strings not fitting in combo row popovers. This basically # copies the stock Adw.ComboRow factory excluding the 20 character width limit. def __setup_temporary_combo_factories(self) -> None: header_combo_factory = Gtk.SignalListItemFactory() header_combo_factory.connect("setup", self.__long_comborow_factory_setup) header_combo_factory.connect( "bind", self.__long_comborow_factory_bind, self._editor_header_bar_visibility_combo ) header_combo_factory.connect( "unbind", self.__long_comborow_factory_unbind, self._editor_header_bar_visibility_combo ) self._editor_header_bar_visibility_combo.set_list_factory(header_combo_factory) format_combo_factory = Gtk.SignalListItemFactory() format_combo_factory.connect("setup", self.__long_comborow_factory_setup) format_combo_factory.connect( "bind", self.__long_comborow_factory_bind, self._editor_formatting_bar_visibility_combo ) format_combo_factory.connect( "unbind", self.__long_comborow_factory_unbind, self._editor_formatting_bar_visibility_combo, ) self._editor_formatting_bar_visibility_combo.set_list_factory(format_combo_factory) def __long_comborow_factory_setup( self, _factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem ) -> None: box = Gtk.Box() label = Gtk.Label() label.set_xalign(0) label.set_ellipsize(Pango.EllipsizeMode.END) label.set_width_chars(1) label.set_valign(Gtk.Align.CENTER) box.append(label) icon = Gtk.Image.new_from_icon_name("object-select-symbolic") icon.set_accessible_role(Gtk.AccessibleRole.PRESENTATION) box.append(icon) list_item.set_child(box) def __long_comborow_factory_bind( self, _factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem, combo: Adw.ComboRow ) -> None: box = list_item.get_child() label = box.get_first_child() label.set_text(list_item.get_item().get_string()) combo.connect("notify::selected-item", self.__selected_item_changed, list_item) self.__selected_item_changed(combo, None, list_item) def __long_comborow_factory_unbind( self, _factory: Gtk.SignalListItemFactory, _list_item: Gtk.ListItem, combo: Adw.ComboRow ) -> None: combo.disconnect_by_func(self.__selected_item_changed) @staticmethod def __selected_item_changed( combo: Adw.ComboRow, _pspec: GObject.ParamSpec, list_item: Gtk.ListItem ) -> None: box = list_item.get_child() icon = box.get_last_child() if combo.get_selected_item() == list_item.get_item(): icon.set_opacity(1.0) else: icon.set_opacity(0.0) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/render_search_header_bar.py000066400000000000000000000172431507102636600270420ustar00rootroot00000000000000from gi.repository import Adw, Gdk, Gio, GObject, Gtk from iotas.editor_search_entry import EditorSearchEntry from iotas.ui_utils import check_for_search_starting @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/render_search_header_bar.ui") class RenderSearchHeaderBar(Adw.Bin): __gtype_name__ = "RenderSearchHeaderBar" __gsignals__ = { "resumed": (GObject.SignalFlags.RUN_FIRST, None, ()), } _entry: EditorSearchEntry = Gtk.Template.Child() _backward_button: Gtk.Button = Gtk.Template.Child() _forward_button: Gtk.Button = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__active = False self.__current_matches = 0 self.__current_match = 0 self.__current_term = "" self.__limit_notify_timeout = None self.__found_signal_handler_id = None self.__failed_to_find_signal_handler_id = None self.__term_changed_signal_handler_id = None def setup(self) -> None: """Perform initial setup.""" self.__setup_actions() def check_if_starting( self, controller: Gtk.EventControllerKey, keyval: int, state: Gdk.ModifierType ) -> bool: """Check if starting search via type to search. :param Gtk.EventControllerKey controller: The key controller :param int keyval: The key value :param Gdk.ModifierType state: Any modifier state :return: Whether search is starting :rtype: bool """ if not check_for_search_starting(controller, keyval, state): return False self._entry.set_text("") if controller.forward(self._entry.text): return True return False def enter(self, render_view, resuming: bool, type_to_search: bool) -> None: """Enter search. The render view is passed in each time as, depending on configuration, it may be a new instance each time. :param bool render_view: WebKit view :param bool resuming: Whether resuming search (via keyboard shortcut) :param bool type_to_search: Starting from type to search """ if type_to_search or resuming: # Used when starting search by typing; the initial character will already be populated # in the GtkText. self._entry.text.grab_focus() self._entry.text.set_position(-1) else: self._entry.select_all_and_focus() if self.__found_signal_handler_id is None: self.__render_view = render_view self.__controller = render_view.get_find_controller() if not type_to_search and not resuming: self._entry.set_text("") self.__term_changed_signal_handler_id = self._entry.text.get_buffer().connect( "notify::text", lambda _o, _v: self.__do_search() ) self.__found_signal_handler_id = self.__controller.connect( "found-text", self.__on_found_text ) self.__failed_to_find_signal_handler_id = self.__controller.connect( "failed-to-find-text", lambda _c: self.__on_failed_to_find_text() ) self.__current_matches = 0 self.__current_match = 0 self.__occurrences_count_changed() # If we're here via type-to-search we may already have some text self.__current_term = self._entry.get_text() # Part of the effort to delay all WebKit initialisation if "WebKit" not in globals(): import gi gi.require_version("WebKit", "6.0") global WebKit from gi.repository import WebKit if resuming: # Blank to avoid found callback thinking we're just iterating results self.__current_term = "" self.__do_search() else: self.__resuming = False self.active = True def exit(self) -> None: """Exit search.""" self.__controller.search_finish() self.__controller.disconnect(self.__found_signal_handler_id) self.__found_signal_handler_id = None self.__controller.disconnect(self.__failed_to_find_signal_handler_id) self._entry.text.get_buffer().disconnect(self.__term_changed_signal_handler_id) self.active = False def disable_actions(self) -> None: """Disable actions.""" self.__action_group.lookup_action("backward").set_enabled(False) self.__action_group.lookup_action("forward").set_enabled(False) def focus(self) -> None: """Grab focus to entry.""" self._entry.text.grab_focus() @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @active.setter def set_active(self, value: bool) -> None: self.__active = value def __setup_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() action = Gio.SimpleAction.new("forward") action.connect("activate", lambda _o, _p: self.__move_forward()) action_group.add_action(action) app.set_accels_for_action("render-search.forward", ["g"]) action.set_enabled(False) action = Gio.SimpleAction.new("backward") action.connect("activate", lambda _o, _p: self.__move_backward()) action_group.add_action(action) app.set_accels_for_action("render-search.backward", ["g"]) action.set_enabled(False) self.__action_group = action_group app.get_active_window().insert_action_group("render-search", action_group) def __on_found_text(self, controller, match_count: int) -> None: if controller.get_search_text() == self.__current_term: return self.__current_term = controller.get_search_text() self.__current_matches = match_count self.__occurrences_count_changed() self.__current_match = 1 self._entry.set_occurrence_position(1) def __on_failed_to_find_text(self) -> None: self.__current_match = 0 self.__current_matches = 0 self.__occurrences_count_changed() def __do_search(self) -> None: self.__controller.search( self._entry.get_text(), # mypy ignore to allow for module lazy loading WebKit.FindOptions.CASE_INSENSITIVE | WebKit.FindOptions.WRAP_AROUND, # type: ignore [name-defined] # noqa: E501 2**32 - 1, ) def __move_forward(self) -> None: """Move to next search match.""" if not self.__active and self._entry.get_text() != "": self.emit("resumed") return self.__current_match += 1 if self.__current_match > self.__current_matches: self.__current_match = 1 self._entry.set_occurrence_position(self.__current_match) self.__controller.search_next() def __move_backward(self) -> None: """Move to previous search match.""" if not self.__active and self._entry.get_text() != "": self.emit("resumed") return self.__current_match -= 1 if self.__current_match < 1: self.__current_match = self.__current_matches self._entry.set_occurrence_position(self.__current_match) self.__controller.search_previous() def __occurrences_count_changed(self) -> None: self._entry.set_occurrence_count(self.__current_matches) search_can_move = self.__current_matches > 0 self.__action_group.lookup_action("backward").set_enabled(search_can_move) self.__action_group.lookup_action("forward").set_enabled(search_can_move) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/selection_header_bar.py000066400000000000000000000136111507102636600262160ustar00rootroot00000000000000from gettext import gettext as _ from gi.repository import Adw, Gio, GObject, Gtk from iotas.category_header_bar import CategoryHeaderBar from iotas.category_treeview_list_store import CategoryTreeViewListStore from iotas.note import Note from iotas.ui_utils import show_error_dialog @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/selection_header_bar.ui") class SelectionHeaderBar(Adw.Bin): __gtype_name__ = "SelectionHeaderBar" __gsignals__ = { "set-favourite": (GObject.SignalFlags.RUN_FIRST, None, ()), "clear-favourite": (GObject.SignalFlags.RUN_FIRST, None, ()), "delete": (GObject.SignalFlags.RUN_FIRST, None, ()), "categories-changed": (GObject.SignalFlags.RUN_FIRST, None, ()), "abort": (GObject.SignalFlags.RUN_FIRST, None, ()), } _stack: Gtk.Stack = Gtk.Template.Child() _main_header_bar: Adw.HeaderBar = Gtk.Template.Child() _category_header_bar: CategoryHeaderBar = Gtk.Template.Child() _count_label: Gtk.Label = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__active = False self.__selected: list[Note] = [] self._category_header_bar.connect( "categories-changed", lambda _o: self.emit("categories-changed") ) self._category_header_bar.connect("abort", lambda _o: self.emit("abort")) self.__setup_actions() def setup(self, model: CategoryTreeViewListStore) -> None: """Perform initial setup. :param CategoryTreeViewListStore model: Categories model """ self._category_header_bar.setup(model) def activate(self) -> None: """Activate header bar.""" self._stack.set_visible_child(self._main_header_bar) self.active = True self.__selected = [] self.__refresh() def set_note_selected(self, note: Note, select: bool) -> None: """Add or remove note from selection. :param Note note: Note to select :param bool select: Whether to add or remote from selection """ if select: if note not in self.__selected: self.__selected.append(note) else: if note in self.__selected: self.__selected.remove(note) self.__refresh() def get_selected(self) -> list[Note]: """Get selected notes. :return: Selected notes :rtype: list[Note] """ return self.__selected def get_categories_changeset(self) -> list[tuple[Note, str]]: """Get categories changeset. :return: Selected of category-changed notes and their previous categories :rtype: list[tuple[Note, str]] """ return self._category_header_bar.take_changeset() def edit_category_for_selection(self) -> None: """Edit the category for the selected notes.""" if not self.__selected: return msg = _("Unable to change category on read-only note") if self.__error_for_readonly_in_selection(msg): return self._stack.set_visible_child(self._category_header_bar) self._category_header_bar.activate(self.__selected) def toggle_favourite_on_selection(self) -> None: """Toggle favourites for the selected notes. If a collection of notes with mixed favourite states are selected the destination state is the less common one in those selected. """ if not self.__selected: return set = len([x for x in self.__selected if x.favourite]) unset = len(self.__selected) - set if set >= unset: self.emit("clear-favourite") else: self.emit("set-favourite") def handle_delete_keyboard_shortcut(self) -> None: """Handle pressed delete keyboard shortcut.""" if self._stack.get_visible_child() == self._category_header_bar: self._category_header_bar.clear_and_apply() else: self.__delete_selection() @GObject.Property(type=bool, default=False) def active(self) -> bool: return self.__active @active.setter def set_active(self, value: bool) -> None: self.__active = value def __setup_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() action = Gio.SimpleAction.new("categorise") action.connect("activate", lambda _a, _p: self.edit_category_for_selection()) action_group.add_action(action) action = Gio.SimpleAction.new("favourite") action.connect("activate", lambda _a, _p: self.toggle_favourite_on_selection()) action_group.add_action(action) action = Gio.SimpleAction.new("delete") action.connect("activate", lambda _a, _p: self.__delete_selection()) action_group.add_action(action) self.insert_action_group("selection", action_group) self.__action_group = action_group def __delete_selection(self) -> None: """Delete the selected notes.""" if not self.__selected: return self.emit("delete") def __refresh(self) -> None: # Translators: Description, {} is a number self._count_label.set_text(_("{} Selected").format(len(self.__selected))) if self._stack.get_visible_child() == self._category_header_bar: self._category_header_bar.replace_notes(self.__selected) for action in self.__action_group.list_actions(): action = self.__action_group.lookup(action) action.set_property("enabled", self.__selected) def __error_for_readonly_in_selection(self, message: str) -> bool: have_readonly = False for note in self.__selected: if note.read_only: have_readonly = True break if have_readonly: # Translators: Description, alert show_error_dialog(self, _("Unable to change category on read-only note")) return have_readonly iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/sidebar.py000066400000000000000000000171151507102636600235110ustar00rootroot00000000000000from gi.repository import Adw, Gdk, Gio, Gtk from typing import Callable, Optional from iotas.category import Category, CategorySpecialPurpose from iotas.category_manager import CategoryManager from iotas.index_menu_button import IndexMenuButton from iotas.sidebar_row import SidebarRow from iotas.sync_manager import SyncManager from iotas.theme_selector import ThemeSelector @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/sidebar.ui") class Sidebar(Adw.Bin): __gtype_name__ = "Sidebar" _listview: Gtk.ListView = Gtk.Template.Child() _close_button: Gtk.Button = Gtk.Template.Child() _menu_button: IndexMenuButton = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__init_listview() def setup( self, sync_manager: SyncManager, category_manager: CategoryManager, category_activated_func: Callable[[Category, bool], None], ) -> None: """Perform initial setup. :param SyncManager sync_manager: Remote sync manager :param CategoryManager: Category manager :param Callable[[Category], None] category_activated_func: Function to call upon category activation. """ self.__sync_manager = sync_manager self.__category_manager = category_manager self.__category_activated_func = category_activated_func self.__filter_model.set_model(self.__category_manager.list_model) self.__category_manager.connect("initial-load-complete", lambda _o: self.__populate()) self._menu_button.get_popover().add_child(ThemeSelector(), "theme") def select_and_fetch_category( self, category_name: Optional[str], purpose: Optional[CategorySpecialPurpose] = None, ) -> Optional[Category]: """Select and fetch the specified category. :param Optional[str]: Name of category :param Optional[CategorySpecialPurpose]: Alternatively, a category special purpose :return: The category, if found :rtype: Optional[Category] """ category = None if purpose is not None: (category, index) = self.__category_manager.get_special_purpose_category(purpose) elif category_name is not None: (category, index) = self.__category_manager.get_normal_category(category_name) else: raise Exception("Incorrect usage") self.__selection_model.set_selected(index) return category def take_focus(self) -> None: """Grab keyboard focus.""" self._listview.grab_focus() # Ensure one of the rows has focus, but don't force it to the top row if self._listview.has_focus(): for row in self._listview: row.grab_focus() break def has_focus_within(self) -> bool: """Fetch whether the sidebar or any of its rows have focus. :return: Whether focused :rtype: bool """ # There's considerably more complexity here than expected due to Gtk.Widget.is_ancestor # not behaving as expected. if self._listview.has_focus(): return True else: for row in self._listview: sidebar_row = row.get_first_child() if sidebar_row.has_focus(): return True return False def show_buttons(self, close_visible: bool, menu_visible: bool) -> None: """Set visibility on buttons. :param bool close_visible: Close button visibility :param bool menu_visible: Menu button visibility """ self._close_button.set_visible(close_visible) self._menu_button.set_visible(menu_visible) def __init_listview(self) -> None: self.__factory = Gtk.SignalListItemFactory() self.__factory.connect("setup", self.__setup_listitem) self.__factory.connect("bind", self.__bind_listitem) self.__factory.connect("unbind", self.__unbind_listitem) self._listview.set_factory(self.__factory) self.__filter_model = Gtk.FilterListModel() self.__custom_filter = Gtk.CustomFilter() self.__filter_model.set_filter(self.__custom_filter) def filter_root_categories(category: Category) -> bool: return "/" not in category.name self.__custom_filter.set_filter_func(filter_root_categories) def __populate(self) -> None: self.__tree_model = Gtk.TreeListModel.new( self.__filter_model, False, False, self.__create_subcategory_models ) self.__selection_model = Gtk.SingleSelection.new(self.__tree_model) self._listview.set_model(self.__selection_model) self._listview.connect("activate", self.__on_listview_row_activated) controller = Gtk.EventControllerKey() controller.connect("key-pressed", self.__on_key_pressed) self._listview.add_controller(controller) def __create_subcategory_models(self, category: Category) -> Optional[Gio.ListModel]: if not category.is_sub_category: def filter_toplevel_parent(category: Category, parent_name: str) -> bool: return parent_name != category.name and category.name.startswith(parent_name + "/") filter = Gtk.CustomFilter.new(filter_toplevel_parent, category.name) model = Gtk.FilterListModel.new(self.__category_manager.list_model) model.set_filter(filter) if model.get_n_items() > 0: model.connect("notify::n-items", self.__subcategory_store_items_changed, category) return model return None def __setup_listitem(self, _factory: Gtk.SignalListItemFactory, listitem: Gtk.ListItem) -> None: row = SidebarRow(self.__category_activated_func, self.__category_manager) listitem.set_child(row) def __bind_listitem(self, _factory: Gtk.SignalListItemFactory, listitem: Gtk.ListItem) -> None: expander = listitem.get_child() tree_list_row = listitem.get_item() expander.set_list_row(tree_list_row) category = tree_list_row.get_item() expander.bind(category) def __unbind_listitem( self, _factory: Gtk.SignalListItemFactory, listitem: Gtk.ListItem ) -> None: row = listitem.get_child() row.unbind() def __subcategory_store_items_changed( self, model: Gtk.FilterListModel, _n_items: int, category: Category ) -> None: if model.get_n_items() == 0: self.__category_manager.recreate_category_for_expandable_change(category) def __expand_selected_row(self, expanded: bool) -> None: selected = self.__selection_model.get_selected() selected_row = self.__selection_model.get_item(selected) if selected_row.is_expandable() and selected_row.get_expanded() is not expanded: selected_row.set_expanded(expanded) def __on_key_pressed( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ): if keyval in (Gdk.KEY_Right, Gdk.KEY_KP_Right): self.__expand_selected_row(True) return Gdk.EVENT_STOP elif keyval in (Gdk.KEY_Left, Gdk.KEY_KP_Left): self.__expand_selected_row(False) return Gdk.EVENT_STOP return Gdk.EVENT_PROPAGATE def __on_listview_row_activated(self, listview: Gtk.ListView, position: int) -> None: model = listview.get_model() model.select_item(position, True) row = model.get_item(position) category = row.get_item() close_sidebar = True self.__category_activated_func(category, close_sidebar) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/sidebar_row.py000066400000000000000000000110351507102636600243730ustar00rootroot00000000000000from gi.repository import Gdk, GLib, GObject, Gtk from typing import Callable from iotas.category import Category, CategorySpecialPurpose from iotas.category_manager import CategoryManager from iotas.config_manager import ConfigManager @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/sidebar_row.ui") class SidebarRow(Gtk.TreeExpander): __gtype_name__ = "SidebarRow" FOCUS_CSS_CLASS_NAME = "focused" _icon: Gtk.Image = Gtk.Template.Child() _name_label: Gtk.Label = Gtk.Template.Child() _count_with_children_label: Gtk.Label = Gtk.Template.Child() _count_node_only_label: Gtk.Label = Gtk.Template.Child() def __init__( self, activated_func: Callable[[Category, bool], None], category_manager: CategoryManager ) -> None: super().__init__() self.__category: Category | None = None self.__bindings: list[GObject.Binding] = [] self.__activated_func = activated_func category_manager.bind_property( "have-sub-category", self, "indent-for-icon", GObject.BindingFlags.SYNC_CREATE ) # Add some (hopefully temporary) handling of the keyboard focus ring def manage_manual_css_class(row, _flags: Gtk.StateFlags): parent = row.get_property("parent") if parent is None: return if row.get_state_flags() & Gtk.StateFlags.FOCUS_VISIBLE: parent.add_css_class(self.FOCUS_CSS_CLASS_NAME) else: parent.remove_css_class(self.FOCUS_CSS_CLASS_NAME) self.connect("state-flags-changed", manage_manual_css_class) def bind(self, category: Category) -> None: """Bind category to row. :param Category category: New category """ self.__category = category self.__add_binding(category, "note-count", self._count_node_only_label, "label") if self.__category.get_parent() is None: # Build for root category self.__add_binding(category, "display-name", self._name_label, "label") self.__add_binding( category, "note-count-with-children", self._count_with_children_label, "label" ) tree_list_row = self.get_list_row() self.__add_binding( tree_list_row, "expanded", self._count_with_children_label, "visible", GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN, ) self.__add_binding(tree_list_row, "expanded", self._count_node_only_label, "visible") if category.special_purpose == CategorySpecialPurpose.ALL: self._icon.set_from_icon_name("edit-select-all-symbolic") elif category.special_purpose == CategorySpecialPurpose.UNCATEGORISED: self._icon.set_from_icon_name("grid-symbolic") else: # Build for sub category self.__add_binding(category, "sub-category-name", self._name_label, "label") self._count_node_only_label.set_visible(True) self._count_with_children_label.set_visible(False) def unbind(self) -> None: """Unbind category from row.""" for binding in self.__bindings: binding.unbind() self.__bindings.clear() self.__category = None @Gtk.Template.Callback() def _activate(self, click: Gtk.GestureClick, _n_press: int, _x: float, _y: float) -> None: assert self.__category state = click.get_current_event_state() if state == Gdk.ModifierType.ALT_MASK: list_row = self.get_list_row() if list_row.is_expandable(): list_row.set_expanded(not list_row.get_expanded()) else: close_sidebar = state != Gdk.ModifierType.CONTROL_MASK if ConfigManager.get_default().pin_sidebar: self.__activated_func(self.__category, close_sidebar) else: # Without the idle callback the listview selection doesn't get set before the # sidebar closes (when auto-hiding is enabled) GLib.idle_add(self.__activated_func, self.__category, close_sidebar) def __add_binding( self, from_object: GObject.Object, from_property: str, to_object: GObject.Object, to_property: str, binding_flags: GObject.BindingFlags = GObject.BindingFlags.SYNC_CREATE, ) -> None: binding = from_object.bind_property(from_property, to_object, to_property, binding_flags) self.__bindings.append(binding) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/sync_manager.py000066400000000000000000000711661507102636600245540ustar00rootroot00000000000000from gettext import gettext as _ from gi.repository import Gio, GLib, GObject, Gtk from hashlib import sha256 import logging from threading import Lock, Thread import time from typing import Optional from iotas.attachment import Attachment from iotas.attachment_helpers import write_attachment_to_disk from iotas.category_manager import CategoryManager from iotas.config_manager import ConfigManager from iotas.nextcloud_sync_worker import NextcloudSyncWorker, LoginRequestResult from iotas.note import Note from iotas.note_database import NoteDatabase from iotas.note_manager import NoteManager from iotas.sync_result import ContentPushSyncResult, FailedPush from iotas.ui_utils import idle_add_wait class SyncWorkLock: def __init__(self) -> None: self.__lock = Lock() self.__locked = False def acquire(self) -> None: """Acquire the lock.""" self.__locked = True self.__lock.acquire() def release(self) -> None: """Release the lock.""" self.__locked = False self.__lock.release() @property def locked(self) -> bool: return self.__locked class SyncManager(GObject.Object): __gsignals__ = { # bool: Whether a new account "ready": (GObject.SignalFlags.RUN_FIRST, None, (bool,)), "started": (GObject.SignalFlags.RUN_FIRST, None, ()), # int: Number of changes "finished": (GObject.SignalFlags.RUN_FIRST, None, (int,)), # Note: Note in conflict "note-conflict": (GObject.SignalFlags.RUN_FIRST, None, (Note,)), # Note: Remotely deleted note "note-deleted": (GObject.SignalFlags.RUN_FIRST, None, (Note,)), "secret-service-failure": (GObject.SignalFlags.RUN_FIRST, None, ()), # str: Previous category, str: Remote category "remote-category-sanitised": (GObject.SignalFlags.RUN_FIRST, None, (str, str)), "missing-password": (GObject.SignalFlags.RUN_FIRST, None, ()), "notes-capability-missing": (GObject.SignalFlags.RUN_FIRST, None, ()), "attachment-downloaded": (GObject.SignalFlags.RUN_FIRST, None, (Attachment,)), } STARTUP_SYNC_INIT_DURATION = 500 SYNC_FAIL_OFFLINE_THRESHOLD = 2 MIN_NEW_NOTES_FOR_BATCHING = 30 SYNC_BATCH_SIZE = 5 def __init__(self, db: NoteDatabase) -> None: super().__init__() self.__db = db self.__config_manager = ConfigManager.get_default() self.__sync_worker = NextcloudSyncWorker(self.__config_manager) self.__lock = SyncWorkLock() self.__note_manager: NoteManager self.__category_manager: CategoryManager self.__authenticated = False self.__api_check_complete = False self.__initial_sync_delay_complete = False self.__sync_requested_while_active = False self.__waiting_timeout = None self.__offline = False self.__sync_fail_counter = 0 self.__config_manager.connect_changed( ConfigManager.SYNC_INTERVAL, self.__set_sync_interval, ) self.__set_sync_interval() self.__config_manager.bind( ConfigManager.NETWORK_TIMEOUT, self.__sync_worker, "timeout", Gio.SettingsBindFlags.DEFAULT, ) self.__sync_worker.connect("ready", self.__on_sync_ready) self.__sync_worker.connect("api-check-finished", self.__on_api_check_finished) self.__sync_worker.connect("settings-fetched", self.__on_settings_fetched) self.__sync_worker.connect( "secret-service-failure", lambda _o: GLib.idle_add(self.emit, "secret-service-failure") ) self.__sync_worker.bind_property( "authenticated", self, "authenticated", GObject.BindingFlags.SYNC_CREATE ) self.__sync_worker.connect("missing-password", self.__on_missing_password) self.__sync_worker.connect( "notes-capability-missing", lambda _o: self.emit("notes-capability-missing") ) def init_auth(self) -> None: """Initialise sync authentication details from the Secret Service.""" self.__sync_worker.init_auth() def set_managers(self, note_manager: NoteManager, category_manager: CategoryManager) -> None: """Set the models. :param NoteManager note_manager: The note manager :param CategoryManager category_manager: The category manager """ self.__note_manager = note_manager self.__note_manager.connect( "initial-load-complete", lambda _o: self.__on_initial_note_load_complete() ) self.__category_manager = category_manager def sync_now(self) -> None: """Attempt to initiate a sync. If the server isn't authenticated the request will be discarded. Another sync already underway will result in the sync being run immediately after the current operation. """ if not self.__sync_worker.authenticated: return if self.__lock.locked: self.__sync_requested_while_active = True return if self.__waiting_timeout: GLib.source_remove(self.__waiting_timeout) self.__waiting_timeout = None self.__sync() def close(self) -> None: """Close the manager, perform cleanup.""" self.__config_manager.nextcloud_prune_threshold = self.__sync_worker.prune_threshold def reset_marker(self) -> None: """Reset the most recent sync timestamp market.""" self.__sync_worker.reset_prune_threshold() def sign_out(self) -> None: """Sign out from the sync server.""" self.__sync_worker.sign_out() def flush_pending_deletions(self) -> None: """Flush any notes awaiting their pending undo period.""" notes_pending_undo = self.__note_manager.get_deleted_notes_pending_undo() if notes_pending_undo and self.authenticated: for note in notes_pending_undo: if note.has_remote_id: self.sync_now() break self.__note_manager.set_deleted_notes_pending_undo([]) def start_login( self, server_uri: str, window: Gtk.Window ) -> tuple[LoginRequestResult, Optional[str], Optional[str]]: """Initiate a new login. :param str server_uri: Server instance URI :param Gtk.Window window: Main window :return: Tuple with LoginRequestResult before endpoint URI and auth token (or Nones on failures) :rtype: tuple[LoginRequestResult, Optional[str], Optional[str]] """ return self.__sync_worker.start_login(server_uri, window) def check_for_login_success(self, endpoint: str, token: str) -> tuple[bool, bool]: """Check whether login succeeded. :param str endpoint: Endpoint URI :param str token: Request token :return: Whether authenticated and whether auth. storage succeeded :rtype: tuple[bool, bool] """ return self.__sync_worker.check_endpoint_for_auth_token(endpoint, token) def download_attachments( self, attachments: dict[str, Attachment], on_thread: bool ) -> Optional[bool]: """Fetch attachments from server. :param dict[str, Attachment] attachments: Attachments to transfer :param bool on_thread: Whether to work on background thread :return: Success when not working on thread :rtype: bool, optional """ def work(attachments: dict[str, Attachment]) -> bool: had_failure = False for attachment in attachments.values(): if not self.__download_single_attachment(attachment): had_failure = True return not had_failure if on_thread: thread = Thread(target=work, args=(attachments,)) thread.daemon = True thread.start() return None else: return work(attachments) @GObject.Property(type=bool, default=False) def authenticated(self) -> bool: return self.__authenticated @authenticated.setter def set_authenticated(self, new_val: bool) -> None: self.__authenticated = new_val @GObject.Property(type=bool, default=False) def configured_but_no_password(self) -> bool: return ( self.__config_manager.nextcloud_endpoint != "" and self.__config_manager.nextcloud_username != "" and not self.authenticated ) @GObject.Property(type=bool, default=False) def offline(self) -> bool: return self.__offline @offline.setter def set_offline(self, new_val: bool) -> None: self.__offline = new_val def __on_initial_note_load_complete(self) -> None: if self.__config_manager.nextcloud_username != "": GLib.timeout_add(self.STARTUP_SYNC_INIT_DURATION, self.__perform_initial_sync) def __sync(self) -> None: self.__waiting_timeout = None if self.__lock.locked: self.__sync_requested_while_active = True return GLib.idle_add(self.emit, "started") thread = Thread(target=self.__sync_on_thread) thread.daemon = True thread.start() def __sync_on_thread(self) -> None: logging.debug("Refresh....") self.__lock.acquire() self.__sync_requested_while_active = False start_time = time.time() fetching_all = self.__sync_worker.prune_threshold == 0 sync_result = self.__sync_worker.get_notes() if sync_result.success: logging.debug("Server GET took {:.2f}s".format(time.time() - start_time)) else: logging.info(f"Refresh failed with status code {sync_result.status_code}") # Ensure our API check gets run, just in case a major API version issue is causing # the issue self.__api_check_and_settings_sync() self.__finish_sync(0) self.__sync_fail_counter += 1 if not self.__offline and self.__sync_fail_counter >= self.SYNC_FAIL_OFFLINE_THRESHOLD: logging.info("Flagging offline") self.offline = True return self.__sync_fail_counter = 0 if self.__offline: logging.info("Recovered connectivity") self.offline = False notes = sync_result.data assert notes is not None remote_ids_from_db = self.__db.get_all_notes_remote_ids() # logging.debug("Pulled {} notes".format(len(notes))) # Determine remote creations and updates (remote_new, remote_upd) = self.__determine_remote_new_and_updated( notes, remote_ids_from_db, fetching_all ) # Remove duplicate updates caused by eg. ignored No-Cache headers remote_upd = self.__filter_out_false_updates(remote_upd) # Pre-processing for remote updates to notes which have local changes remote_upd = self.__preprocess_remote_updates_for_locally_modified(remote_upd) # Determine any remote deletions sync_server_remote_ids = [v["id"] for v in notes] remote_del = list(set(remote_ids_from_db) - set(sync_server_remote_ids)) # Check for delete conflicts self.__check_for_remote_delete_conflicts(remote_del) # Determine, sync and locally apply local deletions local_del = self.__apply_local_deletions() # Determine and sync local updates local_upd = self.__apply_local_updates() # Determine and sync local creations local_new = self.__apply_local_creations() changes_out = len(local_new + local_upd + local_del) if changes_out > 0: logging.debug( "Changes OUT: %s new %s upd %s del", len(local_new), len(local_upd), len(local_del), ) changes_in = len(remote_new + remote_upd + remote_del) if changes_in > 0: logging.debug( "Changes IN: %s new %s upd %s del", len(remote_new), len(remote_upd), len(remote_del), ) if changes_in > 0: # Integrate remote changes, batching for large initial transfers if len(remote_new) > self.MIN_NEW_NOTES_FOR_BATCHING: batch_size = self.SYNC_BATCH_SIZE else: batch_size = self.MIN_NEW_NOTES_FOR_BATCHING for i in range(0, max(1, len(remote_new)), batch_size): if len(remote_new) > 0: batch = remote_new[i : i + batch_size] else: batch = [] idle_add_wait(self.__integrate_remote_changes, batch, remote_upd, remote_del) remote_upd = [] remote_del = [] # API check and settings sync are slung onto the back of the first request so that first # sync isn't as delayed. Justified by the fact that the outcome of the API check isn't # currently impacting behaviour; this may move. self.__api_check_and_settings_sync() self.__finish_sync(changes_in + changes_out) def __determine_remote_new_and_updated( self, notes: list[dict], remote_ids_from_db: list[int], force_refresh_all: bool ) -> tuple[list[dict], list[dict]]: create = [] update = [] for sync_note in notes: # Notes before the prune cutoff will only have an "id" item if len(sync_note) == 1: continue if sync_note["id"] not in remote_ids_from_db: create.append(sync_note) elif force_refresh_all or self.__db.note_needs_update( sync_note["id"], sync_note["etag"] ): update.append(sync_note) return (create, update) def __filter_out_false_updates(self, updates_in: list[dict]) -> list[dict]: updates_out = [] for remote_note_dict in updates_in: # Fetch note local_note = self.__note_manager.fetch_note_by_remote_id(remote_note_dict["id"]) if local_note is None: logging.warning( f"Failed to find local note with remote id '{remote_note_dict['id']}'" ) continue # Handle possible false updates from misbehaving proxies etc remote_note = Note.from_nextcloud(remote_note_dict) if local_note.etag_is_recent(remote_note.etag): if local_note.identical_non_sync_meta(remote_note): # The update from the server is an ETag from a recent push with no metadata # changes, we're likely receiving cached or otherwise old content. Ignore the # update. logging.debug( f"Remote note appears to be a past push, etag '{remote_note.etag}'" ) # Skip adding for further processing continue else: if not local_note.content_loaded: self.__db.populate_note_content(local_note) if local_note.dirty and local_note.content == remote_note.content: # If our local note has changed for something other than content we # possibly have a real conflict. Allow falling through to that. logging.debug( "Note update received for locally modified note with no etag change " "and no content change" ) else: # Possibly just a remote metadata change, but let's ignore the # content to be safe logging.debug("Note received with past etag but meta update") remote_note_dict["ignore-content"] = True updates_out.append(remote_note_dict) return updates_out def __preprocess_remote_updates_for_locally_modified( self, updates_in: list[dict] ) -> list[dict]: updates_out = [] for remote_note_dict in updates_in: # Fetch note local_note = self.__note_manager.fetch_note_by_remote_id(remote_note_dict["id"]) if local_note is None: logging.warning( f"Failed to find local note with remote id '{remote_note_dict['id']}'" ) continue # Duplicate filtering can flag notes for which content changes should be ignored ignore_content_change = "ignore-content" in remote_note_dict # Handle local note with changes if local_note.dirty and not ignore_content_change: remote_note = Note.from_nextcloud(remote_note_dict) new_dirty = False if not local_note.content_loaded: self.__db.populate_note_content(local_note) if local_note.identical_excepting_sync_meta(remote_note): logging.info("Applying remote sync meta to otherwise identical note") elif self.__conflict_is_recent_failed_push(local_note, remote_note): # The remote note is an older version of the local note. We attempted to sync # it but didn't receive an ack and as a result our local etag is out of date. # So we update the etag and ignore everything else. logging.info( "Avoiding conflict as remote note with updated etag appears to be " "a failed past push" ) local_note.etag = remote_note.etag self.__db.persist_note_etag(local_note) # Skip adding for further processing continue else: logging.info( f"Sync. conflict, note '{local_note.title}' was modified locally and " "updated remotely" ) GLib.idle_add(self.emit, "note-conflict", local_note) # Duplicate existing note GLib.idle_add(self.__duplicate_note_for_sync_conflict, local_note) local_note.dirty = new_dirty self.__db.persist_note_dirty(local_note) updates_out.append(remote_note_dict) return updates_out def __check_for_remote_delete_conflicts(self, remote_del: list[int]) -> None: for remote_id in remote_del: note = self.__note_manager.fetch_note_by_remote_id(remote_id) if note is None: continue if note.dirty and not note.locally_deleted: GLib.idle_add(self.emit, "note-conflict", note) # Duplicate existing note logging.info( "Sync. conflict, note '%s' was modified locally and deleted remotely", note.title, ) GLib.idle_add(self.__duplicate_note_for_sync_conflict, note) note.dirty = False self.__db.persist_note_dirty(note) def __apply_local_updates(self) -> list[Note]: local_upd = [ v for v in self.__note_manager.base_model if v.dirty and not v.locally_deleted and v.remote_id >= 0 ] for note in local_upd: if not note.content_loaded: self.__db.populate_note_content(note) note.saving = True res = self.__sync_worker.update_note(note) idle_add_wait(self.__update_note_metadata_post_sync, note, res) return local_upd def __apply_local_creations(self) -> list[Note]: local_new = [ n for n in self.__note_manager.base_model if n.has_id and n.dirty and not n.locally_deleted and n.remote_id < 0 ] for note in local_new: if not note.content_loaded: self.__db.populate_note_content(note) note.saving = True res = self.__sync_worker.create_note(note) idle_add_wait(self.__update_note_metadata_post_sync, note, res) return local_new def __apply_local_deletions(self) -> list[Note]: local_del_queue = [ n for n in self.__note_manager.base_model if n.locally_deleted and n not in self.__note_manager.get_deleted_notes_pending_undo() ] local_del = [] for note in local_del_queue: # logging.debug("Processing {} in local_del_queue".format(len(local_del_queue))) if note.remote_id >= 0: res = self.__sync_worker.delete_note(note) if res.success: local_del.append(note) else: local_del.append(note) if len(local_del) > 0: for note in local_del: self.__db.delete_note(note.id) idle_add_wait(self.__note_manager.remove_notes_from_model, local_del) return local_del def __finish_sync(self, number_of_changes: int) -> None: GLib.idle_add(self.emit, "finished", number_of_changes) if self.__sync_requested_while_active: self.__lock.release() self.__sync() else: self.__waiting_timeout = GLib.timeout_add_seconds(self.__sync_interval, self.__sync) self.__lock.release() def __integrate_remote_changes( self, remote_new: list[dict], remote_upd: list[dict], remote_del: list[int] ) -> None: for sync_note in remote_new + remote_upd: existing_note = self.__note_manager.fetch_note_by_remote_id(sync_note["id"]) if existing_note: if not existing_note.content_loaded: self.__db.populate_note_content(existing_note) old_category = existing_note.category updated_fields = existing_note.update_from_remote_sync(sync_note) # Updated fields can be empty when doing a schema migration full resync if updated_fields.empty(): continue self.__db.persist_note_selective(existing_note, updated_fields) if updated_fields.category: self.__category_manager.note_category_changed( old_category, existing_note.category ) else: note = Note.from_nextcloud(sync_note) self.__db.add_note(note) self.__note_manager.add_notes_to_model([note]) self.__category_manager.note_added(note.category) remove_notes = [] for remote_id in remote_del: deleted_note = self.__note_manager.fetch_note_by_remote_id(remote_id) if deleted_note is not None: self.emit("note-deleted", deleted_note) remove_notes.append(deleted_note) if len(remove_notes) > 0: self.__note_manager.delete_notes(remove_notes, provide_undo=False) def __duplicate_note_for_sync_conflict(self, note: Note) -> None: if not note.content_loaded: self.__db.populate_note_content(note) # Translators: Description, used as a prefix to the previous title for notes updated both # locally and remotely. " - " is placed between this prefix and the title. reason = _("SYNC CONFLICT") new_note = self.__db.create_duplicate_note(note, reason) self.__note_manager.add_notes_to_model([new_note]) self.__category_manager.note_added(new_note.category) new_note.saving = True res = self.__sync_worker.create_note(new_note) self.__update_note_metadata_post_sync(new_note, res) def __update_note_metadata_post_sync( self, note: Note, sync_result: ContentPushSyncResult ) -> None: if sync_result.success: previous_category = note.category remote_category = sync_result.data["category"] self.__note_manager.update_note_post_sync(note, sync_result) if previous_category != remote_category: GLib.idle_add( self.emit, "remote-category-sanitised", previous_category, remote_category ) else: logging.info(f"Note push failed (with status code {sync_result.status_code})") if sync_result.sent_content is not None: # Track this failed push so that it can be used to avoid possible conflicts if the # push actually did make it to the server but we haven't received the tag to update. self.__track_failed_push(note, sync_result.sent_content) else: logging.warning("Wanted to track failed push with null sent content") note.saving = False if not sync_result.success or note.dirty_while_saving: note.flag_changed(update_last_modified=False) note.dirty_while_saving = False def __on_sync_ready(self, _obj: GObject.Object, new_setup: bool) -> None: GLib.idle_add(self.emit, "ready", new_setup) if new_setup or self.__initial_sync_delay_complete: self.sync_now() def __on_missing_password(self, _obj: GObject.Object) -> None: if self.configured_but_no_password: logging.info( "Sync is configured but password missing. Login to the server to reauthenticate." ) self.emit("missing-password") def __on_api_check_finished(self, _obj: GObject.Object) -> None: self.__api_check_complete = True thread = Thread(target=self.__sync_worker.fetch_settings) thread.daemon = True thread.start() def __on_settings_fetched(self, _obj: GObject.Object, file_suffix: str) -> None: if self.__config_manager.backup_note_extension != file_suffix: logging.info( f"Changed backup note filename extension to '{file_suffix}' " "as received from server" ) self.__config_manager.backup_note_extension = file_suffix def __set_sync_interval(self) -> None: self.__sync_interval = self.__config_manager.sync_interval def __api_check_and_settings_sync(self) -> None: # API check and settings sync are slung onto the back of the first request so that first # sync isn't as delayed. Justified by the fact that the outcome of the API check isn't # currently impacting behaviour. if not self.__api_check_complete: thread = Thread(target=self.__sync_worker.check_capabilities) thread.daemon = True thread.start() def __perform_initial_sync(self) -> None: self.__initial_sync_delay_complete = True self.sync_now() def __track_failed_push(self, note: Note, sent_content: str) -> None: hash = sha256(sent_content.encode("utf-8")).hexdigest() length = len(sent_content) timestamp = int(time.time()) push = FailedPush(hash, length, timestamp) self.__note_manager.add_failed_push(note, push) def __conflict_is_recent_failed_push(self, note: Note, remote_note: Note) -> bool: pushes = self.__note_manager.get_note_failed_pushes(note) if not pushes: return False hash = sha256(remote_note.content.encode("utf-8")).hexdigest() length = len(remote_note.content) matched = False for push in pushes: if push.hash == hash and push.length == length: logging.info("Changed etag matches failed push, conflict avoided") matched = True break return matched def __download_single_attachment(self, attachment: Attachment) -> bool: self.__check_and_warn_for_other_note_attachment(attachment) data = self.__sync_worker.get_attachment(attachment) if not data: logging.warning(f"Failed to download attachment '{attachment.path}'") return False if not self.__db.get_note_by_remote_id(attachment.note_remote_id): logging.warning("Discarding attachment for removed note") # Returning true as this isn't a failure return True if not write_attachment_to_disk(attachment, data): return False GLib.idle_add(self.emit, "attachment-downloaded", attachment) return True def __check_and_warn_for_other_note_attachment(self, attachment: Attachment) -> None: path = attachment.path this_note_prefix = f".attachments.{attachment.note_remote_id}/" if path.startswith(".attachments.") and not path.startswith(this_note_prefix): logging.warning( f"Attachment '{attachment.filename}' appears to belong to another note. " "This is unsupported; unpredictable behaviour ahead." ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/sync_result.py000066400000000000000000000061651507102636600244550ustar00rootroot00000000000000from __future__ import annotations import logging from requests import Response from requests.exceptions import JSONDecodeError from typing import Any, NamedTuple, Optional class ResponseParseException(Exception): """Generic exception parsing response.""" class SyncResult(NamedTuple): success: bool status_code: Optional[int] = None data: Optional[list[dict]] = None @staticmethod def from_requests_response(response: Optional[Response]) -> SyncResult: """Create SyncResult from requests response. :param Optional[Response] response: The response :return: Object containing sync results :rtype: Self """ try: success, response_json = parse_response(response) except ResponseParseException: success = False return SyncResult(success) if not isinstance(response_json, list): logging.warning(f"Data from server unexpected type {type(response_json)}") success = False return SyncResult(success) return SyncResult(success, response.status_code, response_json) class ContentPushSyncResult(NamedTuple): success: bool status_code: Optional[int] data: Any sent_content: Optional[str] @staticmethod def from_requests_response( response: Optional[Response], sent_content: Optional[str] ) -> ContentPushSyncResult: """Create ContentPushSyncResult from requests response and sent content. The sent content is included here so it can be used in retaining a hash for failed pushes (which assist with false sync conflicts on high packet loss connections). :param Optional[Response] response: The response :param Optional[str] sent_content: The content as sent in the request :return: Object containing sync results and sent content :rtype: Self """ try: success, response_json = parse_response(response) except ResponseParseException: status_code = None if not response else response.status_code return ContentPushSyncResult(False, status_code, None, sent_content) assert response is not None # mypy return ContentPushSyncResult(success, response.status_code, response_json, sent_content) class FailedPush(NamedTuple): hash: str length: int timestamp: int def parse_response(response: Optional[Response]) -> tuple[bool, dict]: """Parse requests response. :param Optional[Response] response: The response :return: Whether the request was a success and the parsed response JSON :rtype: tuple[bool, dict] :raises ResponseParseException: If the response could not be parsed """ if response is None: logging.debug("parse_response received null response") raise ResponseParseException("No response") try: response_json = response.json() except JSONDecodeError as e: logging.warning(f"Failed to decode server JSON response: {e}") raise ResponseParseException("Failed to decode JSON") success = response.status_code == 200 return (success, response_json) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/table_dialog.py000066400000000000000000000126541507102636600245110ustar00rootroot00000000000000from gi.repository import Adw, Gio, GLib, GObject, Gtk import logging import time @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/table_dialog.ui") class TableDialog(Adw.Dialog): """Table creation dialog.""" __gtype_name__ = "TableDialog" __gsignals__ = { "create": (GObject.SignalFlags.RUN_FIRST, None, (int, int)), } GRID_WIDTH = 6 GRID_HEIGHT = 5 DEFAULT_HEIGHT = 3 DEFAULT_WIDTH = 3 _size_grid: Gtk.Grid = Gtk.Template.Child() _size_label: Gtk.Label = Gtk.Template.Child() _button: Gtk.Button = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__width = self.DEFAULT_WIDTH self.__height = self.DEFAULT_HEIGHT self.__hover_timeout_id = None self.__hover_until = 0.0 self.__build() self.connect("closed", lambda _o: self.__cleanup()) def show(self, parent: Gtk.Window) -> None: """Show dialog. :param Gtk.Window window: Parent window """ self.width = self.DEFAULT_WIDTH self.height = self.DEFAULT_HEIGHT for action in self.__action_group.list_actions(): self.__action_group.lookup_action(action).set_enabled(True) self.present(parent) @GObject.Property(type=int) def width(self) -> int: return self.__width @width.setter def set_width(self, value: int) -> None: self.__width = value self.__update_grid() @GObject.Property(type=int) def height(self) -> int: return self.__height @height.setter def set_height(self, value: int) -> None: self.__height = value self.__update_grid() @Gtk.Template.Callback() def _on_button_clicked(self, _obj: Gtk.Button) -> None: self.__create() def __build(self) -> None: for row in range(self.GRID_HEIGHT): for column in range(self.GRID_WIDTH): button = Gtk.Button.new() self._size_grid.attach(button, column, row, 1, 1) def clicked(_o, width, height) -> None: logging.info(f"Chose {width}x{height}") self.width = width self.height = height button.connect("clicked", clicked, column + 1, row + 1) controller = Gtk.EventControllerMotion.new() controller.connect("enter", self.__on_motion_enter, row, column) button.add_controller(controller) controller = Gtk.EventControllerMotion.new() controller.connect("leave", lambda _o: self.__on_motion_leave()) self._size_grid.add_controller(controller) action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() action = Gio.SimpleAction.new("submit") action.connect("activate", lambda _a, _p: self.__create()) action_group.add_action(action) app.set_accels_for_action("table-dialog.submit", ["Return"]) app.get_active_window().insert_action_group("table-dialog", action_group) self.__action_group = action_group def __update_grid(self) -> None: label = f"{self.width} x {self.height}" self._size_label.set_text(label) for row in range(self.GRID_HEIGHT): for column in range(self.GRID_WIDTH): button = self._size_grid.get_child_at(column, row) if self.width >= column + 1 and self.height >= row + 1: button.add_css_class("on") else: button.remove_css_class("on") def __on_motion_enter( self, motion: Gtk.EventControllerMotion, x: float, y: float, row: int, column: int ) -> None: # Hacky avoidance of motion on possibly mobile device. Without this (in Sept. 2024) a hover # pseudoclass is left on the buttons. if self.get_width() <= 360: return # If no motion hide hover after a second self.__hover_until = time.time() + 1 if self.__hover_timeout_id is None: self.__hover_timeout_id = GLib.timeout_add( 1000, self.__hover_timeout, ) self.__update_hover(row, column) def __on_motion_leave(self) -> None: if self.__hover_timeout_id is not None: GLib.source_remove(self.__hover_timeout_id) self.__hover_timeout_id = None self.__update_hover(-1, -1) def __update_hover(self, hover_row: int, hover_column: int) -> None: for row in range(self.GRID_HEIGHT): for column in range(self.GRID_WIDTH): button = self._size_grid.get_child_at(column, row) if hover_column >= column and hover_row >= row: button.add_css_class("hovering") else: button.remove_css_class("hovering") def __hover_timeout(self) -> None: extra_hover = self.__hover_until - time.time() if extra_hover > 0.0: self.__hover_timeout_id = GLib.timeout_add( extra_hover * 1000.0, self.__hover_timeout, ) return self.__update_hover(-1, -1) self.__hover_timeout_id = None def __create(self) -> None: self.emit("create", self.width, self.height) self.close() def __cleanup(self) -> None: for action in self.__action_group.list_actions(): self.__action_group.lookup_action(action).set_enabled(False) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/template_html_generator.py000066400000000000000000000201361507102636600270020ustar00rootroot00000000000000from gi.repository import Gio import html from typing import Callable, NamedTuple, Optional from markdown_it.token import Token from markdown_it.utils import EnvType, OptionsDict from iotas.html_generator import HtmlGenerator from iotas.html_generator_configuration import HtmlGeneratorConfiguration from iotas.note import Note from iotas.text_utils import has_unicode class TemplateDetails(NamedTuple): """Template string parameters.""" html: str javascript: str css: str search_css: str class TemplateHtmlGenerator(HtmlGenerator): """Generate HTML from note contents using a template.""" EXPORT_CSS_PATH = "css/markdown.css" EXPORT_KATEX_CSS_PATH = "css/katex.min.css" EXPORT_KATEX_JS_PATH = "js/katex.min.js" # Dark 3 TEXT_COLOUR_LIGHT = "#504e55" TEXT_COLOUR_LIGHT_HIGH_CONTRAST = "#000000" # Light 5 TEXT_COLOUR_DARK = "#c0bfbc" TEXT_COLOUR_DARK_HIGH_CONTRAST = "#ffffff" def __init__( self, config_manager: HtmlGeneratorConfiguration, app_data_path: str, toolbar_underlay_padding_height: int, custom_template_loader: Optional[Callable[[], TemplateDetails]] = None, ) -> None: super().__init__() self.__config_manager = config_manager self.__app_data_path = app_data_path self.__toolbar_underlay_padding_height = toolbar_underlay_padding_height self.__font_family = "" self.__html_template: Optional[str] = None self.__javascript_template: str self.__configurable_css_template: str self.__searching_css: str self.__template_loader = ( custom_template_loader if custom_template_loader else self.__populate_template_from_resources ) def generate( self, note: Note, tokens: list[Token], render_func: Callable[[list[Token], OptionsDict, EnvType], str], parser_options: OptionsDict, searching: bool, export_format: Optional[str], scroll_position: Optional[float] = None, ) -> str: """Generator HTML for note. :param Note note: Note to render :param list[Token] tokens: Parser tokens :param Callable[[list[Token], OptionsDict, EnvType], str] render_fun: Render function :param OptionsDict parser_options: Parser options :param bool searching: Whether search CSS should be included :param Optional[str] export_format: Export format, if using :param Optional[float] scroll_position: Position to scroll to :return: Generated HTML :rtype: str """ for token in tokens: if token.map: token.attrs["data-map"] = token.map[0] content = render_func(tokens, parser_options, None) if self.__html_template is None: self.__populate_templates() assert self.__html_template javascript = "" exporting = export_format is not None if not exporting: scroll_js = "" if scroll_position is not None: scroll_js = f"""document.documentElement.scrollTop = {scroll_position} * (document.documentElement.scrollHeight - document.documentElement.clientHeight); """ javascript = self.__javascript_template % (str(not note.read_only).lower(), scroll_js) javascript = f"\n \n" if export_format == "html": css_path = self.EXPORT_CSS_PATH katex_css_path = self.EXPORT_KATEX_CSS_PATH katex_js_path = self.EXPORT_KATEX_JS_PATH else: css_path = f"{self.__app_data_path}/{self.RESOURCE_CSS_PATH}" katex_css_path = f"{self.__app_data_path}/{self.RESOURCE_KATEX_CSS_PATH}" katex_js_path = f"{self.__app_data_path}/{self.RESOURCE_KATEX_JS_PATH}" if self.__config_manager.markdown_tex_support: tex_headers = f'\n ' tex_headers += f'\n ' else: tex_headers = "" if has_unicode(content): meta_headers = '\n ' else: meta_headers = "" configurable_stylesheet = "" if export_format == "html": stylesheet = self.generate_user_stylesheet(searching) configurable_stylesheet = f"\n " content = self.__html_template.format( title=html.escape(note.title), css_path=css_path, meta_headers=meta_headers, configurable_stylesheet=configurable_stylesheet, tex_headers=tex_headers, javascript=javascript, content=content, ) return content def generate_user_stylesheet(self, searching: bool) -> str: """Generate part of stylesheet based on state (configuration etc). :param bool searching: Whether searching :return: stylesheet :rtype: str """ if self.__html_template is None: self.__populate_templates() new_size = self.__get_font_size() new_length = self.__config_manager.line_length backup_font = ( "monospace" if self.__config_manager.markdown_use_monospace_font else "sans-serif" ) families = [self.__font_family, backup_font] new_font_family = ", ".join(families) if self.__config_manager.editor_header_bar_visible_for_window_state: new_margin = 1 else: new_margin = self.__toolbar_underlay_padding_height if self.__config_manager.high_contrast: light_text_colour = self.TEXT_COLOUR_LIGHT_HIGH_CONTRAST dark_text_colour = self.TEXT_COLOUR_DARK_HIGH_CONTRAST figcaption_opacity = "1.0" else: light_text_colour = self.TEXT_COLOUR_LIGHT dark_text_colour = self.TEXT_COLOUR_DARK figcaption_opacity = "0.85" stylesheet = self.__configurable_css_template % ( light_text_colour, figcaption_opacity, new_size, new_length, new_font_family, new_margin, dark_text_colour, ) if searching: stylesheet += self.__searching_css return stylesheet def update_font_family(self, family: str) -> None: """Update the font family. :param str family: New font family """ self.__font_family = family def __get_font_size(self) -> float: monospace_editor = self.__config_manager.use_monospace_font monospace_render = self.__config_manager.markdown_use_monospace_font editor_size = self.__config_manager.font_size ratio = self.__config_manager.markdown_render_monospace_font_ratio if monospace_editor and not monospace_render: size = editor_size / ratio elif monospace_render and not monospace_editor: size = editor_size * ratio else: size = editor_size return size def __populate_templates(self) -> None: if self.__html_template is not None: return details = self.__template_loader() self.__html_template = details.html self.__javascript_template = details.javascript self.__configurable_css_template = details.css self.__searching_css = details.search_css def __populate_template_from_resources(self) -> TemplateDetails: return TemplateDetails( self.__load_object_from_resource("template.html"), self.__load_object_from_resource("binding.js"), self.__load_object_from_resource("configurable.css"), self.__load_object_from_resource("searching.css"), ) def __load_object_from_resource(self, filename: str) -> str: f = Gio.File.new_for_uri(f"resource:///org/gnome/World/Iotas/render-template/{filename}") (status, contents, _tag) = f.load_contents() if not status: raise Exception(f"Failed to load resource {filename}") return contents.decode("utf-8") iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/text_utils.py000066400000000000000000000172771507102636600243150ustar00rootroot00000000000000import gi gi.require_version("GtkSource", "5") from gi.repository import GLib, Gtk, GtkSource import logging import re from typing import NamedTuple, Optional class ParsedLink(NamedTuple): """Parsed general link.""" link: str """Link URL""" start_offset: int """Start offset""" end_offset: int """End offset""" class ParsedInlineLink(NamedTuple): """Parsed markdown inline link.""" link: str = "" """Link URL""" text: str = "" """Link text""" source_text: str = "" """Source text""" start_offset: int = -1 """Start offset""" end_offset: int = -1 """End offset""" url_angle_bracketed: bool = False """Angle-bracket wrapped URL""" title: str = "" """Link title""" class ParsedAutomaticLink(NamedTuple): """Parsed markdown automatic link.""" link: str """Link URL""" start_offset: int """Start offset""" end_offset: int """End offset""" source_text: str """Source text""" def sanitise_path(path: str) -> str: """Sanitise path for filesystem storage. :param str path: The path to work on :return: The sanitised path :rtype: str """ # This is close to a direct translation of what Nextcloud Notes is using. # Remove characters which are illegal on Windows (includes illegal characters on Unix/Linux) # prevents also directory traversal by eliminiating slashes for token in ["*", "|", "/", "\\", ":", '"', "<", ">", "?"]: path = path.replace(token, "") # Prevent file being hidden path = re.sub(r"^[\.\s]+", "", path) return path.strip() def has_unicode(input: str) -> bool: has_unicode = False try: input.encode(encoding="ascii") except UnicodeEncodeError: has_unicode = True return has_unicode def parse_any_url_at_iter(iter: Gtk.TextIter, http_only: bool) -> Optional[ParsedLink]: """Check and parse location in buffer to URL. :param Gtk.TextIter iter: Iter :param bool http_only: Whether only http/s URIs will pass :return: Object with link details, optional :rtype: ParsedLink """ start = iter.copy() end = iter.copy() def whitespace_at_iter(itr: Gtk.TextIter) -> bool: char_end = itr.copy() char_end.forward_char() char = itr.get_text(char_end) return char in (" ", "\t", "\n") # Find preceding whitespace moved = False while not start.is_start() and not whitespace_at_iter(start): moved = True start.backward_char() if moved and not (start.is_start() and not whitespace_at_iter(start)): start.forward_char() # Find following whitespace while not end.is_end() and not whitespace_at_iter(end): end.forward_char() # Grab text between linespace breaks and see if GLib thinks it's a URL, populate text = start.get_text(end) if str_is_url(text, http_only): return ParsedLink(text, start.get_offset(), end.get_offset()) else: return None def parse_markdown_inline_link(inside: Gtk.TextIter) -> Optional[ParsedInlineLink]: """Parse link elements from a known inline link. :param Gtk.TextIter inside: Iter inside inline link :return: Object with link details, optional :rtype: ParsedInlineLink """ start, end = get_iters_at_sourceview_context_class_extents("inline-link", inside) if not start or not end: return None source_text = inside.get_buffer().get_text(start, end, include_hidden_chars=False) # Parsing logic here is a little brittle, reflecting being in this block is predicated on # the GtkSourceView language parsing text, url_part = source_text.split("](") text = text[1:] url_part = url_part[:-1].strip() title = "" if url_part.endswith('"'): # We have a title, parse that out url_part, title = url_part[:-1].split('"') url_part = url_part.strip() if url_part.startswith("<") and url_part.endswith(">"): link = url_part[1:-1] angle_bracketed = True else: link = url_part angle_bracketed = False return ParsedInlineLink( link, text, source_text, start.get_offset(), end.get_offset(), angle_bracketed, title ) def parse_markdown_automatic_link(inside: Gtk.TextIter) -> Optional[ParsedAutomaticLink]: """Parse URL from a known markdown automatic link. :param Gtk.TextIter inside: Iter inside inline link :return: Object with link details, optional :rtype: ParsedAutomaticLink """ start, end = get_iters_at_sourceview_context_class_extents("automatic-link", inside) if not start or not end: return None link = start.get_text(end) if link.startswith("<") and link.endswith(">"): return ParsedAutomaticLink(link[1:-1], start.get_offset(), end.get_offset(), link) else: # Failure very unlikely as we depend on the GtkSourceView language parsing to reach # here logging.warning("Failed to parse automatic-link") return None def get_iters_at_sourceview_context_class_extents( cls: str, inside: Gtk.TextIter ) -> tuple[Optional[Gtk.TextIter], Optional[Gtk.TextIter]]: """Get text iterators at the extents of a context class. :param str cls: Context class name :param Gtk.TextIter: Iterator inside class :return: The iters :rtype: tuple[Optional[Gtk.TextIter], Optional[Gtk.TextIter]] """ start = inside.copy() if not iter_backward_to_context_class_start(start, cls): logging.warning("Backward to start of '{cls}' failed") return (None, None) end = start.copy() if not iter_forward_to_context_class_removed(end, cls): logging.warning("Forward to end of '{cls}' failed") return (None, None) return (start, end) def iter_backward_to_context_class_start(location: Gtk.TextIter, cls: str) -> bool: """Move text iterator back to start of context class. :param Gtk.TextIter location: Iterator inside class :param str cls: Context class name :return: Success :rtype: bool """ buffer: GtkSource.Buffer = location.get_buffer() if cls not in buffer.get_context_classes_at_iter(location): logging.debug(f"Not in '{cls}' at start to move backward") return False while not location.is_start(): location.backward_char() if cls not in buffer.get_context_classes_at_iter(location): location.forward_char() return True return location.is_start() def iter_forward_to_context_class_removed(location: Gtk.TextIter, cls: str) -> bool: """Move text iterator forward to end of context class. :param Gtk.TextIter location: Iterator inside class :param str cls: Context class name :return: Success :rtype: bool """ buffer: GtkSource.Buffer = location.get_buffer() if cls not in buffer.get_context_classes_at_iter(location): logging.debug(f"Not in '{cls}' at start to move forward") return False while not location.is_end(): location.forward_char() if cls not in buffer.get_context_classes_at_iter(location): return True return location.is_end() def str_is_url(text: str, http_only: bool) -> bool: """Get whether provided text is a URL. :param str text: The text to check :param bool http_only: Whether only http/s URIs will pass :return: Whether a URL :rtype: bool """ valid = False try: valid = GLib.uri_is_valid(text, GLib.UriFlags.NONE) except GLib.GError: pass # GLib's Uri.is_valid appears to allow eg. http:someurl.com if valid and http_only: scheme = GLib.uri_peek_scheme(text) if scheme not in ("http", "https") or not text.startswith(f"{scheme}://"): valid = False return valid iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/theme_selector.py000066400000000000000000000027331507102636600251020ustar00rootroot00000000000000from gi.repository import Gio, Gtk from iotas.config_manager import ConfigManager @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/theme_selector.ui") class ThemeSelector(Gtk.Box): __gtype_name__ = "ThemeSelector" _follow: Gtk.CheckButton = Gtk.Template.Child() _light: Gtk.CheckButton = Gtk.Template.Child() _dark: Gtk.CheckButton = Gtk.Template.Child() def __init__(self) -> None: super().__init__() self.__config_manager = ConfigManager.get_default() self.__populate() self.__config_manager.connect_changed(ConfigManager.STYLE, self.__populate) @Gtk.Template.Callback() def _on_option_selected(self, _widget: Gtk.CheckButton) -> None: name = None if self._follow.get_active(): name = "follow" elif self._light.get_active(): name = "light" elif self._dark.get_active(): name = "dark" # Name can be null when checkbutton is unchecked for radio group. A positive check will # follow. if name and self.__config_manager.style != name: self.__config_manager.style = name app = Gio.Application.get_default() app.apply_style() def __populate(self) -> None: style = self.__config_manager.style if style == "follow": self._follow.set_active(True) elif style == "light": self._light.set_active(True) else: self._dark.set_active(True) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/ui_utils.py000066400000000000000000000127731507102636600237420ustar00rootroot00000000000000from gettext import gettext as _ from gi.repository import Adw, Gdk, Gio, GLib, GObject, Gtk from functools import wraps from threading import Event from typing import Any, Callable, Optional class ComboRowHelper(GObject.Object): __gsignals__ = { "changed": (GObject.SignalFlags.RUN_FIRST, None, (str,)), } def __init__( self, combo: Adw.ComboRow, options: dict[str, str], selected: str, ) -> None: super().__init__() self.__option_keys = list(options.keys()) model = Gtk.StringList() for v in options.values(): model.append(v) combo.set_model(model) combo.set_selected(self.__option_keys.index(selected)) combo.connect("notify::selected", self.__on_selection_change) def __on_selection_change(self, obj: Adw.ComboRow, param: GObject.ParamSpec) -> None: index = obj.get_property(param.name) if index >= len(self.__option_keys): return selected_key = self.__option_keys[index] self.emit("changed", selected_key) def add_mouse_button_accel( widget: Gtk.Widget, function: Callable[[Any, int, float, float], None], propagation: Gtk.PropagationPhase = Gtk.PropagationPhase.BUBBLE, ) -> None: """Add a mouse button gesture. :param Gtk.Widget widget: Widget to add on :param Callable[[], None] function: Callback function :param Gtk.PropagationPhase propagation: Propagation phase """ gesture = Gtk.GestureClick.new() gesture.set_button(0) gesture.set_propagation_phase(propagation) gesture.connect("pressed", function) widget.add_controller(gesture) # Keep the gesture in scope widget._gesture_click = gesture def idle_add_wait(function, *args, **kwargs) -> Any: """Execute function in the GLib main loop and wait. :param Callbable function: The function to call :param args: Any positional arguments :param kwargs: Any key word arguments :return: The result the function call :rtype: None or the result """ function_completed = Event() results = [] @wraps(function) def wrapper(): results.append(function(*args, **kwargs)) function_completed.set() return False GLib.idle_add(wrapper) function_completed.wait() return results.pop() def show_error_dialog(parent: Gtk.Widget, message: str) -> None: """Show a modal error dialog. :param Gtk.Widget parent: Parent widget :param str message: Message text """ # Translators: Title dialog = Adw.AlertDialog.new(_("Error"), message) # Translators: Button dialog.add_response("close", _("Close")) dialog.set_close_response("close") dialog.present(parent) def check_for_search_starting( controller: Gtk.EventControllerKey, keyval: int, state: Gdk.ModifierType ) -> bool: """Check if starting search via type to search. :param Gtk.EventControllerKey controller: The key controller :param int keyval: The key value :param Gdk.ModifierType state: Any modifier state :return: Whether search is starting :rtype: bool """ if keyval in ( Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter, Gdk.KEY_Tab, Gdk.KEY_KP_Tab, Gdk.KEY_Left, Gdk.KEY_KP_Left, Gdk.KEY_Right, Gdk.KEY_KP_Right, Gdk.KEY_Home, Gdk.KEY_KP_Home, Gdk.KEY_End, Gdk.KEY_KP_End, Gdk.KEY_Page_Up, Gdk.KEY_KP_Page_Up, Gdk.KEY_Page_Down, Gdk.KEY_KP_Page_Down, Gdk.KEY_Control_L, Gdk.KEY_Control_R, Gdk.KEY_Alt_L, Gdk.KEY_Alt_R, Gdk.KEY_Meta_L, Gdk.KEY_Meta_R, Gdk.KEY_Shift_L, Gdk.KEY_Shift_R, Gdk.KEY_BackSpace, Gdk.KEY_Delete, Gdk.KEY_KP_Delete, Gdk.KEY_Escape, ): return False elif state & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.ALT_MASK): return False else: return True # A concession for mobile device Gdk.Device entries seeming to report having cursors (at time of # writing in 2024). Currently being used to determine if the device likely isn't being driven by a # cursor and so as a result can't rely on hover interaction. It's obviously a loose match though, # somebody could be using a tiny window on desktop, landscape orientation on mobile or we're in the # future and 360 width is no longer relevant. Hence "likely". def is_likely_mobile_device() -> Optional[bool]: """Check if device is likely a mobile. Loose check, see comment. :returns: Whether likely a phone or None during initialisation :rtype: bool, optional """ app = Gio.Application.get_default() if not app: return None window = app.get_active_window() return window.get_width() <= 360 def have_window_with_width() -> bool: """Check if the window has been initialised and has a width. :returns: Whether window has a width. :rtype: bool """ app = Gio.Application.get_default() if not app: return False window = app.get_active_window() if not window: return False return window.get_width() > 0 def check_for_open_first_result_shortcut(keyval: int, state: Gdk.ModifierType) -> bool: """Check keyboard shortcut to activate first result has been pressed. :param int keyval: The key value :param Gdk.ModifierType state: Any modifier state :return: Whether pressed :rtype: bool """ return keyval == Gdk.KEY_Return and state & Gdk.ModifierType.ALT_MASK iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/uri_to_note_creator.py000066400000000000000000000041541507102636600261440ustar00rootroot00000000000000from gi.repository import GObject import logging from typing import NamedTuple, Optional from urllib.parse import urlparse, parse_qs from iotas.note import Note class UriParseResult(NamedTuple): success: bool note: Optional[Note] = None open: bool = False # Note: Iotas' addition of this URI handler is a stopgap measure until the freedesktop # intent system is fleshed out. The handling provided here will be unceremoniously removed # when that system is available and may be removed or modified without notice beforehand; # this is not a stable public interface. class UriToNoteCreator(GObject.Object): """Handles creation of notes from temporary iotas-notes:// URI.""" def __init__(self) -> None: super().__init__() def parse(self, uri: str) -> UriParseResult: """Parse URI to note. See comment in source re. interface. :param str uri: URI :return: Result :rtype: UriParseResult """ logging.debug(f"Handling {uri}") parsed = urlparse(uri) if parsed.scheme != "iotas-notes": logging.warning(f"Not handling schema '{parsed.scheme}'") return UriParseResult(False) if parsed.netloc != "create-note": logging.warning(f"Not handling unknown URI '{parsed.netloc}'") return UriParseResult(False) fields = parse_qs(parsed.query) if "content" not in fields or fields["content"][0].strip() == "": logging.warning("No content provided, not creating note from URI") return UriParseResult(False) if "title" not in fields or fields["title"][0].strip() == "": logging.warning("No title provided, not creating note from URI") return UriParseResult(False) note = Note() note.content = fields["content"][0] note.title = fields["title"][0] if "category" in fields and fields["category"][0].strip() != "": note.category = fields["category"][0] note.flag_changed() open = "open" in fields and fields["open"][0] == "1" return UriParseResult(True, note, open) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/webkit_pdf_exporter.py000066400000000000000000000107371507102636600261510ustar00rootroot00000000000000from gi.repository import GLib, Gtk import logging from typing import Any, Callable, Optional from iotas.note import Note from iotas.pdf_exporter import PdfExporter class WebKitPdfExporter(PdfExporter): # webkit type hinting avoided to allow for module lazy loading def __init__(self, render_view, keep_webkit_process: bool) -> None: super().__init__() self.__render_view = render_view self.__render_view.connect("loaded", lambda _o: self.__on_web_view_loaded()) self.__keep_webkit_process = keep_webkit_process self.__finished_callback: Callable[[], None] self.__error_callback: Callable[[str], None] self.__active = False self.__in_error = False def set_callbacks( self, finished_callback: Callable[[], None], error_callback: Callable[[str], None] ) -> None: """Set functions to be called upon export result. :param Callable finished_callback: Finished callback :param Callable error_callback: Error callback """ self.__finished_callback = finished_callback self.__error_callback = error_callback def export(self, note: Note, location: str) -> None: """Export PDF of note. :param Note note: Note to export :param str location: Destination location """ self.__note = note self.__location = location self.__active = True self.__in_error = False # Part of the effort to delay all WebKit initialisation if "WebKit" not in globals(): import gi gi.require_version("WebKit", "6.0") global WebKit from gi.repository import WebKit self.__render_view.render_retaining_scroll(self.__note, "pdf") def __on_web_view_loaded(self) -> None: if not self.__active: return printer_name = self.__get_printer_name() if printer_name is None: self.__in_error = True # Theoretically rare, avoiding translation for now self.__error_callback("Failed to locate virtual printer for export to PDF") return settings = Gtk.PrintSettings() settings.set(Gtk.PRINT_SETTINGS_PRINTER, printer_name) settings.set(Gtk.PRINT_SETTINGS_OUTPUT_FILE_FORMAT, "pdf") settings.set(Gtk.PRINT_SETTINGS_OUTPUT_URI, f"file://{self.__location}") page_setup = Gtk.PageSetup() page_setup.set_left_margin(54, Gtk.Unit.POINTS) page_setup.set_right_margin(54, Gtk.Unit.POINTS) operation = WebKit.PrintOperation.new(self.__render_view) # type: ignore [name-defined] operation.set_print_settings(settings) operation.set_page_setup(page_setup) def finished(_print_operation): logging.info(f"Exported pdf to {self.__location}") if not self.__keep_webkit_process: logging.info("Terminating WebKit process as holding disabled in preference") self.__render_view.terminate_web_process() if not self.__in_error: self.__finished_callback() self.__active = False def failed(_print_operation, error: GLib.Error): logging.warning(f"Failed to export pdf to {self.__location}: {error.message}") if not self.__keep_webkit_process: logging.info("Terminating WebKit process as holding disabled in preference") self.__render_view.terminate_web_process() self.__in_error = True self.__error_callback(error.message) operation.connect("finished", finished) operation.connect("failed", failed) operation.print_() def __get_printer_name(self) -> Optional[str]: default_language = Gtk.get_default_language().to_string() if default_language.startswith("en"): return "Print to File" else: virtual_printers = [] def check_printer(printer: Gtk.Printer, _data: Any) -> None: if printer.is_virtual(): virtual_printers.append(printer.get_name()) Gtk.enumerate_printers(check_printer, data=None, wait=True) if len(virtual_printers) == 1: return virtual_printers[0] elif not virtual_printers: logging.warning("No virtual printers found") return None else: logging.warning("See more than one virtual printer, can't identify Print to File") return None iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/widgets.py000066400000000000000000000035001507102636600235370ustar00rootroot00000000000000from gi.repository import GObject from iotas.category_header_bar import CategoryHeaderBar from iotas.editor import Editor from iotas.editor_rename_header_bar import EditorRenameHeaderBar from iotas.editor_search_entry import EditorSearchEntry from iotas.editor_search_header_bar import EditorSearchHeaderBar from iotas.editor_text_view import EditorTextView from iotas.first_start_page import FirstStartPage from iotas.font_size_selector import FontSizeSelector from iotas.formatting_header_bar import FormattingHeaderBar from iotas.index import Index from iotas.index_menu_button import IndexMenuButton from iotas.index_note_list import IndexNoteList from iotas.index_search_header_bar import IndexSearchHeaderBar from iotas.render_search_header_bar import RenderSearchHeaderBar from iotas.selection_header_bar import SelectionHeaderBar from iotas.sidebar import Sidebar from iotas.sidebar_row import SidebarRow from iotas.theme_selector import ThemeSelector def load_widgets() -> None: """Ensure that the types have been registered with the type system. Allows them to be used in template UI files. """ GObject.type_ensure(CategoryHeaderBar) GObject.type_ensure(Editor) GObject.type_ensure(EditorRenameHeaderBar) GObject.type_ensure(EditorSearchEntry) GObject.type_ensure(EditorSearchHeaderBar) GObject.type_ensure(EditorTextView) GObject.type_ensure(FirstStartPage) GObject.type_ensure(FontSizeSelector) GObject.type_ensure(FormattingHeaderBar) GObject.type_ensure(Index) GObject.type_ensure(IndexMenuButton) GObject.type_ensure(IndexNoteList) GObject.type_ensure(IndexSearchHeaderBar) GObject.type_ensure(RenderSearchHeaderBar) GObject.type_ensure(SelectionHeaderBar) GObject.type_ensure(Sidebar) GObject.type_ensure(SidebarRow) GObject.type_ensure(ThemeSelector) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/iotas/window.py000066400000000000000000000356501507102636600234130ustar00rootroot00000000000000from gi.repository import Adw, Gio, GLib, GObject, Gtk import logging from typing import Optional from iotas.attachment import Attachment from iotas.attachment_helpers import trim_orphaned_images from iotas.config_manager import ConfigManager from iotas.category_manager import CategoryManager import iotas.const as const from iotas.editor import Editor, EditorSessionDetails from iotas.index import Index from iotas.note import Note from iotas.note_database import NoteDatabase from iotas.note_manager import NoteManager from iotas.nextcloud_login_dialog import NextcloudLoginDialog, LoginDialogMode from iotas.sync_manager import SyncManager from iotas.uri_to_note_creator import UriToNoteCreator @Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/window.ui") class Window(Adw.ApplicationWindow): __gtype_name__ = "Window" _navigation: Adw.NavigationView = Gtk.Template.Child() _index: Index = Gtk.Template.Child() _editor: Editor = Gtk.Template.Child() _editor_page: Adw.NavigationPage = Gtk.Template.Child() def __init__( self, app: Adw.Application, db: NoteDatabase, sync_manager: SyncManager, ) -> None: super().__init__(application=app) self.set_icon_name(const.APP_ID) if const.IS_DEVEL: self.add_css_class("devel") self.app = self.get_application() self.__db = db self.__sync_manager = sync_manager self.__category_manager = CategoryManager(self.__db) self.__note_manager = NoteManager(self.__db, self.__category_manager) self.__config_manager = ConfigManager.get_default() self.__initialised = False self.__using_keyboard_navigation = False self.__secret_service_failed = False self.__open_note_after_init = None self.__create_note_after_init = False self.__setup_actions() self._index.setup(self.__note_manager, self.__category_manager, self.__sync_manager) self._index.connect( "note-opened", lambda _o, note, immediate: self.__open_note(note, immediate) ) self._index.connect("reauthenticate", lambda _o: self.show_login_dialog()) self._editor.setup(self.__category_manager.tree_store, self.__sync_manager) self._editor.connect( "note-modified", lambda _o, note: self.__note_manager.persist_note_while_editing( note, update_excerpt=False ), ) self._editor.connect("note-deleted", self.__on_editor_note_deleted) self._editor.connect( "category-changed", lambda _o, note, old_category: self.__note_manager.persist_note_category( note, old_category ), ) self._editor.connect("exit", lambda _o: self._navigation.pop()) self.__note_manager.connect("sync-requested", lambda _o: self.__sync_manager.sync_now()) self.__sync_manager.connect("ready", self.__on_sync_ready) self.__sync_manager.connect("note-conflict", lambda _o, note: self.__on_note_conflict(note)) self.__sync_manager.connect( "note-deleted", lambda _o, note: self.__on_note_remotely_deleted(note) ) self.__sync_manager.connect("secret-service-failure", self.__on_secret_service_failure) self.__sync_manager.connect( "notify::authenticated", lambda _o, _v: self._editor.set_sync_authenticated(self.__sync_manager.authenticated), ) self.__sync_manager.connect( "remote-category-sanitised", lambda _o, old, new: self.__category_manager.note_category_changed(old, new), ) self.__sync_manager.connect("attachment-downloaded", self.__on_attachment_downloaded) self.__note_manager.connect( "initial-load-complete", lambda _o: self.__on_initial_load_from_db_complete() ) self.connect("close-request", lambda _o: self.cleanup_and_close()) self.connect("notify::visible-dialog", lambda _o, _v: self.__update_for_visible_dialogs()) (width, height) = self.__config_manager.get_window_size() self.set_default_size(width, height) self._index.update_layout_for_initial_size(width, height) self.connect( "notify::default-height", lambda _o, _v: self._index.update_search_pagesize_for_height(self.get_height()), ) self._index.active = True self._editor.active = False def cleanup_and_close(self) -> None: """Cleanup for exit.""" if self._editor.editing: self.__note_manager.apply_any_server_sanitised_title(self._editor.current_note) self.__note_manager.persist_note_sync( self._editor.current_note, force_update_excerpt=self._editor.note_had_edit ) trim_orphaned_images(self._editor.current_note, on_thread=False) self.__note_manager.apply_deleted_notes_attachment_deletion() self.__sync_manager.close() if not self.is_fullscreen(): self.__config_manager.set_window_size(self.get_width(), self.get_height()) self.__config_manager.first_start = False self.close() def show_login_dialog(self) -> None: """Show Nextcloud Notes onboarding dialog.""" if self.__secret_service_failed: mode = LoginDialogMode.SECRET_SERVICE_FAILURE elif self.__sync_manager.configured_but_no_password: mode = LoginDialogMode.REAUTHENTICATE else: mode = LoginDialogMode.NORMAL dialog = NextcloudLoginDialog(self.__sync_manager, mode) dialog.present(self) @GObject.Property(type=bool, default=False) def using_keyboard_navigation(self) -> bool: return self.__using_keyboard_navigation @using_keyboard_navigation.setter def set_using_keyboard_navigation(self, value: bool) -> None: self.__using_keyboard_navigation = value @Gtk.Template.Callback() def _on_page_pushed(self, _obj: GObject.Object) -> None: self._index.active = False self._editor.active = True self._editor.focus_textview_if_editing() @Gtk.Template.Callback() def _on_page_popped(self, _obj: GObject.Object, _page: Adw.NavigationPage) -> None: note = self._editor.current_note self.__note_manager.persist_note_sync(note, force_update_excerpt=self._editor.note_had_edit) self._index.refresh_after_note_closed(note) self._editor.close_note() on_thread = True GLib.timeout_add(500, trim_orphaned_images, note, on_thread) if note.dirty: self.__sync_manager.sync_now() self._index.active = True self._editor.active = False def __setup_actions(self) -> None: action_group = Gio.SimpleActionGroup.new() app = Gio.Application.get_default() action = Gio.SimpleAction.new("fullscreen") action.connect("activate", lambda _a, _p: self.__toggle_fullscreen()) action_group.add_action(action) app.set_accels_for_action("win.fullscreen", ["F11"]) action = Gio.SimpleAction.new("close") action.connect("activate", lambda _o, _v: self.cleanup_and_close()) action_group.add_action(action) app.set_accels_for_action("win.close", ["w"]) self.__close_window_action = action action = Gio.SimpleAction.new("refresh") action.connect("activate", lambda _o, _v: self.__sync_manager.sync_now()) action_group.add_action(action) app.set_accels_for_action("win.refresh", ["r"]) action.set_enabled(False) action = Gio.SimpleAction.new("start-nextcloud-signin") action.connect("activate", lambda _o, _v: self.show_login_dialog()) action_group.add_action(action) action = Gio.SimpleAction.new("create-note-from-cli") action.connect("activate", lambda _o, _v: self.__on_create_note()) action_group.add_action(action) action = Gio.SimpleAction.new("create-note-from-uri", GLib.VariantType("s")) action.connect("activate", self.__on_create_note_from_uri) action_group.add_action(action) action = Gio.SimpleAction.new("open-note", GLib.VariantType("u")) action.connect("activate", self.__on_open_note) action_group.add_action(action) action = Gio.SimpleAction.new("open-previous-note") action.connect("activate", lambda _o, _v: self.__open_previous_note()) app.set_accels_for_action("win.open-previous-note", ["l"]) action_group.add_action(action) action = Gio.SimpleAction.new("search-from-cli", GLib.VariantType("s")) action.connect("activate", self.__on_search_from_cli) action_group.add_action(action) self.insert_action_group("win", action_group) self.__action_group = action_group def __on_editor_note_deleted(self, _obj: GObject.Object, note: Note) -> None: if self._navigation.get_visible_page() is not self._editor_page: return self._navigation.pop() self.__sync_manager.flush_pending_deletions() self.__note_manager.delete_notes([note], provide_undo=True) self._index.update_for_note_deletions([note]) def __on_note_conflict(self, note: Note) -> None: if self._editor.current_note is not None and note is self._editor.current_note: logging.info("Note being edited in conflict") self._editor.current_note.handling_conflict = True self._navigation.pop() self._index.show_note_conflict_alert() def __on_note_remotely_deleted(self, note: Note) -> None: if self._editor.current_note is not None and note is self._editor.current_note: logging.info("Note being edited was remotely deleted") self._editor.current_note.handling_conflict = True self._navigation.pop() self._index.show_editing_note_deleted_alert() def __on_sync_ready(self, _obj: GObject.Object, new_setup: bool) -> None: action = self.__action_group.lookup("refresh") action.set_enabled(True) action = self.__action_group.lookup("start-nextcloud-signin") action.set_enabled(False) def __toggle_fullscreen(self) -> None: if self.is_fullscreen(): self.unfullscreen() else: self.fullscreen() def __on_secret_service_failure(self, _obj: GObject.Object) -> None: self.__secret_service_failed = True if self.__config_manager.show_startup_secret_service_failure: self._index.show_secret_service_failure_alert() def __on_create_note(self) -> None: """Create a new note and edit it.""" if self.__initialised: if self._editor.active: self._navigation.pop() self.activate_action("index.create-note") else: self.__create_note_after_init = True def __on_open_note( self, _obj: GObject.Object, note_id: GObject.ParamSpec, ) -> None: note_id = note_id.get_uint32() if self.__initialised: if self._editor.active: self._navigation.pop() self.__open_note_by_id(note_id, immediate=False) else: self.__open_note_after_init = note_id # Note: Iotas' addition of this URI handler is a stopgap measure until the freedesktop # intent system is fleshed out. The handling provided here will be unceremoniously removed # when that system is available and may be removed or modified without notice beforehand; # this is not a stable public interface. def __on_create_note_from_uri( self, _obj: GObject.Object, param: GObject.ParamSpec, ) -> None: uri = param.get_string() parser = UriToNoteCreator() result = parser.parse(uri) if result.success: assert result.note note = result.note logging.info(f"Creating note from URI '{note.title}'") self.__note_manager.persist_note_sync(note, force_update_excerpt=False) self.__sync_manager.sync_now() if result.open: if self._editor.active: self._navigation.pop() self.__open_note(note, immediate=True) def __on_search_from_cli( self, _obj: GObject.Object, param: GObject.ParamSpec, ) -> None: search_term = param.get_string() if self._editor.active: self._navigation.pop() self._index.search_from_cli(search_term) def __on_initial_load_from_db_complete(self) -> None: self.__initialised = True if self.__create_note_after_init: note = self.__note_manager.create_note(self.__category_manager.all_category) self.__open_note(note, immediate=True) elif self.__open_note_after_init is not None: self.__open_note_by_id(self.__open_note_after_init, immediate=True) def __on_attachment_downloaded(self, _obj: GObject.Object, attachment: Attachment) -> None: if not self._editor.active or not self._editor.editing: return self._editor.show_downloaded_attachment_in_render(attachment) def __open_note( self, note: Note, immediate: bool, restore_session: Optional[EditorSessionDetails] = None ) -> None: if immediate: self._navigation.set_animate_transitions(False) if not note.content_loaded: self.__db.populate_note_content(note) # Handle opening a note from CLI / shell search provider when another note is open if self._editor.active: self._navigation.pop() self._editor.init_note(note, restore_session) self._navigation.push(self._editor_page) if immediate: self._navigation.set_animate_transitions(True) def __open_note_by_id(self, note_id: int, immediate: bool) -> None: note = self.__note_manager.fetch_note_by_id(note_id) if note is None: logging.error(f"Failed to find note with id {note_id}") return self.__open_note(note, immediate) def __open_previous_note(self) -> None: session = self._editor.get_previous_session() if session is None: return if not self.__note_manager.fetch_note_by_id(session.note.id): return if session.note.locally_deleted: return if session.note in self.__note_manager.get_deleted_notes_pending_undo(): return if self._editor.current_note == session.note: return logging.info("Opening previous note") session.direct_switching = self._editor.active self.__open_note(session.note, immediate=self._editor.active, restore_session=session) def __update_for_visible_dialogs(self) -> None: visible = self.get_visible_dialog() is not None self._index.update_for_dialog_visibility(visible) self._editor.update_for_dialog_visibility(visible) self.__close_window_action.set_enabled(not visible) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/meson.build000066400000000000000000000040551507102636600225500ustar00rootroot00000000000000project('iotas', version: '0.12.1', meson_version: '>= 0.59', license: 'GPL-3.0-or-later' ) i18n = import('i18n') python = import('python') gnome = import('gnome') project_id = 'org.gnome.World.Iotas' project_name = 'Iotas' package_url = 'https://gitlab.gnome.org/World/iotas' copyright = '© 2022-2025 Chris Heywood' contributors = '\n'.join([ 'Chris Heywood', ]) artists = '\n'.join([ ]) message('Looking for dependencies') python_bin = python.find_installation('python3') if not python_bin.found() error('No valid python3 binary found') else message('Found python3 binary') endif if not python_bin.language_version().version_compare('>= 3.11') error('Python 3.11 or newer is required.') endif dependency('glib-2.0', version: '>= 2.76') dependency('gio-2.0', version: '>= 2.76') dependency('gobject-introspection-1.0', version: '>=1.66.0') dependency('gtk4', version: '>=4.20') dependency('libadwaita-1', version: '>=1.8') dependency('gtksourceview-5', version: '>= 5.6') python_dir = python_bin.get_install_dir() DATA_DIR = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) LIBEXEC_DIR = join_paths(get_option('prefix'), get_option('libexecdir')) bindir = join_paths(get_option('prefix'), get_option('bindir')) application_id = project_id if get_option('profile') == 'development' profile = 'Devel' application_id = '@0@.Devel'.format(application_id) vcs_tag = run_command( ['git', 'rev-parse', '--short', 'HEAD'], check: false ).stdout().strip() if vcs_tag == '' version_suffix = '-devel' else version_suffix = '-@0@'.format (vcs_tag) endif else profile = '' version_suffix = '' endif iotas_version = meson.project_version() top_source_dir = meson.current_source_dir() gettext_package = meson.project_name() subdir('data') subdir('po') subdir('iotas') subdir('search-provider') subdir('third-party') subdir('tests') gnome.post_install( gtk_update_icon_cache: true, glib_compile_schemas: true, update_desktop_database: true, ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/meson_options.txt000066400000000000000000000001561507102636600240410ustar00rootroot00000000000000option( 'profile', type: 'combo', choices: [ 'default', 'development' ], value: 'default' ) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/000077500000000000000000000000001507102636600210205ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/LINGUAS000066400000000000000000000001711507102636600220440ustar00rootroot00000000000000# Please keep this list alphabetically sorted bg cs de en_GB es eu fi fr he hu it ka nl oc pt_BR ro ru sl sv tr uk zh_CN iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/POTFILES.in000066400000000000000000000050021507102636600225720ustar00rootroot00000000000000# List of source files containing translatable strings. # Please keep this file sorted alphabetically data/org.gnome.World.Iotas.desktop.in.in data/org.gnome.World.Iotas.metainfo.xml.in.in data/ui/about_dialog.ui.in data/ui/category_header_bar.ui data/ui/editor_rename_header_bar.ui data/ui/editor_search_entry.ui data/ui/editor_search_header_bar.ui data/ui/editor.ui data/ui/export_dialog.ui data/ui/first_start_page.ui data/ui/font_size_selector.ui data/ui/formatting_header_bar.ui data/ui/index_menu_button.ui data/ui/index_note_list.ui data/ui/index_row.ui data/ui/index_search_header_bar.ui data/ui/index.ui data/ui/keyboard_shortcuts_dialog.ui data/ui/link_dialog.ui data/ui/nextcloud_login_dialog.ui data/ui/outline_dialog.ui data/ui/preferences_dialog.ui data/ui/render_search_header_bar.ui data/ui/selection_header_bar.ui data/ui/sidebar_row.ui data/ui/sidebar.ui data/ui/table_dialog.ui data/ui/theme_selector.ui data/ui/window.ui iotas/application.py iotas/attachment_helpers.py iotas/attachment.py iotas/backup_manager.py iotas/backup_storage.py iotas/category_header_bar.py iotas/category_list_model.py iotas/category_manager.py iotas/category.py iotas/category_storage.py iotas/category_treeview_list_store.py iotas/config_manager.py iotas/database.py iotas/editor.py iotas/editor_rename_header_bar.py iotas/editor_search_entry.py iotas/editor_search_header_bar.py iotas/editor_text_view.py iotas/export_dialog.py iotas/exporter.py iotas/first_start_page.py iotas/focus_mode_helper.py iotas/font_size_selector.py iotas/formatter.py iotas/formatting_header_bar.py iotas/html_generator_configuration.py iotas/html_generator.py iotas/index_menu_button.py iotas/index_note_list.py iotas/index.py iotas/index_row.py iotas/index_search_header_bar.py iotas/link_dialog.py iotas/list_formatter.py iotas/markdown_helpers.py iotas/markdown_render_view.py iotas/migration_assistant.py iotas/nextcloud_login_dialog.py iotas/nextcloud_sync_worker_configuration.py iotas/nextcloud_sync_worker.py iotas/note_database.py iotas/note_list_model.py iotas/note_manager.py iotas/note.py iotas/ordered_list_utils.py iotas/outline_dialog.py iotas/outline_generator.py iotas/pdf_exporter.py iotas/preferences_dialog.py iotas/render_search_header_bar.py iotas/selection_header_bar.py iotas/sidebar.py iotas/sidebar_row.py iotas/sync_manager.py iotas/sync_result.py iotas/table_dialog.py iotas/template_html_generator.py iotas/text_utils.py iotas/theme_selector.py iotas/ui_utils.py iotas/uri_to_note_creator.py iotas/webkit_pdf_exporter.py iotas/widgets.py iotas/window.py iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/bg.po000066400000000000000000001504311507102636600217540ustar00rootroot00000000000000# Bulgarian translation for Iotas. # Copyright (C) 2025 twlvnn kraftwerk # This file is distributed under the same license as the Iotas package. # twlvnn kraftwerk , 2025. # msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/-/issues\n" "POT-Creation-Date: 2025-03-18 06:13+0000\n" "PO-Revision-Date: 2025-03-20 18:53+0100\n" "Last-Translator: \n" "Language-Team: Bulgarian\n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.5\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:4 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:6 msgid "Simple note taking with Nextcloud Notes" msgstr "Просто водене на записки с Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:14 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "бележки;записки;прост;разсейване;редактор;фокусиран;текст;писане;документ;notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Просто водене на записки" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas цели водене на бележки без нищо да ви разсейва. Дизайнът на програмата " "е ориентиран към мобилни устройства." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Функции" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Бързо синхронизиране с Nextcloud Notes по избор" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "" "Редактиране на бележки без връзка с Интернет и синхронизация при връзка с " "Интернет" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Редактиране и филтриране по категории" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Любими" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Проверка на правописа" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Търсене в колекцията или в отделни бележки" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Режим на фокусиране и скриване на лентите за заглавието и форматирането на " "редактора (по избор)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "В експериментален етап: изнасяне към PDF, ODT и HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Адаптивен дизайн, при който „Iotas“ изглежда добре както на настолен " "компютър, така и на мобилно устройство" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Може да търсите чрез обвивката на GNOME" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Създавайте и възстановявайте бележките си от резервни копия (от командния " "ред, за използване без синхронизация)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "" "Възможност за промяна на размера на шрифта и ползване на равноширок стил" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Писането на markdown се поддържа, но не е задължително" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Форматиране чрез лентата с инструменти и клавишни комбинации" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Оцветяване на синтаксиса с теми" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Форматиран изглед" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "" "Способност за отбелязване на задачи като изпълнени от форматирания изглед" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Малко повече технически подробности за тези, които се интересуват" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "Синхронизацията на Nextcloud Notes се извършва чрез REST API, а не чрез " "WebDAV, което я прави бърза" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Включва просто засичане на конфликти при синхронизация" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Бележките непрекъснато се запазват" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Големите колекции от бележки се зареждат частично, за да се ускори " "стартирането" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Бележките се съхраняват в SQLite, което осигурява бързо търсене (FTS), без " "да се налага да се изгражда технологията наново. Обикновените файлове може " "да се възстановяват от и към резервно копие (само в команден ред)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Индекс" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Редактор с markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Визуализиран markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Съдържание в тъмен стил" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Работи на мобилни устройства" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "" "twlvnn kraftwerk <kraft_werk@tutanota.com>\n" "\n" "\n" "Проектът за превод на GNOME има нужда от подкрепа.\n" "Научете повече за нас на уеб сайта ни.\n" "Докладвайте за грешки в превода в съответния раздел." #. Translators: Button #: data/ui/category_header_bar.ui:14 data/ui/editor_rename_header_bar.ui:16 msgid "Revert Changes" msgstr "Връщане на промените" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:41 data/ui/editor_rename_header_bar.ui:39 msgid "Apply Changes" msgstr "Прилагане на промените" #. Translators: Button #: data/ui/category_header_bar.ui:43 data/ui/editor_rename_header_bar.ui:41 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Прилагане" #. Translators: Button #: data/ui/category_header_bar.ui:57 msgid "Clear and Apply" msgstr "Изчистване и прилагане" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Търсене" #. Translators: Button #: data/ui/editor_search_header_bar.ui:15 data/ui/index_search_header_bar.ui:11 #: data/ui/render_search_header_bar.ui:14 data/ui/selection_header_bar.ui:16 msgid "Back" msgstr "Назад" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:42 #: data/ui/keyboard_shortcuts_window.ui:287 #: data/ui/render_search_header_bar.ui:35 msgid "Previous Match" msgstr "Предишна поява" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:50 #: data/ui/keyboard_shortcuts_window.ui:280 #: data/ui/render_search_header_bar.ui:43 msgid "Next Match" msgstr "Следваща поява" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:72 #: data/ui/editor_search_header_bar.ui:81 #: data/ui/keyboard_shortcuts_window.ui:273 msgid "Replace" msgstr "Заместване" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:300 msgid "Focus Mode" msgstr "Режим на фокус" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Търсене и замяна…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Към…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Редактиране на заглавието…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Промяна на категорията…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Изтриване" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Изнасяне…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Назад към бележките" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Бележката е само за четене" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Меню на редактора" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle Markdown Render" msgstr "Превключване на визуализирането на Markdown" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Редактиране на бележката" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Зареждане на ядрото за визуализиране" #. Translators: Button #: data/ui/export_dialog.ui:21 iotas/preferences_dialog.py:336 #: iotas/preferences_dialog.py:357 msgid "Cancel" msgstr "Отказване" #. Translators: Title #: data/ui/export_dialog.ui:29 msgid "Export As..." msgstr "Изнасяне като…" #. Translators: Title #: data/ui/export_dialog.ui:49 msgid "Exporting..." msgstr "Изнасяне…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:68 data/ui/export_dialog.ui:95 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Затваряне" #. Translators: Button #: data/ui/export_dialog.ui:75 msgid "Show" msgstr "Показване" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Добре дошли в „Iotas“" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Използвайте заглавната лента по-горе, за…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Добавяне на бележка" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Синхронизиране с Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Намаляване" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Увеличаване" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:157 #: data/ui/keyboard_shortcuts_window.ui:239 msgid "Horizontal Rule" msgstr "Хоризонтална линия" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:166 #: data/ui/keyboard_shortcuts_window.ui:246 msgid "Quote" msgstr "Цитат" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:175 #: data/ui/keyboard_shortcuts_window.ui:225 msgid "Code" msgstr "Код" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:184 #: data/ui/keyboard_shortcuts_window.ui:253 msgid "Table" msgstr "Таблица" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Ниво 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Ниво 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Ниво 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Ниво 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Премахване" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:80 data/ui/keyboard_shortcuts_window.ui:183 msgid "Heading" msgstr "Заглавие" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:89 data/ui/keyboard_shortcuts_window.ui:169 msgid "Bold" msgstr "Получерно" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:98 data/ui/keyboard_shortcuts_window.ui:176 msgid "Italic" msgstr "Курсив" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:107 #: data/ui/keyboard_shortcuts_window.ui:232 msgid "Strikethrough" msgstr "Зачертаване" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:116 #: data/ui/keyboard_shortcuts_window.ui:190 msgid "Unordered List" msgstr "Неподреден списък" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:125 #: data/ui/keyboard_shortcuts_window.ui:197 msgid "Ordered List" msgstr "Подреден списък" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:134 #: data/ui/keyboard_shortcuts_window.ui:204 msgid "Checkbox" msgstr "Поле за избор" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:143 #: data/ui/keyboard_shortcuts_window.ui:218 msgid "Link" msgstr "Връзка" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Опресняване" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Настройки" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Клавишни комбинации" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Относно „Iotas“" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Основно меню" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Днес" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Вчера" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Тази седмица" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Този месец" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Миналия месец" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Показване на предишните месеци" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Преди миналия месец" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Още" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Отваряне на категориите" #. Translators: Button #: data/ui/index.ui:42 msgid "New Note" msgstr "Нова бележка" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:266 msgid "Search" msgstr "Търсене" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Избиране на бележки" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Връзката със сървъра е изключена" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Поради промени (нов идентификатор на програмата) „Iotas“ трябва да се " "удостовери отново с вашия сървър за Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Удостоверяване" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "Жетонът за удостоверяване за синхронизиране с Nextcloud Notes не може да се " "извлече" #. Translators: Button #: data/ui/index.ui:111 msgid "OK" msgstr "Добре" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Списъкът с бележки е празен" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Въведете термин за търсене" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Няма резултати от търсенето" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create New Note" msgstr "Създаване на нова бележка" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show Sidebar" msgstr "Показване на страничната лента" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete Note" msgstr "Изтриване на бележката" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move Up List" msgstr "Преместване нагоре в списъка" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move Down List" msgstr "Преместване надолу в списъка" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start Selection" msgstr "Начало на избор" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset Filter" msgstr "Връщане на филтъра" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open First Search Result" msgstr "Отваряне на първия резултат от търсенето" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Редактор" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit Title" msgstr "Редактиране на заглавието" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_window.ui:93 iotas/export_dialog.py:129 msgid "Export" msgstr "Изнасяне" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create New Note Including Selection" msgstr "Създаване на нова бележка от избора" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Change Category" msgstr "Промяна на категорията" # или въведеното? #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo Typing" msgstr "Отмяна на въвеждането" # или въведеното? #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo Typing" msgstr "Повтаряне на въвеждането" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Insert Emoji" msgstr "Вмъкване на емоджи" # ако е само “текста” ще е по-кратко, но нз дали е РАЗРЕШЕНО или разбираемо че е полето за текст #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Focus Text View" msgstr "Фокусиране на текста" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Focus Header Bar" msgstr "Фокусиране на заглавната лента" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:156 msgid "Focus Formatting Bar" msgstr "Фокусиране на лентата за форматиране" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:164 msgid "Formatting" msgstr "Форматиране" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:211 msgid "Toggle Checkbox" msgstr "Превключване на полето за избор" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:261 msgid "Editor Search" msgstr "Търсене в редактора" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:295 msgid "Editor Appearance" msgstr "Външен вид на редактора" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:307 msgid "Increase Line Length" msgstr "Увеличаване на дължината на шрифта" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:314 msgid "Decrease Line Length" msgstr "Намаляване на дължината на шрифта" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:321 msgid "Increase Font Size" msgstr "Увеличаване на размера на шрифта" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:328 msgid "Decrease Font Size" msgstr "Намаляване на размера на шрифта" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:336 msgid "General" msgstr "Общи" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:341 msgid "Toggle Fullscreen" msgstr "Превключване на цял екран" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:348 msgid "Show Preferences" msgstr "Показване на настройките" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:355 msgid "Show Shortcuts" msgstr "Показване на клавишните комбинации" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:362 msgid "Open Previous Note" msgstr "Отваряне на предишната бележка" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:369 msgid "Go Back" msgstr "Назад" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:376 msgid "Quit" msgstr "Спиране на програмата" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "Адрес" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Текст" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Настройване на Nextcloud Notes" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Натиснете „Продължаване“, за да предоставите адреса на сървъра на Nextcloud " "и да се впишете чрез уеб браузър" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Продължаване" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Продължаване към адреса" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Услугата за тайни не е достъпна" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "Услугата за съхраняване на данни за удостоверяване не може да бъде " "достъпена. Уверете се, че разполагате с доставчик като gnome-keyring. Трябва " "да бъде настроен стандартен ключодържател и той да бъде отключен. Повечето " "работни среди ще ви предоставят това. Рестартирайте програмата, за да " "опитате отново." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Адрес на сървъра" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Начало на влизането" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Самоподписан сертификат" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Изглежда, че използвате самоподписан SSL сертификат, в резултат на което " "самоличността на сървъра не се потвърждава. Ако това е се очаква, следвайте " "инструкциите в често задаваните въпроси, за да предоставите веригата на " "сертификата на удостоверителя." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Отваряне на ЧЗВ" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Връзката е установена" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Готово" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Завършване на настройването на синхронизацията" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Очертание" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Няма заглавия, отговарящи на филтъра" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Няма заглавия за съдържанието" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Интерфейс" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Използване на равноширок шрифт" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Проверка на правописа" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Променяйте езика чрез контекстното меню на редактора" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Заглавна лента" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Ограничаване на дължината на реда" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Предимно за настолни компютри. Използвайте Ctrl + ↑ и Ctrl + ↓ от " "клавиатурата, за да настройвате." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Разпознаване на синтаксиса" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "Необходимо за оцветяване на синтаксиса и форматиране (лента с инструменти и " "клавишни комбинации). Изключете, ако искате малко по-добра производителност." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Тема" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Лента за форматиране" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Включване на форматиран изглед" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Изключете, за да намалите времето за стартиране" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Отваряне във форматиран изглед" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Ако е зададено, отваря всички бележки като визуализиран markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Поддръжка на математически уравнения" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Леко намалява скоростта на визуализиране" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Визуализиране с равноширок шрифт" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Пропорционално на съотношението на размера на равноширокия шрифт" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "В режим на визуализиране. Използвайте 1 за без нагласяне." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Запазване на ядрото в паметта" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "По-бързи следващи преобразувания при по-висока употреба на паметта" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Закачване на страничната лента" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "На работния плот, когато има място" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Стил на етикета на категорията" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Данни" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Reset Database" msgstr "Зануляване на базата от данни" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Delete all notes from the local database. The app will quit." msgstr "" "Изтриване на всички бележки от локалната база от данни. Програмата ще спре." #. Translators: Button #: data/ui/preferences_dialog.ui:178 iotas/preferences_dialog.py:338 msgid "Reset" msgstr "Връщане" #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "Прекъсване на Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Излизане от Nextcloud Notes. Всички бележки ще се изтрият и програмата ще " "спре." #. Translators: Button #: data/ui/preferences_dialog.ui:199 iotas/preferences_dialog.py:359 msgid "Disconnect" msgstr "Прекъсване" #. Translators: Title #: data/ui/preferences_dialog.ui:217 msgid "Debug" msgstr "Отстраняване на грешки" #. Translators: Title #: data/ui/preferences_dialog.ui:223 msgid "Clear Sync Timestamp" msgstr "Изчистване на времето на синхронизацията" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:225 msgid "Forces a pull of all notes from the sync server" msgstr "Принуждава издърпване на всички бележки от сървъра за синхронизация" #. Translators: Button #: data/ui/preferences_dialog.ui:232 msgid "Clear" msgstr "Изчистване" #. Translators: Button #: data/ui/selection_header_bar.ui:32 msgid "Delete Selected" msgstr "Изтриване на избора" #. Translators: Button #: data/ui/selection_header_bar.ui:43 msgid "Toggle Favorite for Selected" msgstr "Превключване като любимо за избора" #. Translators: Button #: data/ui/selection_header_bar.ui:51 msgid "Change Category for Selected" msgstr "Променяне на категорията за избора" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Затваряне на категориите" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Категории" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Вмъкване на таблица" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Създаване" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Използване на системен стил" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Светъл стил" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Тъмен стил" #. Translators: Description, CLI option #: iotas/application.py:266 msgid "Create a note" msgstr "Създаване на бележка" #. Translators: Description, CLI option #: iotas/application.py:275 msgid "Create a backup" msgstr "Създаване на резерва" #. Translators: Description, CLI option #: iotas/application.py:284 msgid "Restore a backup" msgstr "Възстановяване от резерва" #. Translators: Description, CLI option #: iotas/application.py:293 msgid "Display backup path" msgstr "Извеждане на местоположението на резервите" # или “верижния файл”? #. Translators: Description, CLI option #: iotas/application.py:302 msgid "Display path for custom server SSL CA chain file" msgstr "" "Извеждане на местоположението за SSL веригата на сертификата на " "удостоверителя" #. Translators: Description, CLI option #: iotas/application.py:311 msgid "Toggle display of extended preferences in UI" msgstr "Превключване на допълнителните настройки в интерфейса" #. Translators: Description, CLI option #: iotas/application.py:320 msgid "Quit any running instance" msgstr "Спиране на работещите прозорци" #. Translators: Description, CLI option #: iotas/application.py:329 msgid "Enable debug logging and functions" msgstr "" "Включване на съобщенията и функциите за отстраняване на грешки в журнала" #. Translators: Description, CLI option #: iotas/application.py:338 msgid "Open note by id" msgstr "Отваряне на бележка по идентификатор" #. Translators: Description, CLI option #: iotas/application.py:347 msgid "Search in notes" msgstr "Търсене в бележките" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:203 msgid "RESTORATION REMOTE ID CLASH" msgstr "ПРИ ВЪЗСТАНОВЯВАНЕТО Е ОТКРИТ ПОВТАРЯЩ СЕ ИДЕНТИФИКАТОР" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:221 msgid "RESTORATION TITLE CLASH" msgstr "ПРИ ВЪЗСТАНОВЯВАНЕТО Е ОТКРИТО ПОВТАРЯЩО СЕ ЗАГЛАВИЕ" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Всички бележки" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Без категория" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:946 #, python-brace-format msgid "Line length now {0}px" msgstr "Дължината на реда е вече {0}px" #. Translators: Description, notification #: iotas/editor.py:952 msgid "Line length limit disabled" msgstr "Ограничението на дължината на реда е изключено" #: iotas/editor.py:1572 msgid "Opening link in browser" msgstr "Отваряне на връзката в браузъра" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} от {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:100 msgid "Exported to {}" msgstr "Изнасяне към {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:113 msgid "Failed to export to {}" msgstr "Изнасянето към {} е неуспешно" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:198 msgid "{} notes deleted" msgstr "{} бележки са изтрити" #. Translators: Description, notification #: iotas/index.py:201 msgid "Note deleted" msgstr "Бележката е изтрита" #. Translators: Button #: iotas/index.py:206 msgid "Undo" msgstr "Отмяна" #. Translators: Description, notification #: iotas/index.py:244 msgid "Sync conflict with note being edited" msgstr "Има конфликт на синхронизация с отворената бележка" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:252 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Услугата за тайни не може да бъде достъпена. Уверете се, че имате доставчик " "като gnome-keyring, който има стандартно настроен ключодържател, който е " "отключен." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:484 msgid "Syncing" msgstr "Синхронизиране" #. Translators: Description, notification, {} is a number #: iotas/index.py:503 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} промяна" msgstr[1] "{} промени" #. Translators: Description, notification #: iotas/index.py:519 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "" "Неуспешно синхронизиране. Инсталирана ли е програмата Nextcloud Notes на " "сървъра?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:616 msgid "Loading" msgstr "Зареждане" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Вмъкване на връзка" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Редактиране на връзката" #. Translators: Title #: iotas/nextcloud_login_dialog.py:107 msgid "Updating Notes" msgstr "Обновяване на бележките" #. Translators: Title #: iotas/nextcloud_login_dialog.py:111 msgid "Performing Initial Transfer" msgstr "Извършване на първоначално прехвърляне" #. Translators: Title #: iotas/nextcloud_login_dialog.py:165 msgid "Connecting" msgstr "Свързване" #. Translators: Title #: iotas/nextcloud_login_dialog.py:187 msgid "Waiting for Login" msgstr "Изчакване за вход" #. Translators: Description #: iotas/nextcloud_login_dialog.py:189 msgid "Complete the authentication in your browser" msgstr "Завършете удостоверяването в браузъра си" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:205 msgid "Failed to start login with possible certificate issue" msgstr "Неуспешно влизане, вероятно проблем със сертификата" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:208 msgid "Failed to start login. Wrong address?" msgstr "Неуспешно влизане. Грешен адрес?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:65 iotas/preferences_dialog.py:97 msgid "Monochrome" msgstr "Едноцветно" #. Translators: Description, a style name #: iotas/preferences_dialog.py:67 msgid "Muted Markup" msgstr "Затъмнено маркиране" #. Translators: Description, a style name #: iotas/preferences_dialog.py:69 msgid "Bold Markup" msgstr "Получерно маркиране" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:126 msgid "Disabled" msgstr "Изключено" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:99 msgid "Muted" msgstr "Заглушено" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:101 msgid "Blue" msgstr "Синьо" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:103 msgid "Orange" msgstr "Оранжево" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Red" msgstr "Червено" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "None" msgstr "Без" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:120 iotas/preferences_dialog.py:140 msgid "Always Visible" msgstr "Винаги видимо" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:122 iotas/preferences_dialog.py:142 msgid "Automatically Hide" msgstr "Автоматично скриване" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Auto Hide When Fullscreen" msgstr "Автоматично скриване при цял екран" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:277 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Скриване след {0} натискане(ия)" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:280 #, python-brace-format msgid "Extending in {0} presses" msgstr "Разширяване след {0} натискане(ия)" #. Translators: Description, notification #: iotas/preferences_dialog.py:285 msgid "Extended hidden" msgstr "Разширението е скрито" #. Translators: Description, notification #: iotas/preferences_dialog.py:288 msgid "Extended shown" msgstr "Разширението е показано" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:311 msgid "Hiding discouraged on mobile" msgstr "Скриването не се препоръчва за мобилни устройства" #. Translators: Title #: iotas/preferences_dialog.py:331 msgid "Reset Database?" msgstr "Нулиране на базата от данни?" #. Translators: Description #: iotas/preferences_dialog.py:333 msgid "All notes will be deleted. Continue with the reset?" msgstr "Всички бележки ще бъдат изтрити. Продължаване с нулирането?" #. Translators: Title #: iotas/preferences_dialog.py:352 msgid "Disconnect Nextcloud?" msgstr "Прекъсване на Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:354 msgid "All notes will be removed. Do you want to sign out?" msgstr "Всички бележки ще бъдат премахнати. Искате ли да излезете?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Категорията на бележка само за четене не може да бъде променена" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} избрано(и)" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:502 msgid "SYNC CONFLICT" msgstr "КОНФЛИКТ ПРИ СИНХРОНИЗАЦИЯ" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Грешка" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/cs.po000066400000000000000000001421521507102636600217720ustar00rootroot00000000000000# Czech translations for Iotas package. # Copyright (C) 2024 Iota's copyright holder # This file is distributed under the same license as the Iotas package. # Jiri Eischmann , 2024. # msgid "" msgstr "" "Project-Id-Version: Iotas\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-05-28 20:10+1000\n" "PO-Revision-Date: 2024-05-31 16:06+0200\n" "Last-Translator: Jiri Eischmann \n" "Language-Team: Czech\n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Poedit 3.4.2\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:4 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:6 msgid "Simple note taking with Nextcloud Notes" msgstr "Jednoduché pořizování poznámek s Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:14 msgid "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;" "document;" msgstr "" "notes;poznámky;nextcloud;editor;minimalistický;rozptýlení;zaměřený;text;psát;" "markdown;dokument;" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Jednoduché pořizování poznámek" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Cílem aplikace Iotas je vytváření poznámek bez rozptylování prostřednictvím " "designu zaměřeného na mobilní zařízení." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Nabízí" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Volitelná rychlá synchronizace s Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Upravování poznámky offline, synchronizování po připojení" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Upravování a filtrování kategorií" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Oblíbené" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Kontrola pravopisu" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Vyhledávání ve sbírce nebo jednotlivých poznámkách" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and an option to hide the editor header bar" msgstr "Režim soustředění a možnost skrýt panel záhlaví" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "Technologická ukázka: export do PDF, ODT a HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Konvergentní návrh, díky kterému je Iotas doma jak na desktopu, tak na mobilu" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Vyhledávání z GNOME Shellu" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "Zálohování a obnova poznámek (z CLI, při používání bez synchronizace)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Možnost měnit velikost písma a přepínat styl monospace" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Psaní v jazyce markdown je podporované, ale je není povinné, nabízí:" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Syntax highlighting with themes" msgstr "Zvýraznění syntaxe s různými tématy" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "A formatted view" msgstr "Formátované zobrazení" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "The ability to check off task lists from the formatted view" msgstr "Možnost odškrtávat seznamy úkolů z formátovaného zobrazení" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:92 msgid "Slightly more technical details, for those into that type of thing" msgstr "Trochu více technických detailů pro ty, kteří tomu holdují:" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:95 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "Synchronizace s Nextcloud Notes je skrze REST API, ne WebDAV, díky čemuž je " "rychlejší" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "There's basic sync conflict detection" msgstr "Je k dispozici základní detekce synchronizačních konfliktů" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "Notes are constantly saved" msgstr "Poznámky jsou neustále ukládány" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Large note collections are partially loaded to quicken startup" msgstr "Velké sbírky poznámek jsou částečně načteny, aby se urychlilo spuštění" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Poznámky jsou uložené v SQLite, což poskytuje rychlé vyhledávání (FTS) bez " "znovuvynalézání kola. Prosté soubory můžete získat vytvořením zálohy (v CLI)." #. Translators: Part of metainfo description. "Iotas" is the application name, do not translate. Left to your discretion whether it makes sense to translate "iota" or not. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:106 msgid "" "Why \"Iotas\"? An iota is a little bit and this app is designed for jotting " "down little things on little devices. Iota stems from the same Greek word as " "jot and is commonly used in negative statements eg. \"not one iota of …\", " "but we think the word has more to give. Maybe somebody will take note?" msgstr "" "Proč \"Iotas\"? Iota je málo a tato aplikace je určena k zapisování malých " "věcí na malých zařízeních. Iota pochází ze stejného řeckého slova jako jot a " "běžně se používá v záporných výrocích, např. \"ani iota z ...\", ale my si " "myslíme, že toto slovo má na víc. Třeba si toho někdo všimne?" #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:14 msgid "Index" msgstr "Rejstřík" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editor s markdownem" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Vykreslený markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Rejstřík ve tmavém stylu" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobil" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Jiří Eischmann" #. Translators: Button #: data/ui/category_header_bar.ui:11 data/ui/editor_rename_header_bar.ui:13 msgid "Revert changes" msgstr "Vrátit změny" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:38 data/ui/editor_rename_header_bar.ui:36 msgid "Apply changes" msgstr "Použít změny" #. Translators: Button #: data/ui/category_header_bar.ui:40 data/ui/editor_rename_header_bar.ui:38 msgid "Apply" msgstr "Použít" #. Translators: Button #: data/ui/category_header_bar.ui:54 msgid "Clear and apply" msgstr "Vymazat a použít" #. Translators: Placeholder text #. Translators: Menu item #: data/ui/editor_search_entry.ui:14 data/ui/editor.ui:25 msgid "Find" msgstr "Hledat" #. Translators: Button #: data/ui/editor_search_header_bar.ui:12 data/ui/index_search_header_bar.ui:11 #: data/ui/render_search_header_bar.ui:11 data/ui/selection_header_bar.ui:16 msgid "Back" msgstr "Zpět" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:39 #: data/ui/keyboard_shortcuts_window.ui:169 #: data/ui/render_search_header_bar.ui:32 msgid "Previous match" msgstr "Předchozí shoda" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:47 #: data/ui/keyboard_shortcuts_window.ui:162 #: data/ui/render_search_header_bar.ui:40 msgid "Next match" msgstr "Následující shoda" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:69 #: data/ui/editor_search_header_bar.ui:78 #: data/ui/keyboard_shortcuts_window.ui:155 msgid "Replace" msgstr "Nahradit" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:182 msgid "Focus mode" msgstr "Režim soustředění" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:32 data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit title" msgstr "Upravit název" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:37 data/ui/keyboard_shortcuts_window.ui:107 msgid "Change category" msgstr "Změnit kategorii" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Delete" msgstr "Smazat" #. Translators: Menu item #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/editor.ui:49 data/ui/keyboard_shortcuts_window.ui:93 #: iotas/export_dialog.py:119 msgid "Export" msgstr "Exportovat" #. Translators: Button #: data/ui/editor.ui:65 msgid "Back to notes" msgstr "Zpátky k poznámkám" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:109 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle markdown render" msgstr "Přepnout na vykreslení markdownu" #. Translators: Button #: data/ui/editor.ui:117 msgid "Edit note" msgstr "Upravit poznámku" #. Translators: Description #: data/ui/editor.ui:143 msgid "Read-only note" msgstr "Poznámka pouze ke čtení" #. Translators: Description, help #: data/ui/editor.ui:211 msgid "Render engine loading" msgstr "Načítání vykreslovacího jádra" #. Translators: Title #: data/ui/empty_state.ui:11 msgid "Let's get started" msgstr "Začínáme" #. Translators: Description, help #: data/ui/empty_state.ui:43 msgid "Add new feeds via URL" msgstr "Přidat nové kanály skrze URL" #. Translators: Description, help #: data/ui/empty_state.ui:54 msgid "Import an OPML file" msgstr "Importovat soubor OPML" #. Translators: Button #: data/ui/export_dialog.ui:21 data/ui/nextcloud_login_dialog.ui:21 msgid "Cancel" msgstr "Zrušit" #. Translators: Title #: data/ui/export_dialog.ui:29 msgid "Export As..." msgstr "Exportovat jako..." #. Translators: Title #: data/ui/export_dialog.ui:49 msgid "Exporting..." msgstr "Probíhá exportování..." #. Translators: Button #: data/ui/export_dialog.ui:68 data/ui/export_dialog.ui:95 #: iotas/ui_utils.py:112 msgid "Close" msgstr "Zavřít" #. Translators: Button #: data/ui/export_dialog.ui:75 msgid "Show" msgstr "Zobrazit" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Vítejte v Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:29 msgid "Add a note" msgstr "Přidat poznámku" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:49 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Synchronizovat s Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom out" msgstr "Oddálit" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom in" msgstr "Přiblížit" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Obnovit" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Předvolby" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Klávesové zkratky" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "O aplikaci Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Menu" msgstr "Nabídka" #. Translators: Section title #: data/ui/index_note_list.ui:58 msgid "Today" msgstr "Dnes" #. Translators: Section title #: data/ui/index_note_list.ui:90 msgid "Yesterday" msgstr "Včera" #. Translators: Section title #: data/ui/index_note_list.ui:122 msgid "This Week" msgstr "Tento týden" #. Translators: Section title #: data/ui/index_note_list.ui:154 msgid "This Month" msgstr "Tento měsíc" #. Translators: Section title #: data/ui/index_note_list.ui:186 msgid "Last Month" msgstr "Minulý měsíc" #. Translators: Button #: data/ui/index_note_list.ui:217 msgid "Show earlier months" msgstr "Zobrazit dřívější měsíce" #. Translators: Section title #: data/ui/index_note_list.ui:235 msgid "Before Last Month" msgstr "Před minulým měsícem" #. Translators: Button #: data/ui/index_note_list.ui:267 msgid "Show more" msgstr "Zobrazit více" #: data/ui/index.ui:20 msgid "Categories" msgstr "Kategorie" #. Translators: Button #: data/ui/index.ui:41 msgid "Open categories" msgstr "Otevřít kategorie" #. Translators: Button #: data/ui/index.ui:49 msgid "New note" msgstr "Nová poznámka" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:68 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:148 msgid "Search" msgstr "Hledání" #. Translators: Button #: data/ui/index.ui:76 msgid "Select notes" msgstr "Vybrat poznámky" #. Translators: Description #: data/ui/index.ui:94 msgid "Server connection offline" msgstr "Spojení se serverem přerušeno" #. Translators: Description #: data/ui/index.ui:100 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Kvůli změnám na pozadí (nové ID aplikace) se Iotas musí znovu ověřit na " "serveru Nextcloud." #. Translators: Button #: data/ui/index.ui:102 data/ui/index.ui:111 msgid "Authenticate" msgstr "Ověřit" #. Translators: Description #: data/ui/index.ui:109 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "Ověřovací token pro synchronizaci s Nextcloud Notes se nepodařilo stáhnout" #. Translators: Description, help #: data/ui/index.ui:134 msgid "Note list empty" msgstr "Seznam poznámek je prázdný" #. Translators: Description, help #: data/ui/index.ui:141 msgid "Enter search term" msgstr "Zadejte hledaný termín" #. Translators: Description, help #: data/ui/index.ui:148 msgid "No search results" msgstr "Žádné výsledky hledání" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create new note" msgstr "Vytvořit novou poznámku" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show sidebar" msgstr "Zobrazit postranní panel" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete note" msgstr "Smazat poznámku" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move up list" msgstr "Posunout v seznamu nahoru" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move down list" msgstr "Posunout v seznamu dolů" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start selection" msgstr "Spustit výběr" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset filter" msgstr "Resetovat filtr" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open first search result" msgstr "Otevřít první výsledek hledání" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:36 msgid "Editor" msgstr "Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create new note including selection" msgstr "Vytvořit novou poznámku včetně výběru" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo typing" msgstr "Vrácení napsaného" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo typing" msgstr "Obnovení napsaného" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Return to Index" msgstr "Vrátit se do rejstříku" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:143 msgid "Editor Search" msgstr "Upravit hledání" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:177 msgid "Editor Appearance" msgstr "Vzhled editoru" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:189 msgid "Increase line length" msgstr "Zvýšit délku řádku" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:196 msgid "Decrease line length" msgstr "Snížit délku řádku" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:203 msgid "Increase font size" msgstr "Zvýšit velikost písma" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:210 msgid "Decrease font size" msgstr "Snížit velikost písma" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:218 msgid "General" msgstr "Obecné" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:223 msgid "Toggle fullscreen" msgstr "Přepnout na celou obrazovku" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:230 msgid "Show preferences" msgstr "Zobrazit předvolbxy" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:237 msgid "Show shortcuts" msgstr "Zobrazit klávesové zkratky" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:244 msgid "Go back" msgstr "Jít zpět" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:251 msgid "Quit" msgstr "Ukončit" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:30 msgid "Continue" msgstr "Pokračovat" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:67 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Po stisknutí tlačítka Pokračovat zadejte adresu serveru Nextcloud a " "přihlaste se prostřednictvím webového prohlížeče." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:95 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "K Secret Service nebylo možné získat přístup pro uložení ověřovacích údajů. " "Ujistěte se, že máte poskytovatele, například gnome-keyring. Je třeba " "nastavit výchozí svazek klíčů a tento svazek klíčů odemknout. Většina " "desktopových prostředí vám toto poskytne. Restartujte aplikaci a zkuste to " "znovu." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:116 msgid "Nextcloud Server URL" msgstr "URL serveru Nextcloud" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:157 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Zdá se, že používáte certifikát SSL s vlastním podpisem, což vede k tomu, že " "identita serveru není ověřena. Pokud se to očekává, postupujte podle pokynů " "v často kladených dotazech a poskytněte řetězový soubor certifikační " "autority." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:163 msgid "Open the FAQ" msgstr "Otevřít FAQ" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:188 msgid "Connecting" msgstr "Připojování" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:195 msgid "Waiting for completion of login in browser" msgstr "Čeká se na dokončení přihlášení v prohlížeči" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:202 msgid "Performing initial transfer" msgstr "Probíhá úvodní stažení dat" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:209 msgid "Updating notes" msgstr "Probíhá aktualizace poznámek" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:242 msgid "Connection established with Nextcloud Notes" msgstr "Spojení s Nextcloud Notes navázáno" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Rozhraní" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Automatically Expand Sidebar" msgstr "Automaticky rozbalovat postranní panel" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:20 msgid "On desktop, when there is space." msgstr "Na desktopu, když je místo." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:28 msgid "Category Label Style" msgstr "Styl štítků kategorií" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Use Monospace Font" msgstr "Použít písmo s pevnou šířkou" #. Translators: Title #: data/ui/preferences_dialog.ui:47 msgid "Check Spelling" msgstr "Kontrola pravopisu" #. Translators: Title #: data/ui/preferences_dialog.ui:54 msgid "Hide Headerbar" msgstr "Skrýt panel záhlaví" #. Translators: Title #: data/ui/preferences_dialog.ui:61 msgid "Hide Headerbar When Fullscreen" msgstr "Skrýt panel záhlaví při zobrazení na celé obrazovce" #. Translators: Title #: data/ui/preferences_dialog.ui:68 msgid "Limit Line Length" msgstr "Limit délky řádku" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:71 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Primárně pro desktop. Chcete-li upravit, použijte na klávesnici Ctrl + ↑ a " "Ctrl + ↓." #. Translators: Title #: data/ui/preferences_dialog.ui:79 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:83 msgid "Highlight Syntax" msgstr "Zvýrazňovat syntaxi" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:85 msgid "Disable for slightly improved performance." msgstr "Vypněte, chcete-li trochu lepší výkon." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:92 msgid "Syntax Theme" msgstr "Téma syntaxe" #. Translators: Title #: data/ui/preferences_dialog.ui:98 msgid "Enable Formatted View" msgstr "Povolit formátované zobrazení" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:100 msgid "Disable to reduce startup time." msgstr "Vypněte, chcete-li zkrátit dobu spouštění." #. Translators: Title #: data/ui/preferences_dialog.ui:107 msgid "Open In Formatted View" msgstr "Otevírat ve formátovaném zobrazení" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:109 msgid "Enabling opens all notes as rendered markdown." msgstr "Povolení bude otevírat všechny poznámky vykreslené markdownem." #. Translators: Title #: data/ui/preferences_dialog.ui:116 msgid "Support Math Equations" msgstr "Podporovat matematické rovnice" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:118 msgid "Slightly decreases render performance." msgstr "Částečně snižuje výkon vykreslování." #. Translators: Title #: data/ui/preferences_dialog.ui:125 msgid "Render Using Monospace Font" msgstr "Vykreslovat za použití písma s pevnou šířkou" #. Translators: Title #: data/ui/preferences_dialog.ui:132 msgid "Proportional To Monospace Font Size Ratio" msgstr "Poměr velikosti písma proporcionální vs s pevnou šířkou" #: data/ui/preferences_dialog.ui:133 msgid "In render view. Use 1 for no adjustment." msgstr "Ve vykresleném zobrazení. Nechcete-li žádnou úpravu, použije 1." #. Translators: Title #: data/ui/preferences_dialog.ui:149 msgid "Hold Engine In Memory" msgstr "Držet jádro v paměti" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:151 msgid "Faster subsequent conversions for higher memory usage." msgstr "Rychlejší následné konverze za cenu vyšší spotřeby paměti." #. Translators: Title #: data/ui/preferences_dialog.ui:164 msgid "Data" msgstr "Data" #. Translators: Title #: data/ui/preferences_dialog.ui:170 msgid "Reset Database" msgstr "Resetovat databázi" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:172 msgid "Delete all notes from the local database. The app will quit." msgstr "Smazat všechny poznámky z lokální databáze. Aplikace se ukončí." #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "Odpojit od Nextcloudu" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Odhlásí se z Nextcloud Notes. Všechny poznámky budou odstraněny a aplikace " "se ukončí." #. Translators: Title #: data/ui/preferences_dialog.ui:216 msgid "Debug" msgstr "Ladit" #. Translators: Title #: data/ui/preferences_dialog.ui:222 msgid "Clear Sync Timestamp" msgstr "Vymazat časové razítko synchronizace" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:224 msgid "Forces a pull of all notes from the sync server." msgstr "Vynucuje stažení všech poznámek ze synchronizačního serveru." #. Translators: Button #: data/ui/selection_header_bar.ui:32 msgid "Delete selected" msgstr "Smazat vybrané" #. Translators: Button #: data/ui/selection_header_bar.ui:43 msgid "Toggle favorite for selected" msgstr "Přepnout příznak Oblíbené pro vybrané" #. Translators: Button #: data/ui/selection_header_bar.ui:51 msgid "Change category for selected" msgstr "Změnit kategorii pro vybrané" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close categories" msgstr "Zavřít kategorie" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:26 data/ui/theme_selector.ui:29 msgid "Follow system style" msgstr "Řídit se systémovým stylem" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:45 data/ui/theme_selector.ui:48 msgid "Light style" msgstr "Světlý styl" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:64 data/ui/theme_selector.ui:67 msgid "Dark style" msgstr "Tmavý styl" #. Translators: Description, CLI option #: iotas/application.py:236 msgid "Create a note" msgstr "Vytvořit poznámku" #. Translators: Description, CLI option #: iotas/application.py:245 msgid "Create a backup" msgstr "Vytvořit zálohu" #. Translators: Description, CLI option #: iotas/application.py:254 msgid "Restore a backup" msgstr "Obnovit zálohu" #. Translators: Description, CLI option #: iotas/application.py:263 msgid "Display backup path" msgstr "Zobrazit cestu k záloze" #. Translators: Description, CLI option #: iotas/application.py:272 msgid "Display path for custom server SSL CA chain file" msgstr "" "Zobrazit cestu k vlastnímu souboru řetězce certifikační autority SSL serveru" #. Translators: Description, CLI option #: iotas/application.py:281 msgid "Toggle display of extended preferences in UI" msgstr "Přepínat zobrazení rozšířených předvoleb v UI" #. Translators: Description, CLI option #: iotas/application.py:290 msgid "Quit any running instance" msgstr "Ukončit všechny běžící instance" #. Translators: Description, CLI option #: iotas/application.py:299 msgid "Enable debug logging and functions" msgstr "Povolit logování a funkce pro ladění" #. Translators: Description, CLI option #: iotas/application.py:308 msgid "Open note by id" msgstr "Otevřít poznámku podle id" #. Translators: Description, CLI option #: iotas/application.py:317 msgid "Search in notes" msgstr "Hledat v poznámkách" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:185 msgid "RESTORATION REMOTE ID CLASH" msgstr "KONFLIKT SE VZDÁLENÝM ID PŘI OBNOVĚ" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:203 msgid "RESTORATION TITLE CLASH" msgstr "KONFLIKT NÁZVŮ PRO OBNOVĚ" #. Translators: Title #: iotas/category.py:19 msgid "All notes" msgstr "Všechny poznámky" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Bez kategorie" #. Translators: Description, notification #: iotas/editor.py:680 msgid "Line length limit already disabled" msgstr "Limit délky řádku je už vypnutý" #. Translators: Description, notification #: iotas/editor.py:690 msgid "Line length limit disabled" msgstr "Limit délky řádku vypnutý" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:764 #, python-brace-format msgid "Line length now {0}px" msgstr "Délka řádku nyní {0} px" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:770 #, python-brace-format msgid "Font size now {0}pt" msgstr "Velikost písma nyní {0} px" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} z {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:91 msgid "Exported to {}" msgstr "Exportováno do {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:104 msgid "Failed to export to {}" msgstr "Selhal export do {}" #. Translators: Description, notification #: iotas/index.py:91 iotas/index.py:813 msgid "Loading" msgstr "Načítání" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:187 msgid "{} notes deleted" msgstr "{} poznámek smazáno" #. Translators: Description, notification #: iotas/index.py:190 msgid "Note deleted" msgstr "Poznámka smazána" #. Translators: Button #: iotas/index.py:195 msgid "Undo" msgstr "Zpět" #. Translators: Description, notification #: iotas/index.py:235 msgid "Sync conflict with note being edited" msgstr "Konflikt synchronizace kvůli upravované poznámce" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" #. should likely not be translated. #: iotas/index.py:245 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Selhání přístupu k Secret Service. Ujistěte se, že máte poskytovatele, jako " "je gnome-keyring, který má výchozí nastavení klíčenky, která je odemčená." #. Translators: Button #: iotas/index.py:251 msgid "OK" msgstr "OK" #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Synchronizace" #. Translators: Description, notification, {} is a number #: iotas/index.py:510 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} změna" msgstr[1] "{} změny" msgstr[2] "{} změn" #. Translators: Description, notification #: iotas/index.py:527 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "" "Selhání synchronizace. Je aplikace Nextcloud Notes na serveru nainstalovaná?" #. Translators: Button #: iotas/nextcloud_login_dialog.py:124 msgid "Finish" msgstr "Dokončit" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:218 msgid "Failed to start login with possible certificate issue" msgstr "Nepodařilo se spustit přihlášení s možným problémem certifikátu" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:221 msgid "Failed to start login. Wrong address?" msgstr "Selhal začátek přihlašování. Špatná adresa?" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:79 msgid "Monochrome" msgstr "Monochromatické" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:81 msgid "Muted" msgstr "Tlumené" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:83 msgid "Blue" msgstr "Modré" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:85 msgid "Orange" msgstr "Oranžové" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:87 msgid "Red" msgstr "Červené" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:89 msgid "None" msgstr "Žádné" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:222 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Snížení o {0} stisků" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:225 #, python-brace-format msgid "Extending in {0} presses" msgstr "Prohloužení o {0} stisků" #. Translators: Description, notification #: iotas/preferences_dialog.py:230 msgid "Extended hidden" msgstr "Rozšířené skryté" #. Translators: Description, notification #: iotas/preferences_dialog.py:233 msgid "Extended shown" msgstr "Rozšířené zobrazené" #. Translators: Description, alert #: iotas/selection_header_bar.py:86 iotas/selection_header_bar.py:182 msgid "Unable to change category on read-only note" msgstr "Nelze změnit kategorii u poznámky pouze ke čtení" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:165 msgid "{} Selected" msgstr "{} vybráno" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:456 msgid "SYNC CONFLICT" msgstr "KONFLIKT SYNCHRONIZACE" #. Translators: Title #: iotas/ui_utils.py:110 msgid "Error" msgstr "Chyba" #~ msgid "Editor with plain text" #~ msgstr "Editor s prostým textem" #~ msgid "1 change" #~ msgstr "1 změna" #~ msgid "notes;nextcloud;base;" #~ msgstr "poznámky;nextcloud;notes;" #~ msgid "" #~ "Iotas is a simple note taking app with mobile-first design and a focus on " #~ "sync with Nextcloud Notes." #~ msgstr "" #~ "Iotas je jednoduchá aplikace na pořizování poznámek s mobilním designem a " #~ "zaměřením na synchronizaci s Nextcloud Notes." #~ msgid "Although simple by design there are a few features" #~ msgstr "Ačkoliv má jednoduchý design, má také nějaké funkce:" #~ msgid "Basic search" #~ msgstr "Jednoduché vyhledávání" #~ msgid "Please quit the running instance of Iotas before creating the backup" #~ msgstr "" #~ "Prosím ukončete běžící instanci Iotas před tím, než vytvoříte zálohu" #~ msgid "" #~ "Please quit the running instance of Iotas before restoring the backup" #~ msgstr "Prosím ukončete běžící instanci Iotas před tím, než obnovíte zálohu" #~ msgid "No running instance found" #~ msgstr "Nenalezena žádná běžící instance" #~ msgid "Hiding extended preferences" #~ msgstr "Skrývání rozšířených předvoleb" #~ msgid "Showing extended preferences" #~ msgstr "Zobrazování rozšířených předvoleb" #, python-brace-format #~ msgid "Failed to create backup directory at {0}: {1}" #~ msgstr "Selhalo vytvoření adresáře pro zálohu v {0}: {1}" #~ msgid "Failed to move previous backup to archive path" #~ msgstr "Selhalo přesunutí předchozí zálohy do cesty archivu" #~ msgid "Backup created at {}" #~ msgstr "Záloha vytvořena v {}" #~ msgid "" #~ "Backup restoration isn't possible with Nextcloud Notes sync configured" #~ msgstr "" #~ "Obnovení zálohy není možné s nastavenou synchronizací Nextcloud Notes" #~ msgid "Backup failed" #~ msgstr "Zálohování selhalo" #~ msgid "No backup exists at {}" #~ msgstr "Žádná záloha neexistuje v {}" #~ msgid "Backup restoration can only be run when there are no existing notes" #~ msgstr "" #~ "Obnova zálohy může proběhnout pouze tehdy, kdy nejsou vytvořené žádné " #~ "poznámky" #~ msgid "Backup restoration failed" #~ msgstr "Obnova zálohy selhala" #~ msgid "Backup restoration completed" #~ msgstr "Obnova zálohy dokončena" #, python-brace-format #~ msgid "Failed to write metadata to {0}: {1}" #~ msgstr "Selhal zápis metadat do {0}: {1}" #~ msgid "Creating {}" #~ msgstr "Vytváření {}" #~ msgid "Skipping restoration of existing identical note \"{}\"" #~ msgstr "Přeskakuje se obnova existující identické poznámky \"{}\"" #~ msgid "Duplicating note \"{}\" due to matching remote id" #~ msgstr "Zdvojuje se poznámka \"{}\", protože odpovídá vzdálenému id" #~ msgid "Updating metadata for note \"{}\"" #~ msgstr "Aktualizace metadat pro poznámku \"{}\"" #~ msgid "" #~ "Skipping note \"{}\" with matching title, contents and a newer timestamp" #~ msgstr "" #~ "Přeskakuje se poznámka \"{}\" se stejným názvem, obsahem a novější " #~ "časovou značkou" #~ msgid "Duplicating note \"{}\" due to matching title but different content" #~ msgstr "" #~ "Zdvojuje se poznámka \"{}\", protože název odpovídá, ale obsah je jiný" #, python-brace-format #~ msgid "Failed to remove backup archive directory at {0}: {1}" #~ msgstr "Selhalo odstranění adresáře s archivem zálohy v {0}: {1}" #, python-brace-format #~ msgid "Failed to create backup archive directory at {0}: {1}" #~ msgstr "Selhalo vytvoření adresáře s archivem zálohy v {0}: {1}" #, python-brace-format #~ msgid "Failed to move {0} into {1}: {2}" #~ msgstr "Selhal přesun {0} do {1}: {2}" #~ msgid "Skipping \"{}\" due to missing content" #~ msgstr "Přeskakuje se \"{}\" kvůli chybějícímu obsahu" #, python-brace-format #~ msgid "Bailing \"{0}\" due to exceeding {1}MB" #~ msgstr "Přeskakuje se \"{0}\" kvůli velikosti větší než {1}MB" #, python-brace-format #~ msgid "Failed to read note content from {0}: {1}" #~ msgstr "Selhalo čtení obsahu poznámek z {0}: {1}" #, python-brace-format #~ msgid "Failed to read note metadata from {0}: {1}" #~ msgstr "Selhalo čtení metadat poznámek z {0}: {1}" #~ msgid "Failed to parse note metadata from \"{}\"" #~ msgstr "Selhalo analyzování metadat poznámek z \"{}\"" #~ msgid "Theme used by editor view" #~ msgstr "Motiv použitý v zobrazení editoru" #~ msgid "The GtkSourceView style scheme id" #~ msgstr "ID schématu stylu GtkSourceView" #~ msgid "First start" #~ msgstr "První spuštění" #~ msgid "Whether starting for the first time." #~ msgstr "Zdali se spouští poprvé." #~ msgid "Font size" #~ msgstr "Velikost písma" #~ msgid "Font used in main editor view." #~ msgstr "Písmo používané v hlavním zobrazení editoru." #~ msgid "" #~ "Line length used in both the editor and markdown render views (pixels)." #~ msgstr "Délka řádku použitá v editoru i vykreslení markdownu (v pixelech)" #~ msgid "Whether to use a monospace font" #~ msgstr "Zda použít písmo s pevnou šířkou" #~ msgid "" #~ "The specific fonts are sourced from GNOME's monospace and document font " #~ "settings" #~ msgstr "Konkrétní písma jsou získána z nastavení písma v GNOME" #~ msgid "Markdown render view support" #~ msgstr "Podpora zobrazení vykreslení Markdown" #~ msgid "" #~ "Whether to support showing markdown render view (a temporary performance " #~ "concession for a WebKit issue)" #~ msgstr "" #~ "Zda podporovat zobrazení vykreslování markdown (dočasný výkonnostní " #~ "ústupek kvůli problému s WebKitem)" #~ msgid "Markdown syntax highlighting" #~ msgstr "Zvýraznění syntaxe Markdown" #~ msgid "Whether to highlight markdown syntax." #~ msgstr "Zda zvýrazňovat syntaxi Markdown." #~ msgid "Markdown WebKit process retention." #~ msgstr "Zachování procesu Markdown WebKit." #~ msgid "" #~ "When enabled the WebKit process is retained between uses of the render " #~ "view, decreasing load time and increasing memory usage." #~ msgstr "" #~ "Pokud je tato funkce povolena, proces WebKit zůstává mezi jednotlivými " #~ "použitími vykresleného zobrazení zachován, což snižuje dobu načítání a " #~ "zvyšuje využití paměti." #~ msgid "Markdown TeX support for maths equations." #~ msgstr "Podpora pro Markdown TeX pro matematické rovnice." #~ msgid "" #~ "Whether to support rendering maths equations. Slightly increases markdown " #~ "render time." #~ msgstr "" #~ "Zda podporovat vykreslování matematických rovnic. Mírně prodlužuje čas " #~ "potřebný k vykreslení markdownu." #~ msgid "Markdown monospace font." #~ msgstr "Písmo s pevnou šířkou pro Markdown." #~ msgid "Whether to use a monospace font for the markdown render." #~ msgstr "Zda použít písmo s pevnou šířkou pro vykreslování markdownu." #~ msgid "Markdown default to render." #~ msgstr "Výchozí markdown pro vykreslování." #~ msgid "Whether to show the render view when opening the note." #~ msgstr "Zda zobrazovat vykreslené zobrazení, když se otevře poznámka." #~ msgid "Ratio adjusting proportional to monospace font in markdown render" #~ msgstr "" #~ "Poměr, kterým se má přizpůsobit proporcionální písmu s pevnou šířkou ve " #~ "vykreslování markdownu" #~ msgid "A value of 1 will result in no adjustment." #~ msgstr "Hodnota 1 znamená žádné přizpůsobení." #~ msgid "Nextcloud server to sync against" #~ msgstr "Server Nextcloudu, s kterým se synchronizovat" #~ msgid "Path to the last Nextcloud sync instance." #~ msgstr "Cesta k instanci Nextcloudu, s kterou se naposledy synchronizovalo." #~ msgid "Username for the Nextcloud sync server" #~ msgstr "Uživatelské jméno pro synchronizaci se serverem Nextcloudu" #~ msgid "Login to use with the Nextcloud sync instance." #~ msgstr "" #~ "Přihlašovací údaje, které se mají použít s instancí Nextcloudu pro " #~ "synchronizaci." #~ msgid "Prune threshold for Nextcloud sync" #~ msgstr "Ořezání prahové hodnoty pro synchronizaci Nextcloud" #~ msgid "" #~ "Used to reduce the number of records pulled from the Nextcloud server " #~ "during sync." #~ msgstr "" #~ "Slouží ke snížení počtu záznamů stažených ze serveru Nextcloud během " #~ "synchronizace." #~ msgid "Whether to show a message on Secret Service failure" #~ msgstr "Zda se má zobrazit zpráva o selhání Secret Service" #~ msgid "" #~ "Disabling this provides for a cleaner startup if never intending to use " #~ "Nextcloud Notes sync. on a device without a Secret Service provider." #~ msgstr "" #~ "Zakázáním této funkce zajistíte čistší spuštění, pokud nikdy nemáte v " #~ "úmyslu používat synchronizaci poznámek Nextcloud na zařízení bez " #~ "poskytovatele služby Secret Service." #~ msgid "Whether to show a notification when syncing from the server" #~ msgstr "Zda zobrazovat upozornění, když se synchronizuje se serverem" #~ msgid "Useful for increasing visibility of network issues" #~ msgstr "Užitečné pro zvýšení viditelnosti problémů se sítí" #~ msgid "Spelling enabled" #~ msgstr "Pravopis povolen" #~ msgid "Whether spell checking is enabled." #~ msgstr "Zda je povolena kontrola pravopisu." #~ msgid "Spelling language" #~ msgstr "Jazyk pravopisu" #~ msgid "Language tag to attempt to use by default for spelling." #~ msgstr "" #~ "Značka jazyka, kterou se pokusí použít ve výchozím nastavení pro pravopis." #~ msgid "Colour scheme style" #~ msgstr "Styl barevného schématu" #~ msgid "" #~ "Choosing to follow desktop colour style or enforce dark or light visuals." #~ msgstr "" #~ "Volba barevného stylu desktopu nebo vynucení tmavých či světlých vizuálů." #~ msgid "Sync interval" #~ msgstr "Interval synchronizace" #~ msgid "Interval between pulling from the Nextcloud sync server (seconds)." #~ msgstr "" #~ "Interval mezi stahováními ze synchronizačního serveru Nextcloud (v " #~ "sekundách)." #~ msgid "Window size" #~ msgstr "Velikost okna" #~ msgid "Remember the window size." #~ msgstr "Pamatovat si velikost okna." #~ msgid "Whether to persist the index sidebar in large windows" #~ msgstr "Zda má ve velkých oknech přetrvávat postranní panel rejstříku" #~ msgid "" #~ "Whether to the index sidebar is permanently present in large windows " #~ "(generally desktop)" #~ msgstr "" #~ "Zda je postranní panel rejstříku trvale přítomen ve velkých oknech " #~ "(obecně na desktopu)" #~ msgid "Whether to automatically hide the editor headerbar" #~ msgstr "Zda se má automaticky skrýt panel záhlaví editoru" #~ msgid "Setting to true automatically hides the editor headerbar" #~ msgstr "Nastavení na hodnotu true automaticky skryje panel záhlaví editoru" #~ msgid "Whether to hide the editor headerbar when fullscreen" #~ msgstr "" #~ "Zda se má skrýt panel záhlaví editoru při zobrazení na celou obrazovku" #~ msgid "" #~ "Setting to true automatically hides the editor headerbar entering " #~ "fullscreen mode" #~ msgstr "" #~ "Nastavení na hodnotu true automaticky skryje panel záhlaví editoru při " #~ "vstupu do celoobrazovkového režimu" #~ msgid "File extension for backed up notes" #~ msgstr "Přípona souboru pro zálohované poznámky" #~ msgid "File extension added to each note when exporting for backup." #~ msgstr "" #~ "Přípona souboru přidaná ke každé poznámce, když se exportuje záloha." #~ msgid "Index category style" #~ msgstr "Styl kategorií v rejstříku" #~ msgid "Style options for category labels on index rows" #~ msgstr "Možnosti stylu pro štítky kategorií v řádcích rejstříku" #~ msgid "Last launched version" #~ msgstr "Poslední spuštěná verze" #~ msgid "The last version of the app that was run. Shouldn't be edited." #~ msgstr "" #~ "Verze aplikace, která byla naposledy puštěná. Nemělo by být upravováno." #~ msgid "Directory last used for export" #~ msgstr "Složka naposledy použitá pro export" #~ msgid "" #~ "Only applies to instances with filesystem access. Shouldn't be edited." #~ msgstr "" #~ "Týká se pouze instancí s přístupem k souborovému systému. Nemělo by být " #~ "editováno." #~ msgid "Extra pandoc formats for exporting" #~ msgstr "Další formáty pandoc pro exportování" #~ msgid "See README for definition" #~ msgstr "Definici najdete v README" #~ msgid "Perform full server refresh" #~ msgstr "Provést úplnou aktualizaci ze serveru" #~ msgid "" #~ "Whether to run a full update of all notes from the server. Used for eg. " #~ "schema migrations." #~ msgstr "" #~ "Zda spustit plnou aktualizaci všech poznámek ze serveru. Používá se např. " #~ "u převodů schémat." #~ msgid "Whether to show extended preferences" #~ msgstr "Zda se mají zobrazovat rozšířené volby" #~ msgid "When enabled an excessive number of preferences are shown." #~ msgstr "Pokud je povoleno, zobrazí se nadměrný počet předvoleb." #~ msgid "Searching" #~ msgstr "Hledání" #~ msgid "Sync. with Nextcloud Notes" #~ msgstr "Synchronizace s Nextcloud Notes" #~ msgid "Index on mobile" #~ msgstr "Seznam na mobilu" #~ msgid "Editor on mobile" #~ msgstr "Editor na mobilu" #~ msgid "Index on desktop" #~ msgstr "Seznam na desktopu" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/de.po000066400000000000000000001725601507102636600217630ustar00rootroot00000000000000# German translations for iotas package. # Copyright (C) 2022 THE iotas'S COPYRIGHT HOLDER # This file is distributed under the same license as the iotas package. # Jürgen Benvenuti , 2022-2025. # Philipp Kiemle , 2025. # msgid "" msgstr "" "Project-Id-Version: iotas\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/-/issues\n" "POT-Creation-Date: 2025-07-29 08:18+0000\n" "PO-Revision-Date: 2025-07-29 11:29+0200\n" "Last-Translator: Philipp Kiemle \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.6\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Einfach Notizen erstellen mit Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;Notizen;Nextcloud;minimalistisch;Ablenkung;Editor;fokussiert;Text;schreiben;Markdown;Dokument;gnome;gtk;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Neue Notiz" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Einfach Notizen erstellen" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "Iotas aims to provide distraction-free note taking via its mobile-first design." msgstr "Iotas möchte mit seinem für Mobilgeräte ausgerichteten Design ablenkungsfreie Notizen ermöglichen." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Funktionen" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Optionale schnelle Synchronisierung mit Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Notizen offline bearbeiten; diese werden bei Gelegenheit synchronisiert" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Bearbeiten und Filtern von Kategorien" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Favoriten" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Rechtschreibprüfung" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Innerhalb der Sammlung oder einzelner Notizen suchen" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "Fokusmodus und optionales Ausblenden der Kopf- und Formatierungsleisten des Editors" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "In der Vorschau: Als PDF, ODT und HTML exportieren" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "Durch ein einheitliches Design fühlt sich Iotas sowohl auf dem Desktop als auch auf Mobilgeräten zu Hause" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Suche aus der GNOME Shell" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "Notiz-Datensicherung und -Wiederherstellung (von der Kommandozeile aus, für die Verwendung ohne Synchronisierung)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Die Möglichkeit zur Änderung der Schriftgröße und zum Umschalten auf dicktengleiche Schrift" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Schreiben in Markdown wird unterstützt, ist aber optional und bietet" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formatieren über Werkzeugleiste und Tastenkürzel" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Syntax-Hervorhebung mit Themen" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Eine formatierte Ansicht" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Die Möglichkeit, Aufgabenlisten aus der formatierten Ansicht abzuhaken" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Ein bisschen mehr technische Details für diejenigen, die auf so etwas stehen" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "»Nextcloud Notes«-Synchronisierung erfolgt über die REST API, nicht über WebDAV, was es sehr flott macht" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Es gibt eine grundlegende Sync-Konflikt-Erkennung" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Notizen werden fortlaufend gespeichert" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "Große Notizsammlungen werden nur teilweise geladen, um den Start zu beschleunigen" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "Notes are stored in SQLite, providing for fast search (FTS) without reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "Notizen sind in SQLite gespeichert, was eine schnelle Suche (FTS) ermöglicht, ohne das Rad neu zu erfinden. Einfache Dateien können durch Erstellen einer Sicherungskopie (CLI) abgerufen werden." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Index" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editor mit Markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Markdown-Vorschau" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Index im dunklen Stil" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobil" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "" "Jürgen Benvenuti , 2022-2025\n" "Philipp Kiemle " #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Änderungen zurücknehmen" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Änderungen anwenden" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Anwenden" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Leeren und anwenden" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Suchen" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Zurück" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_window.ui:287 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Vorheriger Treffer" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_window.ui:280 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Nächster Treffer" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_window.ui:273 msgid "Replace" msgstr "Ersetzen" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:300 msgid "Focus Mode" msgstr "Fokusmodus" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Suchen und Ersetzen …" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Springen zu …" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Titel bearbeiten …" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Kategorie ändern …" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Löschen" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Exportieren …" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Zurück zu Notizen" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Notiz ist schreibgeschützt" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Editormenü" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle Markdown Render" msgstr "Markdown-Vorschau umschalten" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Notiz bearbeiten" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Vorschau-Engine wird geladen" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:338 #: iotas/preferences_dialog.py:359 msgid "Cancel" msgstr "Abbrechen" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As..." msgstr "Exportieren als …" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Exporting..." msgstr "Wird exportiert …" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:71 data/ui/export_dialog.ui:99 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Schließen" #. Translators: Button #: data/ui/export_dialog.ui:78 msgid "Show" msgstr "Anzeigen" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Willkommen bei Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Verwenden Sie die Kopfleiste oben, um …" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Eine Notiz hinzufügen" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Mit Nextcloud Notes synchronisieren" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Verkleinern" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Vergrößern" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_window.ui:239 msgid "Horizontal Rule" msgstr "Horizontale Linie" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_window.ui:246 msgid "Quote" msgstr "Zitat" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_window.ui:225 msgid "Code" msgstr "Code" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_window.ui:253 msgid "Table" msgstr "Tabelle" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Ebene 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Ebene 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Ebene 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Ebene 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Entfernen" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_window.ui:183 msgid "Heading" msgstr "Überschrift" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_window.ui:169 msgid "Bold" msgstr "Fett" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_window.ui:176 msgid "Italic" msgstr "Kursiv" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_window.ui:232 msgid "Strikethrough" msgstr "Durchgestrichen" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_window.ui:190 msgid "Unordered List" msgstr "Ungeordnete Liste" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_window.ui:197 msgid "Ordered List" msgstr "Geordnete Liste" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_window.ui:204 msgid "Checkbox" msgstr "Ankreuzfeld" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_window.ui:218 msgid "Link" msgstr "Verweis" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Aktualisieren" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Einstellungen" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Tastenkürzel" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Info zu Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Hauptmenü" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Heute" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Gestern" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Diese Woche" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Dieser Monat" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Letzter Monat" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Frühere Monate anzeigen" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Vor dem letzten Monat" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Mehr anzeigen" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Kategorien öffnen" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:266 msgid "Search" msgstr "Suchen" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Notizen auswählen" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Server-Verbindung offline" #. Translators: Description #: data/ui/index.ui:93 msgid "Due to behind-the-scenes changes (a new app id) Iotas needs to reauthenticate with your Nextcloud server" msgstr "Aufgrund von Änderungen hinter den Kulissen (eine neue Anwendungskennung), muss sich Iotas bei Ihrem Nextcloud-Server erneut legitimieren" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Legitimieren" #. Translators: Description #: data/ui/index.ui:102 msgid "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "Das Legitimierungs-Token zum Synchronisieren mit Nextcloud Notes konnte nicht abgerufen werden" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Verwerfen" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Notizliste ist leer" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Suchbegriff eingeben" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Keine Suchergebnisse" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create New Note" msgstr "Neue Notiz erstellen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show Sidebar" msgstr "Seitenleiste anzeigen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete Note" msgstr "Notiz löschen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move Up List" msgstr "In der Liste nach oben verschieben" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move Down List" msgstr "In der Liste nach unten verschieben" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start Selection" msgstr "Auswahl beginnen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset Filter" msgstr "Filter zurücksetzen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open First Search Result" msgstr "Erstes Suchergebnis öffnen" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit Title" msgstr "Titel bearbeiten" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_window.ui:93 iotas/export_dialog.py:133 msgid "Export" msgstr "Exportieren" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create New Note Including Selection" msgstr "Neue Notiz inklusive Auswahl erstellen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Change Category" msgstr "Kategorie ändern" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo Typing" msgstr "Eingabe rückgängig machen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo Typing" msgstr "Eingabe wiederholen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Insert Emoji" msgstr "Emoji einfügen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Focus Text View" msgstr "Textansicht fokussieren" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Focus Header Bar" msgstr "Kopfleiste fokussieren" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:156 msgid "Focus Formatting Bar" msgstr "Formatierungsleiste fokussieren" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:164 msgid "Formatting" msgstr "Formatieren" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:211 msgid "Toggle Checkbox" msgstr "Ankreuzfeld umschalten" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:261 msgid "Editor Search" msgstr "Editorsuche" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:295 msgid "Editor Appearance" msgstr "Erscheinungsbild des Editors" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:307 msgid "Increase Line Length" msgstr "Zeilenlänge vergrößern" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:314 msgid "Decrease Line Length" msgstr "Zeilenlänge verkleinern" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:321 msgid "Increase Font Size" msgstr "Schrift vergrößern" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:328 msgid "Decrease Font Size" msgstr "Schrift verkleinern" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:336 msgid "General" msgstr "Allgemein" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:341 msgid "Toggle Fullscreen" msgstr "Vollbild umschalten" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:348 msgid "Show Preferences" msgstr "Einstellungen anzeigen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:355 msgid "Show Shortcuts" msgstr "Tastenkürzel anzeigen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:362 msgid "Open Previous Note" msgstr "Vorherige Notiz öffnen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:369 msgid "Go Back" msgstr "Zurück gehen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:376 msgid "Quit" msgstr "Beenden" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "Adresse" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Text" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud Notes einrichten" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "Press Continue to provide your Nextcloud server address and login via a web browser" msgstr "Drücken Sie »Fortsetzen«, um Ihre Nextcloud-Server-Adresse anzugeben und sich über einen Webbrowser anzumelden" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Fortsetzen" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Weiter zur Adresseingabe" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "»Secret Service« nicht erreichbar" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "The Secret Service could not be accessed for storing authentication details. Ensure you have a provider such as gnome-keyring. A default keyring needs to be setup, and that keyring unlocked. Most desktop environments will provide this for you. Restart the app to try again." msgstr "Es konnte nicht auf »Secret Service« zugegriffen werden, um Legitimierungsdetails zu speichern. Stellen Sie sicher, dass Sie einen Anbieter wie »gnome-keyring« haben. Ein Standardschlüsselbund muss eingerichtet werden, und dieser Schlüsselbund muss entsperrt werden. Die meisten Desktop-Umgebungen stellen dies für Sie bereit. Starten Sie die Anwendung neu und versuchen Sie es noch einmal." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Server-Adresse" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Anmeldung beginnen" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Selbst signiertes Zertifikat" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "You appear to be using a self-signed SSL certificate resulting in the server identity not being verified. If this is expected please follow the instructions in the FAQ to provide a CA chain file." msgstr "Sie scheinen ein selbst signiertes SSL-Zertifikat zu verwenden. Das führt dazu, dass die Identität des Servers nicht verifiziert wird. Wenn Sie dies so erwarten, folgen Sie bitte den Anweisungen in den »Häufig gestellten Fragen«, um eine CA-Zertifikatkettendatei bereitzustellen." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "»Häufig gestellte Fragen« öffnen" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Verbindung hergestellt" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Fertig" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Sync-Einrichtung abschließen" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Gliederung" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Keine Überschriften, auf die der Filter passt" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Keine Überschriften für eine Gliederung gefunden" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Oberfläche" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Dicktengleiche Schrift verwenden" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Rechtschreibung prüfen" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Sprache über das Kontextmenü des Editors ändern" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Kopfleiste" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Zeilenlänge begrenzen" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "Hauptsächlich für den Desktop. Verwenden Sie Strg + ↑ und STRG + ↓ auf der Tastatur zur Feinabstimmung." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Syntax erkennen" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "Required for syntax highlighting and formatting (toolbar and keyboard shortcuts). Disable for slightly improved performance." msgstr "Erforderlich für Syntax-Hervorhebung und Formatierung (Werkzeugleiste und Tastenkürzel). Deaktivieren für geringfügig bessere Leistung." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Thema" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Formatierungsleiste" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Formatierte Ansicht aktivieren" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Deaktivieren, um die Startzeit zu verkürzen" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "In formatierter Ansicht öffnen" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Aktivieren öffnet alle Notizen als Markdown-Vorschau" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Mathematische Gleichungen unterstützen" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Verringert die Vorschau-Leistung geringfügig" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Vorschau mit nicht proportionaler Schrift verwenden" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Verhältnis von proportionaler zu nicht proportionaler Schriftgröße" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "In der Vorschau-Ansicht. Verwenden Sie 1 für keine Anpassung." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Engine im Speicher behalten" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Schnellere nachfolgende Umwandlungen bei höherem Speicherbedarf" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Seitenleiste anheften" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Auf dem Desktop, wenn dort Platz ist" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Stil der Kategorie-Schlagwörter" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Daten" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Reset Database" msgstr "Datenbank zurücksetzen" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Delete all notes from the local database. The app will quit." msgstr "Alle Notizen aus der lokalen Datenbank löschen. Die Anwendung wird geschlossen." #. Translators: Button #: data/ui/preferences_dialog.ui:178 iotas/preferences_dialog.py:340 msgid "Reset" msgstr "Zurücksetzen" #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "Von der Nextcloud trennen" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "Signs out from Nextcloud Notes. All notes will be removed and the app will quit." msgstr "Meldet sich von Nextcloud Notes ab. Alle Notizen werden entfernt und die Anwendung wird geschlossen." #. Translators: Button #: data/ui/preferences_dialog.ui:199 iotas/preferences_dialog.py:361 msgid "Disconnect" msgstr "Trennen" #. Translators: Title #: data/ui/preferences_dialog.ui:217 msgid "Debug" msgstr "Fehlersuche" #. Translators: Title #: data/ui/preferences_dialog.ui:223 msgid "Clear Sync Timestamp" msgstr "Sync-Zeitstempel leeren" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:225 msgid "Forces a pull of all notes from the sync server" msgstr "Erzwingt ein Herunterladen aller Notizen vom Sync-Server" #. Translators: Button #: data/ui/preferences_dialog.ui:232 msgid "Clear" msgstr "Leeren" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Markierte löschen" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Ausgewählte favorisieren/aus Favoriten entfernen" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Kategorie für Ausgewählte ändern" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Kategorien schließen" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Kategorien" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Tabelle einfügen" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Erstellen" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Dem Systemstil folgen" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Heller Stil" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Dunkler Stil" #. Translators: Description, CLI option #: iotas/application.py:300 msgid "Create a note" msgstr "Eine Notiz erstellen" #. Translators: Description, CLI option #: iotas/application.py:309 msgid "Create a backup" msgstr "Eine Datensicherung erstellen" #. Translators: Description, CLI option #: iotas/application.py:318 msgid "Restore a backup" msgstr "Eine Datensicherung wiederherstellen" #. Translators: Description, CLI option #: iotas/application.py:327 msgid "Display backup path" msgstr "Datensicherungspfad anzeigen" #. Translators: Description, CLI option #: iotas/application.py:336 msgid "Display path for custom server SSL CA chain file" msgstr "Pfad für benutzerdefinierte Server-SSL-CA-Zertifikatkettendatei anzeigen" #. Translators: Description, CLI option #: iotas/application.py:345 msgid "Toggle display of extended preferences in UI" msgstr "Anzeige der erweiterten Einstellungen in der Benutzeroberfläche umschalten" #. Translators: Description, CLI option #: iotas/application.py:354 msgid "Quit any running instance" msgstr "Alle laufenden Instanzen beenden" #. Translators: Description, CLI option #: iotas/application.py:363 msgid "Enable debug logging and functions" msgstr "Protokollierung und Funktionen zur Fehlerbehebung aktivieren" #. Translators: Description, CLI option #: iotas/application.py:372 msgid "Open note by id" msgstr "Notiz nach Kennung öffnen" #. Translators: Description, CLI option #: iotas/application.py:381 msgid "Search in notes" msgstr "In Notizen suchen" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "ENTFERNTE-KENNUNG-KONFLIKT BEI WIEDERHERSTELLUNG" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "TITEL-KONFLIKT BEI WIEDERHERSTELLUNG" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Alle Notizen" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Ohne Kategorie" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:958 #, python-brace-format msgid "Line length now {0}px" msgstr "Zeilenlänge jetzt {0}px" #. Translators: Description, notification #: iotas/editor.py:964 msgid "Line length limit disabled" msgstr "Zeilenlängenbegrenzung deaktiviert" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Verweis wird im Browser geöffnet" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} von {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:103 msgid "Exported to {}" msgstr "Exportiert nach {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:116 msgid "Failed to export to {}" msgstr "Export nach {} ist fehlgeschlagen" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:203 msgid "{} notes deleted" msgstr "{} Notizen gelöscht" #. Translators: Description, notification #: iotas/index.py:206 msgid "Note deleted" msgstr "Notiz gelöscht" #. Translators: Button #: iotas/index.py:211 msgid "Undo" msgstr "Rückgängig" #. Translators: Description, notification #: iotas/index.py:249 msgid "Sync conflict with note being edited" msgstr "Sync-Konflikt mit Notiz, die bearbeitet wird" #. Translators: Description, notification #: iotas/index.py:256 msgid "The note being edited was remotely deleted" msgstr "Die bearbeitete Notiz wurde von anderer Stelle gelöscht" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:264 msgid "Failure accessing Secret Service. Ensure you have a provider like gnome-keyring which has a default keyring setup that is unlocked." msgstr "Zugriff auf »Secret Service« fehlgeschlagen. Stellen Sie sicher, dass Sie über einen Anbieter wie den GNOME-Schlüsselbund verfügen, der standardmäßig eine entsperrte Schlüsselbund-Einstellung hat." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:498 msgid "Syncing" msgstr "Synchronisierung läuft" #. Translators: Description, notification, {} is a number #: iotas/index.py:517 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} Änderung" msgstr[1] "{} Änderungen" #. Translators: Description, notification #: iotas/index.py:533 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Synchronisierung fehlgeschlagen. Ist die Nextcloud-Notes-App auf dem Server installiert?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:630 msgid "Loading" msgstr "Wird geladen" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Verweis einfügen" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Verweis bearbeiten" #. Translators: Title #: iotas/nextcloud_login_dialog.py:108 msgid "Updating Notes" msgstr "Notizen werden aktualisiert" #. Translators: Title #: iotas/nextcloud_login_dialog.py:112 msgid "Performing Initial Transfer" msgstr "Erstmalige Übermittlung wird durchgeführt" #. Translators: Title #: iotas/nextcloud_login_dialog.py:168 msgid "Connecting" msgstr "Verbindung wird hergestellt" #. Translators: Title #: iotas/nextcloud_login_dialog.py:190 msgid "Waiting for Login" msgstr "Warten auf Anmeldung" #. Translators: Description #: iotas/nextcloud_login_dialog.py:192 msgid "Complete the authentication in your browser" msgstr "Die Legitimierung in Ihrem Browser abschließen" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:208 msgid "Failed to start login with possible certificate issue" msgstr "Anmeldung konnte nicht begonnen werden mit möglichem Zertifikatsproblem" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:211 msgid "Failed to start login. Wrong address?" msgstr "Anmeldung konnte nicht begonnen werden. Falsche Adresse?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:65 iotas/preferences_dialog.py:97 msgid "Monochrome" msgstr "Monochrom" #. Translators: Description, a style name #: iotas/preferences_dialog.py:67 msgid "Muted Markup" msgstr "Gedämpftes Markup" #. Translators: Description, a style name #: iotas/preferences_dialog.py:69 msgid "Bold Markup" msgstr "Kräftiges Markup" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:124 msgid "Disabled" msgstr "Deaktiviert" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:99 msgid "Muted" msgstr "Gedämpft" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:101 msgid "Blue" msgstr "Blau" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:103 msgid "Orange" msgstr "Orange" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Red" msgstr "Rot" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "None" msgstr "Keiner" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:118 iotas/preferences_dialog.py:138 msgid "Always Visible" msgstr "Immer sichtbar" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:120 iotas/preferences_dialog.py:140 msgid "Automatically Hide" msgstr "Automatisch verbergen" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:122 iotas/preferences_dialog.py:142 msgid "Auto Hide When Fullscreen" msgstr "Im Vollbildmodus automatisch ausblenden" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:273 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Verringern in {0} Drücken" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:276 #, python-brace-format msgid "Extending in {0} presses" msgstr "Erweitern in {0} Drücken" #. Translators: Description, notification #: iotas/preferences_dialog.py:281 msgid "Extended hidden" msgstr "Ausgeklappte verborgen" #. Translators: Description, notification #: iotas/preferences_dialog.py:284 msgid "Extended shown" msgstr "Ausgeklappte angezeigt" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:313 msgid "Hiding discouraged on mobile" msgstr "Ausblenden auf Mobilgeräten nicht empfohlen" #. Translators: Title #: iotas/preferences_dialog.py:333 msgid "Reset Database?" msgstr "Datenbank zurücksetzen?" #. Translators: Description #: iotas/preferences_dialog.py:335 msgid "All notes will be deleted. Continue with the reset?" msgstr "Alle Notizen werden gelöscht. Mit dem Zurücksetzen fortfahren?" #. Translators: Title #: iotas/preferences_dialog.py:354 msgid "Disconnect Nextcloud?" msgstr "Von der Nextcloud trennen?" #. Translators: Description #: iotas/preferences_dialog.py:356 msgid "All notes will be removed. Do you want to sign out?" msgstr "Alle Notizen werden entfernt. Wollen Sie sich abmelden?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Die Kategorie einer schreibgeschützten Notiz kann nicht geändert werden" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} ausgewählt" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:506 msgid "SYNC CONFLICT" msgstr "SYNC-KONFLIKT" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Fehler" #~ msgid "OK" #~ msgstr "OK" #~ msgid "Bold Markup (High Contrast)" #~ msgstr "Kräftiges Markup (Hoher Kontrast)" #~ msgid "Muted Markup (High Contrast)" #~ msgstr "Gedämpftes Markup (Hoher Kontrast)" #~ msgid "Monochrome (High Contrast)" #~ msgstr "Monochrom (Hoher Kontrast)" #~ msgid "Disabled (High Contrast)" #~ msgstr "Deaktiviert (Hoher Kontrast)" #~ msgid "Disable" #~ msgstr "Deaktivieren" #~ msgid "Return to Index" #~ msgstr "Zurück zum Index" #~ msgid "Line length limit already disabled" #~ msgstr "Zeilenlängenbegrenzung bereits deaktiviert" #~ msgid "Font size now {0}pt" #~ msgstr "Schriftgröße jetzt {0}pt" #~ msgid "Read-Only Note" #~ msgstr "Schreibgeschützte Notiz" #~ msgid "Waiting for completion of login in browser" #~ msgstr "Warten, bis die Anmeldung im Browser abgeschlossen ist" #~ msgid "Syntax Theme" #~ msgstr "Syntax-Thema" #~ msgid "Finish" #~ msgstr "Fertigstellen" #~ msgid "Auto Hide" #~ msgstr "Automatisch ausblenden" #~ msgid "Why \"Iotas\"? An iota is a little bit and this app is designed for jotting down little things on little devices. Iota stems from the same Greek word as jot and is commonly used in negative statements eg. \"not one iota of …\", but we think the word has more to give. Maybe somebody will take note?" #~ msgstr "Warum »Iotas«? Ein Jota ist ein kleines bisschen, und diese App ist dafür gedacht, Kleinigkeiten auf kleinen Geräten zu notieren. Jota stammt vom griechischen »Jod« ab und wird gemeinhin in negativen Aussagen verwendet, zum Beispiel »nicht ein Jota von …«, aber wir denken, das Wort hat mehr zu bieten. Vielleicht nimmt ja jemand Notiz davon?" #~ msgid "Let's get started" #~ msgstr "Es kann losgehen" #~ msgid "Add new feeds via URL" #~ msgstr "Neue Feeds über Adresse hinzufügen" #~ msgid "Import an OPML file" #~ msgstr "Eine OPML-Datei importieren" #~ msgid "Go back" #~ msgstr "Zurück gehen" #~ msgid "Highlight Syntax" #~ msgstr "Syntax hervorheben" #~ msgid "Disable for slightly improved performance." #~ msgstr "Deaktivieren für leicht verbesserte Leistung." #~ msgid "Editor with plain text" #~ msgstr "Editor mit Reintext" #~ msgid "1 change" #~ msgstr "1 Änderung" #~ msgid "notes;nextcloud;base;" #~ msgstr "notes;nextcloud;base;Notizen;Nextcloud;" #~ msgid "Iotas is a simple note taking app with mobile-first design and a focus on sync with Nextcloud Notes." #~ msgstr "Iotas ist eine einfache, in erster Linie für Mobilgeräte gedachte Notiz-App mit Fokus auf Nextcloud-Notes-Synchronisierung." #~ msgid "Although simple by design there are a few features" #~ msgstr "Obwohl bewusst einfach gehalten, gibt es doch ein paar Funktionen" #~ msgid "Basic search" #~ msgstr "Grundlegende Suche" #~ msgid "Please quit the running instance of Iotas before creating the backup" #~ msgstr "Bitte beenden Sie die laufende Instanz von Iotas vor dem Erstellen der Datensicherung" #~ msgid "Please quit the running instance of Iotas before restoring the backup" #~ msgstr "Bitte beenden Sie die laufende Instanz von Iotas vor dem Wiederherstellen der Datensicherung" #~ msgid "No running instance found" #~ msgstr "Keine laufende Instanz gefunden" #~ msgid "Hiding extended preferences" #~ msgstr "Erweiterte Einstellungen werden verborgen" #~ msgid "Showing extended preferences" #~ msgstr "Erweiterte Einstellungen werden angezeigt" #~ msgid "Failed to create backup directory at {0}: {1}" #~ msgstr "Verzeichnis der Datensicherung konnte nicht erstellt werden bei {0}: {1}" #~ msgid "Failed to move previous backup to archive path" #~ msgstr "Vorherige Datensicherung konnte nicht in den Archivpfad verschoben werden" #~ msgid "Backup created at {}" #~ msgstr "Datensicherung erstellt auf {}" #~ msgid "Backup restoration isn't possible with Nextcloud Notes sync configured" #~ msgstr "Wiederherstellen der Datensicherung ist nicht möglich mit eingerichtetem Nextcloud Notes Sync" #~ msgid "Backup failed" #~ msgstr "Datensicherung fehlgeschlagen" #~ msgid "No backup exists at {}" #~ msgstr "Es existiert keine Datensicherung bei {}" #~ msgid "Backup restoration can only be run when there are no existing notes" #~ msgstr "Wiederherstellen der gesicherten Daten kann nur ausgeführt werden ohne bereits vorhandene Notizen" #~ msgid "Backup restoration failed" #~ msgstr "Wiederherstellen der Datensicherung fehlgeschlagen" #~ msgid "Backup restoration completed" #~ msgstr "Wiederherstellen der Datensicherung abgeschlossen" #~ msgid "Failed to write metadata to {0}: {1}" #~ msgstr "Metadaten konnten nicht nach {0} geschrieben werden: {1}" #~ msgid "Creating {}" #~ msgstr "{} wird erstellt" #~ msgid "Skipping restoration of existing identical note \"{}\"" #~ msgstr "Wiederherstellen der vorhandenen identischen Notiz »{}« wird übersprungen" #~ msgid "Duplicating note \"{}\" due to matching remote id" #~ msgstr "Notiz »{}« wird dupliziert wegen übereinstimmender entfernter Kennung" #~ msgid "Updating metadata for note \"{}\"" #~ msgstr "Metadaten für Notiz »{}« werden aktualisiert" #~ msgid "Skipping note \"{}\" with matching title, contents and a newer timestamp" #~ msgstr "Notiz »{}« mit übereinstimmendem Titel, Inhalt und neuerem Zeitstempel wird übersprungen" #~ msgid "Duplicating note \"{}\" due to matching title but different content" #~ msgstr "Notiz »{}« wird dupliziert wegen übereinstimmenden Titels, aber unterschiedlichen Inhalts" #~ msgid "Failed to remove backup archive directory at {0}: {1}" #~ msgstr "Verzeichnis des Datensicherungsarchivs konnte nicht entfernt werden bei {0}: {1}" #~ msgid "Failed to create backup archive directory at {0}: {1}" #~ msgstr "Verzeichnis des Datensicherungsarchivs konnte nicht erstellt werden bei {0}: {1}" #~ msgid "Failed to move {0} into {1}: {2}" #~ msgstr "Verschieben von {0} nach {1} fehlgeschlagen: {2}" #~ msgid "Skipping \"{}\" due to missing content" #~ msgstr "»{}« wird übersprungen wegen fehlenden Inhalts" #~ msgid "Bailing \"{0}\" due to exceeding {1}MB" #~ msgstr "Abbruch von »{0}«, da {1}MB überschritten werden" #~ msgid "Failed to read note content from {0}: {1}" #~ msgstr "Lesen von Notiz-Inhalt von {0} fehlgeschlagen: {1}" #~ msgid "Failed to read note metadata from {0}: {1}" #~ msgstr "Lesen von Notiz-Metadaten von {0} fehlgeschlagen: {1}" #~ msgid "Failed to parse note metadata from \"{}\"" #~ msgstr "Auswerten von Notiz-Metadaten von »{}« fehlgeschlagen" #~ msgid "Theme used by editor view" #~ msgstr "Thema, das von der Editor-Ansicht verwendet wird" #~ msgid "The GtkSourceView style scheme id" #~ msgstr "Die GtkSourceView-Stil-Schema-Kennung" #~ msgid "First start" #~ msgstr "Erster Start" #~ msgid "Whether starting for the first time." #~ msgstr "Ob zum ersten Mal gestartet wird." #~ msgid "Font size" #~ msgstr "Schriftgröße" #~ msgid "Font used in main editor view." #~ msgstr "Schrift, die in der Hauptansicht des Editors verwendet wird." #~ msgid "Line length used in both the editor and markdown render views (pixels)." #~ msgstr "Zeilenlänge (in Pixeln), die sowohl in der Editor- als auch der Markdown-Vorschau-Ansicht verwendet wird." #~ msgid "Whether to use a monospace font" #~ msgstr "Ob eine nichtproportionale Schrift verwendet wird" #~ msgid "The specific fonts are sourced from GNOME's monospace and document font settings" #~ msgstr "Die spezifischen Schriften stammen von den GNOME-Einstellungen für Nichtproportional- und Dokumentenschriften" #~ msgid "Markdown render view support" #~ msgstr "Unterstützung für Markdown-Vorschau-Ansicht" #~ msgid "Whether to support showing markdown render view (a temporary performance concession for a WebKit issue)" #~ msgstr "Ob die Anzeige der Markdown-Vorschau-Ansicht unterstützt wird (ein vorübergehendes Leistungszugeständnis für ein WebKit-Problem)" #~ msgid "Markdown syntax highlighting" #~ msgstr "Markdown-Syntaxhervorhebung" #~ msgid "Whether to highlight markdown syntax." #~ msgstr "Ob die Markdown-Syntax hervorgehoben wird." #~ msgid "Markdown WebKit process retention." #~ msgstr "WebKit-Prozess für Markdown wird aufrechterhalten." #~ msgid "When enabled the WebKit process is retained between uses of the render view, decreasing load time and increasing memory usage." #~ msgstr "Wenn aktiviert, wird der WebKit-Prozess zwischen den Verwendungen der Vorschau-Ansicht aufrechterhalten. Dies verkürzt die Ladezeit und erhöht die Speichernutzung." #~ msgid "Markdown TeX support for maths equations." #~ msgstr "Markdown-TeX-Unterstützung für mathematische Gleichungen." #~ msgid "Whether to support rendering maths equations. Slightly increases markdown render time." #~ msgstr "Ob die Vorschau für mathematische Gleichungen unterstützt wird. Verlängert etwas das Berechnen der Markdown-Vorschau." #~ msgid "Markdown monospace font." #~ msgstr "Nichtproportionale Markdown-Schrift." #~ msgid "Whether to use a monospace font for the markdown render." #~ msgstr "Ob eine nichtproportionale Schrift für die Markdown-Vorschau verwendet wird." #~ msgid "Markdown default to render." #~ msgstr "Markdown standardmäßig als Vorschau." #~ msgid "Whether to show the render view when opening the note." #~ msgstr "Ob die Vorschau-Ansicht angezeigt wird beim Öffnen der Notiz." #~ msgid "Ratio adjusting proportional to monospace font in markdown render" #~ msgstr "Verhältnisanpassung von proportionaler zu nichtproportionale Schrift in der Markdown-Vorschau" #~ msgid "A value of 1 will result in no adjustment." #~ msgstr "Bei einem Wert von 1 erfolgt keine Anpassung." #~ msgid "Nextcloud server to sync against" #~ msgstr "Nextcloud-Server, mit dem Synchronisierung erfolgt" #~ msgid "Path to the last Nextcloud sync instance." #~ msgstr "Pfad zur letzten Nextcloud-Sync-Instanz." #~ msgid "Username for the Nextcloud sync server" #~ msgstr "Benutzername für den Nextcloud-Sync-Server" #~ msgid "Login to use with the Nextcloud sync instance." #~ msgstr "Anmeldedaten, die für die Nextcloud-Sync-Instanz verwendet werden." #~ msgid "Prune threshold for Nextcloud sync" #~ msgstr "Grenzwert für den Nextcloud-Sync senken" #~ msgid "Used to reduce the number of records pulled from the Nextcloud server during sync." #~ msgstr "Wird verwendet, um die Anzahl der Datensätze zu reduzieren, die vom Nextcloud-Server während des Synchronisierens heruntergeladen werden." #~ msgid "Whether to show a message on Secret Service failure" #~ msgstr "Ob eine Nachricht angezeigt wird, wenn »Secret Service« fehlgeschlagen ist" #~ msgid "Disabling this provides for a cleaner startup if never intending to use Nextcloud Notes sync. on a device without a Secret Service provider." #~ msgstr "Sollten Sie niemals vorhaben, Nextcloud-Notes-Sync auf einem Gerät ohne »Secret-Service«-Anbieter zu verwenden, führt es zu einem saubereren Startvorgang, wenn Sie dies deaktivieren." #~ msgid "Whether to show a notification when syncing from the server" #~ msgstr "Ob eine Benachrichtigung angezeigt wird beim Synchronisieren vom Server" #~ msgid "Useful for increasing visibility of network issues" #~ msgstr "Nützlich für bessere Sichtbarkeit von Netzwerkproblemen" #~ msgid "Spelling enabled" #~ msgstr "Rechtschreibprüfung aktiviert" #~ msgid "Whether spell checking is enabled." #~ msgstr "Ob die Rechtschreibprüfung aktiviert ist." #~ msgid "Spelling language" #~ msgstr "Zu prüfende Sprache" #~ msgid "Language tag to attempt to use by default for spelling." #~ msgstr "Sprach-Kennung, die standardmäßig für die Rechtschreibung verwendet wird." #~ msgid "Colour scheme style" #~ msgstr "Farbschema-Stil" #~ msgid "Choosing to follow desktop colour style or enforce dark or light visuals." #~ msgstr "Dem Desktop-Farbschema folgen oder helle oder dunkle Ansicht erzwingen." #~ msgid "Sync interval" #~ msgstr "Sync-Intervall" #~ msgid "Interval between pulling from the Nextcloud sync server (seconds)." #~ msgstr "Intervall (in Sekunden) zwischen den Abrufen vom Nextcloud-Sync-Server." #~ msgid "Window size" #~ msgstr "Fenstergröße" #~ msgid "Remember the window size." #~ msgstr "Die Fenstergröße merken." #~ msgid "Whether to persist the index sidebar in large windows" #~ msgstr "Ob die Index-Seitenleiste in großen Fenstern bestehen bleibt" #~ msgid "Whether to the index sidebar is permanently present in large windows (generally desktop)" #~ msgstr "Ob die Index-Seitenleiste dauerhaft vorhanden ist in großen Fenstern (normalerweise Desktop)" #~ msgid "Whether to automatically hide the editor headerbar" #~ msgstr "Ob die Kopfleiste des Editors automatisch ausgeblendet wird" #~ msgid "Setting to true automatically hides the editor headerbar" #~ msgstr "Wenn auf »wahr« gesetzt, wird die Kopfleiste des Editors automatisch ausgeblendet" #~ msgid "Whether to hide the editor headerbar when fullscreen" #~ msgstr "Ob die Kopfleiste des Editors im Vollbildmodus ausgeblendet wird" #~ msgid "Setting to true automatically hides the editor headerbar entering fullscreen mode" #~ msgstr "Wenn auf »wahr« gesetzt, blendet sich die Kopfleiste des Editors im Vollbildmodus automatisch aus" #~ msgid "File extension for backed up notes" #~ msgstr "Dateiendung für gesicherte Notizen" #~ msgid "File extension added to each note when exporting for backup." #~ msgstr "Dateiendung, die zu jeder Notiz hinzugefügt wird beim Exportieren für eine Sicherung." #~ msgid "Index category style" #~ msgstr "Stil der Index-Kategorie" #~ msgid "Style options for category labels on index rows" #~ msgstr "Stiloptionen für Kategorie-Schlagwörter in Index-Zeilen" #~ msgid "Last launched version" #~ msgstr "Zuletzt gestartete Version" #~ msgid "The last version of the app that was run. Shouldn't be edited." #~ msgstr "Die letzte Version der Anwendung, die ausgeführt wurde. Sollte nicht bearbeitet werden." #~ msgid "Directory last used for export" #~ msgstr "Zuletzt für den Export benutztes Verzeichnis" #~ msgid "Only applies to instances with filesystem access. Shouldn't be edited." #~ msgstr "Gilt nur für Instanzen mit Zugriff auf das Dateisystem. Sollte nicht bearbeitet werden." #~ msgid "Extra pandoc formats for exporting" #~ msgstr "Zusätzliche Pandoc-Formate fürs Exportieren" #~ msgid "See README for definition" #~ msgstr "Siehe README für Definition" #~ msgid "Perform full server refresh" #~ msgstr "Vollständige Server-Aktualisierung durchführen" #~ msgid "Whether to run a full update of all notes from the server. Used for eg. schema migrations." #~ msgstr "Ob eine vollständige Aktualisierung aller Notizen vom Server ausgeführt wird. Wird z.B. für Schema-Migrationen verwendet." #~ msgid "Whether to show extended preferences" #~ msgstr "Ob erweiterte Einstellungen angezeigt werden" #~ msgid "When enabled an excessive number of preferences are shown." #~ msgstr "Wenn aktiviert, wird eine große Anzahl von Einstellungen angezeigt." #~ msgid "Searching" #~ msgstr "Suche" #~ msgid "Sync. with Nextcloud Notes" #~ msgstr "Mit Nextcloud Notes synchronisieren" #~ msgid "Index on mobile" #~ msgstr "Index auf Mobilgerät" #~ msgid "Index on desktop" #~ msgstr "Index auf Desktop-Gerät" #~ msgid "Limited functionality on mobile for now." #~ msgstr "Derzeit eingeschränkte Funktionalität auf Mobilgeräten." #~ msgid "Note: It's fairly early days in development here, so please expect a few rough edges." #~ msgstr "Hinweis: Die Entwicklung hier steht noch ziemlich am Anfang, als rechnen Sie bitte mit ein paar Kinderkrankheiten." #~ msgid "Optional markdown syntax highlighting and rendered view" #~ msgstr "Optionale Markdown-Syntax-Hervorhebung und -Vorschau" #~ msgid "Follow system-wide dark style preference or make own choice" #~ msgstr "Der Einstellung für systemweiten dunklen Stil folgen oder selbst entscheiden" #~ msgid "Mobile editor" #~ msgstr "Mobilgeräte-Editor" #~ msgid "Desktop index" #~ msgstr "Desktop-Index" #~ msgid "Desktop index dark style" #~ msgstr "Desktop-Index im dunklen Stil" #~ msgid "Sync. offline" #~ msgstr "Sync ist offline" #~ msgid "Add Favorite" #~ msgstr "Favorit hinzufügen" #~ msgid "Remove Favorite" #~ msgstr "Favorit entfernen" #~ msgid "All" #~ msgstr "Alle" #~ msgid "Current obvious feature omissions" #~ msgstr "Derzeit offensichtliche fehlende Funktionen" #~ msgid "Load the Rest" #~ msgstr "Den Rest laden" #~ msgid "The Rest" #~ msgstr "Der Rest" #~ msgid "Sync" #~ msgstr "Sync" #~ msgid "Temporary Debug Functions" #~ msgstr "Temporäre Funktionen zur Fehlersuche" #~ msgid "@NAME@" #~ msgstr "@NAME@" #~ msgid "Initial release." #~ msgstr "Erste Freigabe." #~ msgid "Chris Heywood" #~ msgstr "Chris Heywood" #~ msgid "Learn more about Iotas" #~ msgstr "Erfahren Sie mehr über Iotas" #~ msgid "Rest" #~ msgstr "Rest" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/en_GB.po000066400000000000000000001653731507102636600223510ustar00rootroot00000000000000# British English translation for iotas. # Copyright (C) 2023 the author(s) of iotas. # This file is distributed under the same license as iotas. # Chris Heywood , 2023-2025. # Bruce Cowan , 2025. # msgid "" msgstr "" "Project-Id-Version: iotas\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-19 05:31+0000\n" "PO-Revision-Date: 2025-09-25 10:23+0100\n" "Last-Translator: Bruce Cowan \n" "Language-Team: British English \n" "Language: en_GB\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 49.0\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Simple note taking with Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "New Note" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Simple note taking" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Featuring" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Optional speedy sync with Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Offline note editing, syncing when back online" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Category editing and filtering" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Favourites" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Spell checking" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Search within the collection or individual notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Focus mode and optional hiding of the editor header and formatting bars" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "In preview: export to PDF, ODT and HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "A convergent design, seeing Iotas as at home on desktop as mobile" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Search from GNOME Shell" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "Note backup and restoration (from CLI, for using without sync)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "The ability to change font size and toggle monospace style" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Writing in markdown is supported but optional, providing" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formatting via toolbar and shortcuts" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Syntax highlighting with themes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "A formatted view" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "The ability to check off task lists from the formatted view" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Slightly more technical details, for those into that type of thing" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "There's basic sync conflict detection" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Notes are constantly saved" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "Large note collections are partially loaded to quicken startup" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Index" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editor with markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Rendered markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Index in dark style" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobile" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "" "Chris Heywood \n" "Bruce Cowan " #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Revert Changes" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Apply Changes" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Apply" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Clear and Apply" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Find" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Back" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_dialog.ui:289 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Previous Match" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_dialog.ui:282 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Next Match" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Replace" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Focus Mode" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Find and Replace…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Jump To…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Edit Title…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Change Category…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Delete" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Export…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Back to Notes" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Note is Read-Only" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Editor Menu" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Toggle Markdown Render" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Edit Note" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Render Engine Loading" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 #: iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "Cancel" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Export As…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "Downloading…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Exporting…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Close" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Show" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "One or more attachments failed to transfer." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Retry" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "Export Anyway" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Welcome to Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Use the header bar above to…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Add a Note" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Sync with Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Zoom Out" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Zoom In" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Horizontal Rule" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Quote" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Code" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Table" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Level 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Level 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Level 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Level 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Remove" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Heading" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Bold" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Italic" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Strikethrough" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Unordered List" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Ordered List" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Checkbox" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Link" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Refresh" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Preferences" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Keyboard Shortcuts" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "About Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Main Menu" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Today" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Yesterday" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "This Week" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "This Month" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Last Month" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Show Earlier Months" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Before Last Month" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Show More" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Open Categories" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 #: data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Search" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Select Notes" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Server connection offline" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Due to behind-the-scenes changes (a new app id) Iotas needs to re-" "authenticate with your Nextcloud server" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Authenticate" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "The authentication token for sync with Nextcloud Notes could not be retrieved" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Dismiss" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Note List Empty" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Enter Search Term" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "No Search Results" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Create New Note" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Show Sidebar" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Delete Note" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Move Up List" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Move Down List" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Start Selection" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "Open First Search Result" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "Reset Filter" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Edit Title" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Change Category" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Export" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Jump to Section" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Create New Note Including Selection" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Undo Typing" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Redo Typing" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Insert Emoji" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Focus Text View" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Focus Header Bar" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Focus Formatting Bar" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Formatting" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Toggle Tickbox" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Editor Search" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Editor Appearance" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Increase Line Length" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Decrease Line Length" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Increase Font Size" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Decrease Font Size" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "General" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Toggle Fullscreen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Show Preferences" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Show Shortcuts" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Open Previous Note" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Go Back" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Quit" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Text" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud Notes Setup" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Continue" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Continue to URL Entry" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Secret Service Inaccessible" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Server URL" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Start Login" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Self-Signed Certificate" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Open the FAQ" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Connection Established" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Done" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Complete Sync Setup" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Outline" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "No headings matching filter" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "No headings found for outline" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Interface" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Use Monospace Font" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Check Spelling" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Change language via the editor context menu" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Header Bar" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Limit Line Length" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Detect Syntax" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Theme" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Formatting Bar" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Enable Formatted View" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Disable to reduce startup time" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Open In Formatted View" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Enabling opens all notes as rendered markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Support Maths Equations" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Slightly decreases render performance" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Render Using Monospace Font" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Proportional To Monospace Font Size Ratio" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "In render view. Use 1 for no adjustment." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Hold Engine In Memory" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Faster subsequent conversions for higher memory usage" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Pin Sidebar" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "On desktop, when there is space" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Category Label Style" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Data" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Connect Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Establish sync with Nextcloud Notes" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Log In" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Disconnect Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Disconnect" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Reset Database" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "Delete all notes from the local database. The app will quit." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Reset" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Debug" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Clear Sync Timestamp" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Forces a pull of all notes from the sync server" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Clear" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Delete Selected" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Toggle Favourite for Selected" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Change Category for Selected" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Close Categories" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Categories" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Insert Table" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Create" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Follow System Style" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Light Style" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Dark Style" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Create a note" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Create a backup" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Restore a backup" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Display backup path" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "Display path for custom server SSL CA chain file" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "Toggle display of extended preferences in UI" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Quit any running instance" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Enable debug logging and functions" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Open note by id" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Search in notes" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "RESTORATION REMOTE ID CLASH" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "RESTORATION TITLE CLASH" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "All Notes" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Uncategorised" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "Line length now {0}px" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Line length limit disabled" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Opening link in browser" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} of {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "Exported to {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "Failed to export to {}" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Transfer Failed" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} notes deleted" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Note deleted" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Undo" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Sync conflict with note being edited" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "The note being edited was remotely deleted" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Syncing" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} change" msgstr[1] "{} changes" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Sync failure. Is the Nextcloud Notes app installed on the server?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Loading" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Insert Link" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Edit Link" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Updating Notes" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "Performing Initial Transfer" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "Connecting" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "Waiting for Login" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Complete the authentication in your browser" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "Failed to start login with possible certificate issue" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Failed to start login. Wrong address?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Monochrome" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Muted Markup" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Bold Markup" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Disabled" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Muted" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Blue" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Orange" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Red" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "None" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Always Visible" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Automatically Hide" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Auto Hide When Fullscreen" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Reducing in {0} presses" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "Extending in {0} presses" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Extended hidden" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Extended shown" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "Hiding discouraged on mobile" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Reset Database?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "All notes will be deleted. Continue with the reset?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Disconnect Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "All notes will be removed. Do you want to sign out?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Unable to change category on read-only note" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} Selected" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "SYNC CONFLICT" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Error" #~ msgid "Exporting..." #~ msgstr "Exporting..." #~ msgid "Bold Markup (High Contrast)" #~ msgstr "Bold Markup (High Contrast)" #~ msgid "Muted Markup (High Contrast)" #~ msgstr "Muted Markup (High Contrast)" #~ msgid "Monochrome (High Contrast)" #~ msgstr "Monochrome (High Contrast)" #~ msgid "Disabled (High Contrast)" #~ msgstr "Disabled (High Contrast)" #~ msgid "Disable" #~ msgstr "Disable" #~ msgid "OK" #~ msgstr "OK" #~ msgid "Line length limit already disabled" #~ msgstr "Line length limit already disabled" #, python-brace-format #~ msgid "Font size now {0}pt" #~ msgstr "Font size now {0}pt" #~ msgid "Return to Index" #~ msgstr "Return to Index" #~ msgid "Read-Only Note" #~ msgstr "Read-Only Note" #~ msgid "Waiting for completion of login in browser" #~ msgstr "Waiting for completion of login in browser" #~ msgid "Syntax Theme" #~ msgstr "Syntax Theme" #~ msgid "Finish" #~ msgstr "Finish" #~ msgid "Auto Hide" #~ msgstr "Auto Hide" #~ msgid "" #~ "Why \"Iotas\"? An iota is a little bit and this app is designed for " #~ "jotting down little things on little devices. Iota stems from the same " #~ "Greek word as jot and is commonly used in negative statements eg. \"not " #~ "one iota of …\", but we think the word has more to give. Maybe somebody " #~ "will take note?" #~ msgstr "" #~ "Why \"Iotas\"? An iota is a little bit and this app is designed for " #~ "jotting down little things on little devices. Iota stems from the same " #~ "Greek word as jot and is commonly used in negative statements eg. \"not " #~ "one iota of …\", but we think the word has more to give. Maybe somebody " #~ "will take note?" #~ msgid "Go back" #~ msgstr "Go back" #~ msgid "Highlight Syntax" #~ msgstr "Highlight Syntax" #~ msgid "Disable for slightly improved performance." #~ msgstr "Disable for slightly improved performance." #~ msgid "Editor with plain text" #~ msgstr "Editor with plain text" #~ msgid "1 change" #~ msgstr "1 change" #~ msgid "notes;nextcloud;base;" #~ msgstr "notes;nextcloud;base;" #~ msgid "" #~ "Iotas is a simple note taking app with mobile-first design and a focus on " #~ "sync with Nextcloud Notes." #~ msgstr "" #~ "Iotas is a simple note taking app with mobile-first design and a focus on " #~ "sync with Nextcloud Notes." #~ msgid "Although simple by design there are a few features" #~ msgstr "Although simple by design there are a few features" #~ msgid "Basic search" #~ msgstr "Basic search" #~ msgid "Please quit the running instance of Iotas before creating the backup" #~ msgstr "" #~ "Please quit the running instance of Iotas before creating the backup" #~ msgid "" #~ "Please quit the running instance of Iotas before restoring the backup" #~ msgstr "" #~ "Please quit the running instance of Iotas before restoring the backup" #~ msgid "No running instance found" #~ msgstr "No running instance found" #~ msgid "Hiding extended preferences" #~ msgstr "Hiding extended preferences" #~ msgid "Showing extended preferences" #~ msgstr "Showing extended preferences" #, python-brace-format #~ msgid "Failed to create backup directory at {0}: {1}" #~ msgstr "Failed to create backup directory at {0}: {1}" #~ msgid "Failed to move previous backup to archive path" #~ msgstr "Failed to move previous backup to archive path" #~ msgid "Backup created at {}" #~ msgstr "Backup created at {}" #~ msgid "" #~ "Backup restoration isn't possible with Nextcloud Notes sync configured" #~ msgstr "" #~ "Backup restoration isn't possible with Nextcloud Notes sync configured" #~ msgid "Backup failed" #~ msgstr "Backup failed" #~ msgid "No backup exists at {}" #~ msgstr "No backup exists at {}" #~ msgid "Backup restoration can only be run when there are no existing notes" #~ msgstr "Backup restoration can only be run when there are no existing notes" #~ msgid "Backup restoration failed" #~ msgstr "Backup restoration failed" #~ msgid "Backup restoration completed" #~ msgstr "Backup restoration completed" #, python-brace-format #~ msgid "Failed to write metadata to {0}: {1}" #~ msgstr "Failed to write metadata to {0}: {1}" #~ msgid "Creating {}" #~ msgstr "Creating {}" #~ msgid "Skipping restoration of existing identical note \"{}\"" #~ msgstr "Skipping restoration of existing identical note \"{}\"" #~ msgid "Duplicating note \"{}\" due to matching remote id" #~ msgstr "Duplicating note \"{}\" due to matching remote id" #~ msgid "Updating metadata for note \"{}\"" #~ msgstr "Updating metadata for note \"{}\"" #~ msgid "" #~ "Skipping note \"{}\" with matching title, contents and a newer timestamp" #~ msgstr "" #~ "Skipping note \"{}\" with matching title, contents and a newer timestamp" #~ msgid "Duplicating note \"{}\" due to matching title but different content" #~ msgstr "Duplicating note \"{}\" due to matching title but different content" #, python-brace-format #~ msgid "Failed to remove backup archive directory at {0}: {1}" #~ msgstr "Failed to remove backup archive directory at {0}: {1}" #, python-brace-format #~ msgid "Failed to create backup archive directory at {0}: {1}" #~ msgstr "Failed to create backup archive directory at {0}: {1}" #, python-brace-format #~ msgid "Failed to move {0} into {1}: {2}" #~ msgstr "Failed to move {0} into {1}: {2}" #~ msgid "Skipping \"{}\" due to missing content" #~ msgstr "Skipping \"{}\" due to missing content" #, python-brace-format #~ msgid "Bailing \"{0}\" due to exceeding {1}MB" #~ msgstr "Bailing \"{0}\" due to exceeding {1}MB" #, python-brace-format #~ msgid "Failed to read note content from {0}: {1}" #~ msgstr "Failed to read note content from {0}: {1}" #, python-brace-format #~ msgid "Failed to read note metadata from {0}: {1}" #~ msgstr "Failed to read note metadata from {0}: {1}" #~ msgid "Failed to parse note metadata from \"{}\"" #~ msgstr "Failed to parse note metadata from \"{}\"" #~ msgid "Theme used by editor view" #~ msgstr "Theme used by editor view" #~ msgid "The GtkSourceView style scheme id" #~ msgstr "The GtkSourceView style scheme id" #~ msgid "First start" #~ msgstr "First start" #~ msgid "Whether starting for the first time." #~ msgstr "Whether starting for the first time." #~ msgid "Font size" #~ msgstr "Font size" #~ msgid "Font used in main editor view." #~ msgstr "Font used in main editor view." #~ msgid "" #~ "Line length used in both the editor and markdown render views (pixels)." #~ msgstr "" #~ "Line length used in both the editor and markdown render views (pixels)." #~ msgid "Whether to use a monospace font" #~ msgstr "Whether to use a monospace font" #~ msgid "" #~ "The specific fonts are sourced from GNOME's monospace and document font " #~ "settings" #~ msgstr "" #~ "The specific fonts are sourced from GNOME's monospace and document font " #~ "settings" #~ msgid "Markdown render view support" #~ msgstr "Markdown render view support" #~ msgid "" #~ "Whether to support showing markdown render view (a temporary performance " #~ "concession for a WebKit issue)" #~ msgstr "" #~ "Whether to support showing markdown render view (a temporary performance " #~ "concession for a WebKit issue)" #~ msgid "Markdown syntax highlighting" #~ msgstr "Markdown syntax highlighting" #~ msgid "Whether to highlight markdown syntax." #~ msgstr "Whether to highlight markdown syntax." #~ msgid "Markdown WebKit process retention." #~ msgstr "Markdown WebKit process retention." #~ msgid "" #~ "When enabled the WebKit process is retained between uses of the render " #~ "view, decreasing load time and increasing memory usage." #~ msgstr "" #~ "When enabled the WebKit process is retained between uses of the render " #~ "view, decreasing load time and increasing memory usage." #~ msgid "Markdown TeX support for maths equations." #~ msgstr "Markdown TeX support for maths equations." #~ msgid "" #~ "Whether to support rendering maths equations. Slightly increases markdown " #~ "render time." #~ msgstr "" #~ "Whether to support rendering maths equations. Slightly increases markdown " #~ "render time." #~ msgid "Markdown monospace font." #~ msgstr "Markdown monospace font." #~ msgid "Whether to use a monospace font for the markdown render." #~ msgstr "Whether to use a monospace font for the markdown render." #~ msgid "Markdown default to render." #~ msgstr "Markdown default to render." #~ msgid "Whether to show the render view when opening the note." #~ msgstr "Whether to show the render view when opening the note." #~ msgid "Ratio adjusting proportional to monospace font in markdown render" #~ msgstr "Ratio adjusting proportional to monospace font in markdown render" #~ msgid "A value of 1 will result in no adjustment." #~ msgstr "A value of 1 will result in no adjustment." #~ msgid "Nextcloud server to sync against" #~ msgstr "Nextcloud server to sync against" #~ msgid "Path to the last Nextcloud sync instance." #~ msgstr "Path to the last Nextcloud sync instance." #~ msgid "Username for the Nextcloud sync server" #~ msgstr "Username for the Nextcloud sync server" #~ msgid "Login to use with the Nextcloud sync instance." #~ msgstr "Login to use with the Nextcloud sync instance." #~ msgid "Prune threshold for Nextcloud sync" #~ msgstr "Prune threshold for Nextcloud sync" #~ msgid "" #~ "Used to reduce the number of records pulled from the Nextcloud server " #~ "during sync." #~ msgstr "" #~ "Used to reduce the number of records pulled from the Nextcloud server " #~ "during sync." #~ msgid "Whether to show a message on Secret Service failure" #~ msgstr "Whether to show a message on Secret Service failure" #~ msgid "" #~ "Disabling this provides for a cleaner startup if never intending to use " #~ "Nextcloud Notes sync. on a device without a Secret Service provider." #~ msgstr "" #~ "Disabling this provides for a cleaner startup if never intending to use " #~ "Nextcloud Notes sync. on a device without a Secret Service provider." #~ msgid "Whether to show a notification when syncing from the server" #~ msgstr "Whether to show a notification when syncing from the server" #~ msgid "Useful for increasing visibility of network issues" #~ msgstr "Useful for increasing visibility of network issues" #~ msgid "Spelling enabled" #~ msgstr "Spelling enabled" #~ msgid "Whether spell checking is enabled." #~ msgstr "Whether spell checking is enabled." #~ msgid "Spelling language" #~ msgstr "Spelling language" #~ msgid "Language tag to attempt to use by default for spelling." #~ msgstr "Language tag to attempt to use by default for spelling." #~ msgid "Colour scheme style" #~ msgstr "Colour scheme style" #~ msgid "" #~ "Choosing to follow desktop colour style or enforce dark or light visuals." #~ msgstr "" #~ "Choosing to follow desktop colour style or enforce dark or light visuals." #~ msgid "Sync interval" #~ msgstr "Sync interval" #~ msgid "Interval between pulling from the Nextcloud sync server (seconds)." #~ msgstr "Interval between pulling from the Nextcloud sync server (seconds)." #~ msgid "Window size" #~ msgstr "Window size" #~ msgid "Remember the window size." #~ msgstr "Remember the window size." #~ msgid "Whether to persist the index sidebar in large windows" #~ msgstr "Whether to persist the index sidebar in large windows" #~ msgid "" #~ "Whether to the index sidebar is permanently present in large windows " #~ "(generally desktop)" #~ msgstr "" #~ "Whether to the index sidebar is permanently present in large windows " #~ "(generally desktop)" #~ msgid "Whether to automatically hide the editor headerbar" #~ msgstr "Whether to automatically hide the editor headerbar" #~ msgid "Setting to true automatically hides the editor headerbar" #~ msgstr "Setting to true automatically hides the editor headerbar" #~ msgid "Whether to hide the editor headerbar when fullscreen" #~ msgstr "Whether to hide the editor headerbar when fullscreen" #~ msgid "" #~ "Setting to true automatically hides the editor headerbar entering " #~ "fullscreen mode" #~ msgstr "" #~ "Setting to true automatically hides the editor headerbar entering " #~ "fullscreen mode" #~ msgid "File extension for backed up notes" #~ msgstr "File extension for backed up notes" #~ msgid "File extension added to each note when exporting for backup." #~ msgstr "File extension added to each note when exporting for backup." #~ msgid "Index category style" #~ msgstr "Index category style" #~ msgid "Style options for category labels on index rows" #~ msgstr "Style options for category labels on index rows" #~ msgid "Last launched version" #~ msgstr "Last launched version" #~ msgid "The last version of the app that was run. Shouldn't be edited." #~ msgstr "The last version of the app that was run. Shouldn't be edited." #~ msgid "Directory last used for export" #~ msgstr "Directory last used for export" #~ msgid "" #~ "Only applies to instances with filesystem access. Shouldn't be edited." #~ msgstr "" #~ "Only applies to instances with filesystem access. Shouldn't be edited." #~ msgid "Extra pandoc formats for exporting" #~ msgstr "Extra pandoc formats for exporting" #~ msgid "See README for definition" #~ msgstr "See README for definition" #~ msgid "Perform full server refresh" #~ msgstr "Perform full server refresh" #~ msgid "" #~ "Whether to run a full update of all notes from the server. Used for eg. " #~ "schema migrations." #~ msgstr "" #~ "Whether to run a full update of all notes from the server. Used for eg. " #~ "schema migrations." #~ msgid "Whether to show extended preferences" #~ msgstr "Whether to show extended preferences" #~ msgid "When enabled an excessive number of preferences are shown." #~ msgstr "When enabled an excessive number of preferences are shown." #~ msgid "Searching" #~ msgstr "Searching" #~ msgid "Sync. with Nextcloud Notes" #~ msgstr "Sync. with Nextcloud Notes" #~ msgid "Index on mobile" #~ msgstr "Index on mobile" #~ msgid "Index on desktop" #~ msgstr "Index on desktop" #~| msgid "A formatted view" #~ msgid "Formatted View Mode" #~ msgstr "Formatted View Mode" #~ msgid "Open In View Mode" #~ msgstr "Open In View Mode" #~ msgid "Keep Sidebar Open" #~ msgstr "Keep Sidebar Open" #~ msgid "View By Default" #~ msgstr "View By Default" #~ msgid "Limited functionality on mobile for now." #~ msgstr "Limited functionality on mobile for now." #~ msgid "" #~ "Task list items checked off in the rendered view are updated in the note " #~ "(and to the server)" #~ msgstr "" #~ "Task list items checked off in the rendered view are updated in the note " #~ "(and to the server)" #~ msgid "" #~ "Note: It's fairly early days in development here, so please expect a few " #~ "rough edges." #~ msgstr "" #~ "Note: It's fairly early days in development here, so please expect a few " #~ "rough edges." #~ msgid "Optional markdown syntax highlighting and rendered view" #~ msgstr "Optional markdown syntax highlighting and rendered view" #~ msgid "Follow system-wide dark style preference or make own choice" #~ msgstr "Follow system-wide dark style preference or make own choice" #~ msgid "Mobile editor" #~ msgstr "Mobile editor" #~ msgid "Desktop index" #~ msgstr "Desktop index" #~ msgid "Desktop index dark style" #~ msgstr "Desktop index dark style" #~ msgid "Sync. offline" #~ msgstr "Sync. offline" #~ msgid "Add Favorite" #~ msgstr "Add Favourite" #~ msgid "Remove Favorite" #~ msgstr "Remove Favourite" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/es.po000066400000000000000000001036021507102636600217710ustar00rootroot00000000000000# Spanish translations for iotas package. # Copyright (C) 2022 THE iotas'S COPYRIGHT HOLDER # This file is distributed under the same license as the iotas package. # Óscar Fernández Díaz , 2022-2024. # msgid "" msgstr "" "Project-Id-Version: iotas\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-03-25 18:32+1100\n" "PO-Revision-Date: 2024-03-26 09:56+0100\n" "Last-Translator: Óscar Fernández Díaz \n" "Language-Team: Spanish; Castilian\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" "X-Generator: Gtranslator 46.0\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:4 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:6 msgid "Simple note taking with Nextcloud Notes" msgstr "Toma de notas sencilla con Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:14 msgid "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;" "document;" msgstr "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;" "document;notas;distracción;concentración;texto;escribir;documento;" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Toma de notas sencilla" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas pretende ofrecer la posibilidad de tomar notas sin distracciones " "gracias a su diseño orientado al móvil." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Destacando" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Sincronización rápida opcional con Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "" "Edición de notas sin conexión, sincronización cuando se vuelve a conectar" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Edición y filtrado de categorías" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Favoritos" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Comprobación ortográfica" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Búsqueda dentro de la colección o en notas individuales" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and an option to hide the editor header bar" msgstr "" "Modo de concentración y una opción para ocultar la barra de cabecera del " "editor" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "En vista previa: exportar a PDF, ODT y HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Un diseño convergente, viendo a Iotas como en casa, tanto en el escritorio " "como en el móvil." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Buscar desde GNOME Shell" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Copia de seguridad y restauración de notas (desde CLI, para usar sin " "sincronización)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Posibilidad de cambiar el tamaño de letra y el estilo monoespaciado" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Escribir en markdown es compatible pero opcional, proporcionando" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Syntax highlighting with themes" msgstr "Resaltado de sintaxis con temas" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "A formatted view" msgstr "Una vista formateada" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "The ability to check off task lists from the formatted view" msgstr "Posibilidad de marcar listas de tareas desde la vista formateada." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:92 msgid "Slightly more technical details, for those into that type of thing" msgstr "" "Detalles un poco más técnicos, para los interesados en ese tipo de cosas" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:95 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "La sincronización de Nextcloud Notes se realiza a través de la API REST, no " "de WebDAV, lo que la hace más rápida." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "There's basic sync conflict detection" msgstr "Hay una detección básica de conflictos de sincronización" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "Notes are constantly saved" msgstr "Las notas se guardan constantemente" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Las grandes colecciones de notas se cargan parcialmente para acelerar el " "arranque" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Las notas se almacenan en SQLite, lo que permite una búsqueda rápida (FTS) " "sin reinventar la rueda. Los archivos sin formato pueden recuperarse " "haciendo una copia de seguridad (CLI)." #. Translators: Part of metainfo description. "Iotas" is the application name, do not translate. Left to your discretion whether it makes sense to translate "iota" or not. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:106 msgid "" "Why \"Iotas\"? An iota is a little bit and this app is designed for jotting " "down little things on little devices. Iota stems from the same Greek word as " "jot and is commonly used in negative statements eg. \"not one iota of …\", " "but we think the word has more to give. Maybe somebody will take note?" msgstr "" "¿Por qué \"Iotas\"? Una iota es un poco y esta aplicación está diseñada para " "anotar pequeñas cosas en pequeños dispositivos. Iota proviene de la misma " "palabra griega que jot y se utiliza habitualmente en declaraciones " "negativas, por ejemplo, \"ni una pizca de...\", pero creemos que la palabra " "tiene más que dar. ¿Tal vez alguien tome nota?" #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:15 msgid "Index" msgstr "Índice" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editor con markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Markdown renderizado" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Editor with plain text" msgstr "Editor con texto plano" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Index in dark style" msgstr "Índice en estilo oscuro" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:137 msgid "Mobile" msgstr "Móvil" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Óscar Fernández Díaz " #. Translators: Button #: data/ui/category_header_bar.ui:11 data/ui/editor_rename_header_bar.ui:13 msgid "Revert changes" msgstr "Revertir cambios" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:38 data/ui/editor_rename_header_bar.ui:36 msgid "Apply changes" msgstr "Aplicar cambios" #. Translators: Button #: data/ui/category_header_bar.ui:40 data/ui/editor_rename_header_bar.ui:38 msgid "Apply" msgstr "Aplicar" #. Translators: Button #: data/ui/category_header_bar.ui:54 msgid "Clear and apply" msgstr "Limpiar y aplicar" #. Translators: Button #: data/ui/editor_search_header_bar.ui:12 data/ui/index_search_header_bar.ui:11 #: data/ui/render_search_header_bar.ui:11 data/ui/selection_header_bar.ui:16 msgid "Back" msgstr "Atrás" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:39 #: data/ui/keyboard_shortcuts_window.ui:183 #: data/ui/render_search_header_bar.ui:32 msgid "Previous match" msgstr "Coincidencia anterior" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:47 #: data/ui/keyboard_shortcuts_window.ui:176 #: data/ui/render_search_header_bar.ui:40 msgid "Next match" msgstr "Coincidencia siguiente" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:77 #: data/ui/keyboard_shortcuts_window.ui:169 msgid "Replace" msgstr "Reemplazar" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:196 msgid "Focus mode" msgstr "Modo de concentración" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find" msgstr "Buscar" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:32 data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit title" msgstr "Editar título" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:37 data/ui/keyboard_shortcuts_window.ui:93 #: data/ui/keyboard_shortcuts_window.ui:114 #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Change category" msgstr "Cambiar categoría" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Delete" msgstr "Eliminar" #. Translators: Menu item #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/editor.ui:49 data/ui/keyboard_shortcuts_window.ui:100 #: iotas/export_dialog.py:119 msgid "Export" msgstr "Exportar" #. Translators: Button #: data/ui/editor.ui:65 msgid "Back to notes" msgstr "Volver a las notas" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:109 data/ui/keyboard_shortcuts_window.ui:128 msgid "Toggle markdown render" msgstr "Conmutar la representación de markdown" #. Translators: Button #: data/ui/editor.ui:117 msgid "Edit note" msgstr "Editar nota" #. Translators: Description #: data/ui/editor.ui:143 msgid "Read-only note" msgstr "Nota de solo lectura" #. Translators: Description, help #: data/ui/editor.ui:211 msgid "Render engine loading" msgstr "Cargando el motor de renderizado" #. Translators: Title #: data/ui/empty_state.ui:11 msgid "Let's get started" msgstr "Comencemos" #. Translators: Description, help #: data/ui/empty_state.ui:43 msgid "Add new feeds via URL" msgstr "Añadir fuentes nuevas a través de la URL" #. Translators: Description, help #: data/ui/empty_state.ui:54 msgid "Import an OPML file" msgstr "Importar un archivo OPML" #. Translators: Button #: data/ui/export_dialog.ui:21 data/ui/nextcloud_login_dialog.ui:21 msgid "Cancel" msgstr "Cancelar" #. Translators: Title #: data/ui/export_dialog.ui:29 msgid "Export As..." msgstr "Exportar como..." #. Translators: Title #: data/ui/export_dialog.ui:49 msgid "Exporting..." msgstr "Exportando..." #. Translators: Button #: data/ui/export_dialog.ui:68 data/ui/export_dialog.ui:95 #: iotas/ui_utils.py:112 msgid "Close" msgstr "Cerrar" #. Translators: Button #: data/ui/export_dialog.ui:75 msgid "Show" msgstr "Mostrar" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Le damos la bienvenida a Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:29 msgid "Add a note" msgstr "Añadir una nota" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:49 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Sincronizar con Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom out" msgstr "Alejar" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom in" msgstr "Acercar" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Actualizar" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Preferencias" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Atajos del teclado" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Acerca de Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Menu" msgstr "Menú" #. Translators: Section title #: data/ui/index_note_list.ui:58 msgid "Today" msgstr "Hoy" #. Translators: Section title #: data/ui/index_note_list.ui:90 msgid "Yesterday" msgstr "Ayer" #. Translators: Section title #: data/ui/index_note_list.ui:122 msgid "This Week" msgstr "Esta semana" #. Translators: Section title #: data/ui/index_note_list.ui:154 msgid "This Month" msgstr "Este mes" #. Translators: Section title #: data/ui/index_note_list.ui:186 msgid "Last Month" msgstr "Último mes" #. Translators: Button #: data/ui/index_note_list.ui:217 msgid "Show earlier months" msgstr "Mostrar meses anteriores" #. Translators: Section title #: data/ui/index_note_list.ui:235 msgid "Before Last Month" msgstr "Antes del mes pasado" #. Translators: Button #: data/ui/index_note_list.ui:267 msgid "Show more" msgstr "Mostrar más" #: data/ui/index.ui:20 msgid "Categories" msgstr "Categorías" #. Translators: Button #: data/ui/index.ui:41 msgid "Open categories" msgstr "Abrir categorías" #. Translators: Button #: data/ui/index.ui:49 msgid "New note" msgstr "Nota nueva" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:68 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:162 msgid "Search" msgstr "Buscar" #. Translators: Button #: data/ui/index.ui:76 msgid "Select notes" msgstr "Seleccionar notas" #. Translators: Description #: data/ui/index.ui:94 msgid "Server connection offline" msgstr "Conexión al servidor desconectada" #. Translators: Description #: data/ui/index.ui:100 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Debido a los cambios entre bastidores (un nuevo id de aplicación) Iotas " "necesita volver a autenticarse con su servidor Nextcloud" #. Translators: Button #: data/ui/index.ui:102 data/ui/index.ui:111 msgid "Authenticate" msgstr "Autenticar" #. Translators: Description #: data/ui/index.ui:109 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "No se ha podido recuperar el testigo de autenticación para la sincronización " "con Nextcloud Notes." #. Translators: Description, help #: data/ui/index.ui:134 msgid "Note list empty" msgstr "Lista de notas vacía" #. Translators: Description, help #: data/ui/index.ui:141 msgid "Enter search term" msgstr "Introduzca el término de búsqueda" #. Translators: Description, help #: data/ui/index.ui:148 msgid "No search results" msgstr "No hay resultados de búsqueda" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create new note" msgstr "Crear nota nueva" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show sidebar" msgstr "Mostrar barra lateral" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete note" msgstr "Eliminar nota" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move up list" msgstr "Desplazar hacia arriba en la lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move down list" msgstr "Desplazar hacia abajo en la lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start selection" msgstr "Iniciar selección" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset filter" msgstr "Restablecer filtro" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open first search result" msgstr "Abrir el primer resultado de búsqueda" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:37 msgid "Editor" msgstr "Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Create new note including selection" msgstr "Crear nota nueva con selección incluida" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Undo typing" msgstr "Deshacer" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Redo typing" msgstr "Rehacer" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Return to Index" msgstr "Volver al índice" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:157 msgid "Editor Search" msgstr "Búsqueda del editor" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:191 msgid "Editor Appearance" msgstr "Apariencia del editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:203 msgid "Increase line length" msgstr "Aumentar la longitud de la línea" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:210 msgid "Decrease line length" msgstr "Reducir la longitud de la línea" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:217 msgid "Increase font size" msgstr "Aumentar el tamaño de la tipografía" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:224 msgid "Decrease font size" msgstr "Disminuir el tamaño de letra" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:232 msgid "General" msgstr "General" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:237 msgid "Toggle fullscreen" msgstr "Conmutar pantalla completa" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:244 msgid "Show preferences" msgstr "Mostrar preferencias" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:251 msgid "Show shortcuts" msgstr "Mostrar atajos" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:258 msgid "Go back" msgstr "Volver" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:265 msgid "Quit" msgstr "Salir" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:30 msgid "Continue" msgstr "Continuar" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:67 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Pulse Continuar para proporcionar la dirección de su servidor Nextcloud e " "iniciar sesión a través de un navegador web" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:95 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "No se ha podido acceder al servicio secreto para almacenar los datos de " "autenticación. Asegúrese de tener un proveedor como gnome-keyring. Es " "necesario configurar un llavero predeterminado y desbloquearlo. La mayoría " "de los entornos de escritorio le proporcionarán esto. Reinicie la aplicación " "para volver a intentarlo." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:116 msgid "Nextcloud Server URL" msgstr "URL del servidor Nextcloud" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:157 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Parece que está usando un certificado SSL autofirmado, por lo que no se " "verifica la identidad del servidor. Si esto es lo que espera, siga las " "instrucciones de las FAQ para proporcionar un archivo de cadena CA." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:163 msgid "Open the FAQ" msgstr "Abrir las FAQ" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:187 msgid "Waiting for completion of login in browser" msgstr "Esperando a que se complete el inicio de sesión en el navegador" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:194 msgid "Performing initial transfer" msgstr "Realizando transferencia inicial" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:201 msgid "Updating notes" msgstr "Actualizando notas" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:234 msgid "Connection established with Nextcloud Notes" msgstr "Conexión establecida con Nextcloud Notes" #. Translators: Title #: data/ui/preferences_dialog.ui:11 msgid "Interface" msgstr "Interfaz" #. Translators: Title #: data/ui/preferences_dialog.ui:19 msgid "Automatically Expand Sidebar" msgstr "Expandir automáticamente la barra lateral" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:21 msgid "On desktop, when there is space." msgstr "En el escritorio, cuando hay espacio." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:29 msgid "Category Label Style" msgstr "Estilo de la etiqueta de categoría" #. Translators: Title #: data/ui/preferences_dialog.ui:41 msgid "Use Monospace Font" msgstr "Usar tipografía monoespaciada" #. Translators: Title #: data/ui/preferences_dialog.ui:48 msgid "Check Spelling" msgstr "Revisar ortografía" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Hide Headerbar" msgstr "Ocultar barra de encabezado" #. Translators: Title #: data/ui/preferences_dialog.ui:62 msgid "Hide Headerbar When Fullscreen" msgstr "Ocultar la barra de cabecera en pantalla completa" #. Translators: Title #: data/ui/preferences_dialog.ui:71 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:75 msgid "Highlight Syntax" msgstr "Resaltar sintaxis" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:77 msgid "Disable for slightly improved performance." msgstr "Desactivar para mejorar ligeramente el rendimiento." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:84 msgid "Syntax Theme" msgstr "Tema de la sintaxis" #. Translators: Title #: data/ui/preferences_dialog.ui:90 msgid "Enable Formatted View" msgstr "Activar vista con formato" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:92 msgid "Disable to reduce startup time." msgstr "Desactivar para reducir el tiempo de arranque." #. Translators: Title #: data/ui/preferences_dialog.ui:99 msgid "Open In Formatted View" msgstr "Abrir en vista con formato" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:101 msgid "Enabling opens all notes as rendered markdown." msgstr "Al activar esta opción, todas las notas se abren en formato markdown." #. Translators: Title #: data/ui/preferences_dialog.ui:108 msgid "Support Math Equations" msgstr "Soporte de ecuaciones matemáticas" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:110 msgid "Slightly decreases render performance." msgstr "Disminuye ligeramente el rendimiento de la representación." #. Translators: Title #: data/ui/preferences_dialog.ui:117 msgid "Render Using Monospace Font" msgstr "Representación con tipografía monoespaciada" #. Translators: Title #: data/ui/preferences_dialog.ui:124 msgid "Proportional To Monospace Font Size Ratio" msgstr "Proporcional a la relación de tamaño de la tipografía monoespaciada" #: data/ui/preferences_dialog.ui:125 msgid "In render view. Use 1 for no adjustment." msgstr "En la vista de representación. Use 1 para no ajustar." #. Translators: Title #: data/ui/preferences_dialog.ui:141 msgid "Hold Engine In Memory" msgstr "Mantener el motor en la memoria" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:143 msgid "Faster subsequent conversions for higher memory usage." msgstr "Conversiones posteriores más rápidas para un mayor uso de la memoria." #. Translators: Title #: data/ui/preferences_dialog.ui:156 msgid "Data" msgstr "Datos" #. Translators: Title #: data/ui/preferences_dialog.ui:162 msgid "Reset Database" msgstr "Restablecer base de datos" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:164 msgid "Delete all notes from the local database. The app will quit." msgstr "" "Eliminar todas las notas de la base de datos local. La aplicación se cerrará." #. Translators: Title #: data/ui/preferences_dialog.ui:182 msgid "Disconnect Nextcloud" msgstr "Desconectar Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:184 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Cerrar la sesión de Nextcloud Notes. Todas las notas se eliminarán y la " "aplicación se cerrará." #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Debug" msgstr "Depuración" #. Translators: Title #: data/ui/preferences_dialog.ui:214 msgid "Clear Sync Timestamp" msgstr "Borrar marca de tiempo de sincronización" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:216 msgid "Forces a pull of all notes from the sync server." msgstr "Fuerza la obtención de todas las notas del servidor de sincronización." #. Translators: Button #: data/ui/selection_header_bar.ui:32 msgid "Delete selected" msgstr "Eliminar seleccionada" #. Translators: Button #: data/ui/selection_header_bar.ui:43 msgid "Toggle favorite for selected" msgstr "Conmutar favorito para la selección" #. Translators: Button #: data/ui/selection_header_bar.ui:51 msgid "Change category for selected" msgstr "Cambiar categoría de la selección" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close categories" msgstr "Close categories" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:26 data/ui/theme_selector.ui:29 msgid "Follow system style" msgstr "Seguir el estilo del sistema" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:45 data/ui/theme_selector.ui:48 msgid "Light style" msgstr "Estilo claro" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:64 data/ui/theme_selector.ui:67 msgid "Dark style" msgstr "Estilo oscuro" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:185 msgid "RESTORATION REMOTE ID CLASH" msgstr "RESTAURACIÓN CONFLICTO ID REMOTO" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:203 msgid "RESTORATION TITLE CLASH" msgstr "RESTAURACIÓN CONFLICTO TÍTULO" #. Translators: Title #: iotas/category.py:19 msgid "All notes" msgstr "Todas las notas" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Sin categoría" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:726 #, python-brace-format msgid "Line length now {0}px" msgstr "Longitud de línea ahora {0}px" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:732 #, python-brace-format msgid "Font size now {0}pt" msgstr "Tamaño de tipografía ahora {0}pt" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} de {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:91 msgid "Exported to {}" msgstr "Exportado a {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:104 msgid "Failed to export to {}" msgstr "Error al exportar a {}" #. Translators: Description, notification #: iotas/index.py:89 iotas/index.py:797 msgid "Loading" msgstr "Cargando" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:182 msgid "{} notes deleted" msgstr "{} notas eliminadas" #. Translators: Description, notification #: iotas/index.py:185 msgid "Note deleted" msgstr "Nota eliminada" #. Translators: Button #: iotas/index.py:190 msgid "Undo" msgstr "Deshacer" #. Translators: Description, notification #: iotas/index.py:230 msgid "Sync conflict with note being edited" msgstr "Conflicto de sincronización con la nota que se está editando" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" #. should likely not be translated. #: iotas/index.py:240 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Fallo en el acceso al servicio secreto. Asegúrese de que tiene un proveedor " "como gnome-keyring que tiene una configuración de llavero predeterminada que " "esté desbloqueada." #. Translators: Button #: iotas/index.py:246 msgid "OK" msgstr "Vale" #. Translators: Description, notification #: iotas/index.py:490 msgid "Syncing" msgstr "Sincronizando" #. Translators: Description, notification #: iotas/index.py:501 msgid "1 change" msgstr "1 cambio" #. Translators: Description, notification, {} is a number larger than 1 #: iotas/index.py:504 msgid "{} changes" msgstr "{} cambios" #. Translators: Button #: iotas/nextcloud_login_dialog.py:123 msgid "Finish" msgstr "Finalizar" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login. Wrong address?" msgstr "No se ha podido iniciar la sesión. ¿Dirección incorrecta?" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:78 msgid "Monochrome" msgstr "Monocromático" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:80 msgid "Muted" msgstr "Tenue" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:82 msgid "Blue" msgstr "Azul" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:84 msgid "Orange" msgstr "Naranja" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:86 msgid "Red" msgstr "Rojo" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:88 msgid "None" msgstr "Ninguno" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:213 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Reduciendo en {0} pulsaciones" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:216 #, python-brace-format msgid "Extending in {0} presses" msgstr "Extendiendo en {0} pulsaciones" #. Translators: Description, notification #: iotas/preferences_dialog.py:221 msgid "Extended hidden" msgstr "Ampliado oculto" #. Translators: Description, notification #: iotas/preferences_dialog.py:224 msgid "Extended shown" msgstr "Ampliado mostrado" #. Translators: Description, alert #: iotas/selection_header_bar.py:86 iotas/selection_header_bar.py:182 msgid "Unable to change category on read-only note" msgstr "No se puede cambiar la categoría de una nota de solo lectura" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:165 msgid "{} Selected" msgstr "{} seleccionadas" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:452 msgid "SYNC CONFLICT" msgstr "CONFLICTO DE SINCRONIZACIÓN" #. Translators: Title #: iotas/ui_utils.py:110 msgid "Error" msgstr "Error" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/eu.po000066400000000000000000001275331507102636600220040ustar00rootroot00000000000000# Basque translation for Iotas. # Copyright (C) 2025 Iotas's COPYRIGHT HOLDER # This file is distributed under the same license as the Iotas package. # Asier Saratsua Garmendia , 2025. # msgid "" msgstr "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/-/issues\n" "POT-Creation-Date: 2025-03-22 06:41+0000\n" "PO-Revision-Date: 2025-034-13 06:41+0000\n" "Last-Translator: Asier Saratsua Garmendia \n" "Language-Team: Basque \n" "Language: eu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:4 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:6 msgid "Simple note taking with Nextcloud Notes" msgstr "Oharrak hartzeko aplikazio sinplea, Nextcloud-en oharrak darabilena" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:14 msgid "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;" "document;gnome;gtk;" msgstr "oharrak;nextcloud;sinplea;distrakzioa;editorea;fokuratua;testua;idatzi;markdown;dokumentua;gnome;gtk;" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Ohar sinpleak" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "Iotas aplikazioak oharrak distrakziorik gabe hartzea ahalbidetzen du, mugikorretarako pentsatutako diseinu baten bidez." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Eginbideak" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Aukerako sinkronizazio azkarra Nexcloud Notes aplikazioarekin" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Lineaz kanpoko oharrak hartzea, sinkronizazioa linean jartzean" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Kategoriak editatzea eta iragaztea" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Gogokoak" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Ortografia-egiaztapena" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Bilaketak bildumetan edo banakako oharretan" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "Fokuratze-modua eta editorearen goiburuaren eta formatu-barren aukerako ezkutatzea" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "Aurrebistan: esportatu PDF, ODT eta HTMLra" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "Diseinu konbergentea, Iotas mahaigainean zein mugikorrean erabiltzeko" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Bilatu GNOME Shell aplikaziotik" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "Oharren babeskopia eta leheneratzea (komando-lerrotik, sinkronizaziorik gabe erabiltzeko)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Letra-tamaina aldatu eta espazio bakarreko estilora aldatzeko aukera" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Markdown formatuan idaztea onartzen da, baina aukerakoa da" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formatua ematea tresna-barren eta lasterbideen bidez" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Sintaxia nabarmentzea gaiekin" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Formatudun ikuspegia" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Zeregin-zerrendak egintzat markatzeko aukera formatudun ikuspegian" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Xehetasun teknikoagoak, horrelakoak gustuko dituztenentzat" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "Nextcloud Notes aplikazioarekin sinkronizatzea REST API bidez egiten da, ez WebDAV bidez, azkarragoa izan dadin" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Sinkronizazio-gatazken oinarrizko detekzioa dago" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Oharrak etengabe gordetzen dira" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "Ohar-bilduma handiak partzialki kargatzen dira abioa azkartzeko" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "Oharrak SQLite datu-base batean biltegiratzen dira, bilaketa azkarrak (FTS) egin ahal izateko gurpila berrasmatu gabe. Fitxategi soilak atzitu daitezke babeskopiak egiteko (komando-lerro bidez)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Indizea" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editorea markdown-arekin" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Errendatutako markdown-a" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Indizea estilo ilunean" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mugikorra" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Asier Saratsua Garmendia " #. Translators: Button #: data/ui/category_header_bar.ui:14 data/ui/editor_rename_header_bar.ui:16 msgid "Revert Changes" msgstr "Mantendu aldaketak" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:41 data/ui/editor_rename_header_bar.ui:39 msgid "Apply Changes" msgstr "Aplikatu aldaketak" #. Translators: Button #: data/ui/category_header_bar.ui:43 data/ui/editor_rename_header_bar.ui:41 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Aplikatu" #. Translators: Button #: data/ui/category_header_bar.ui:57 msgid "Clear and Apply" msgstr "Garbitu eta aplikatu" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Aurkitu" #. Translators: Button #: data/ui/editor_search_header_bar.ui:15 data/ui/index_search_header_bar.ui:11 #: data/ui/render_search_header_bar.ui:14 data/ui/selection_header_bar.ui:16 msgid "Back" msgstr "Atzera" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:42 #: data/ui/keyboard_shortcuts_window.ui:287 #: data/ui/render_search_header_bar.ui:35 msgid "Previous Match" msgstr "Aurreko parekatzea" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:50 #: data/ui/keyboard_shortcuts_window.ui:280 #: data/ui/render_search_header_bar.ui:43 msgid "Next Match" msgstr "Hurrengo parekatzea" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:72 #: data/ui/editor_search_header_bar.ui:81 #: data/ui/keyboard_shortcuts_window.ui:273 msgid "Replace" msgstr "Ordeztu" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:300 msgid "Focus Mode" msgstr "Fokuratze-modua" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Bilatu eta ordeztu…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Joan hona…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Editatu izenburua…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Aldatu kategoria…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Ezabatu" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Esportatu…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Itzuli oharretara" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Oharra irakurtzeko soilik da" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Editore-menua" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle Markdown Render" msgstr "Aktibatu/desaktibatu markdown errendatzailea" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Editatu oharra" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Errendatze-motorra kargatzen" #. Translators: Button #: data/ui/export_dialog.ui:21 iotas/preferences_dialog.py:337 #: iotas/preferences_dialog.py:358 msgid "Cancel" msgstr "Utzi" #. Translators: Title #: data/ui/export_dialog.ui:29 msgid "Export As..." msgstr "Esportatu honela…" #. Translators: Title #: data/ui/export_dialog.ui:49 msgid "Exporting..." msgstr "Esportatzen…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:68 data/ui/export_dialog.ui:95 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Itxi" #. Translators: Button #: data/ui/export_dialog.ui:75 msgid "Show" msgstr "Erakutsi" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Ongi etorri Iotas aplikaziora" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Erabili goiburu-barra honetarako…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Gehitu oharra" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Sinkronizatu Nextcloud Notes aplikazioarekin" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Txikiagotu" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Handiagotu" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:157 #: data/ui/keyboard_shortcuts_window.ui:239 msgid "Horizontal Rule" msgstr "Erregela horizontala" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:166 #: data/ui/keyboard_shortcuts_window.ui:246 msgid "Quote" msgstr "Komatxoa" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:175 #: data/ui/keyboard_shortcuts_window.ui:225 msgid "Code" msgstr "Kodea" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:184 #: data/ui/keyboard_shortcuts_window.ui:253 msgid "Table" msgstr "Taula" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "1. maila" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "2. maila" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "3. maila" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "4. maila" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Kendu" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:80 data/ui/keyboard_shortcuts_window.ui:183 msgid "Heading" msgstr "Izenburua" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:89 data/ui/keyboard_shortcuts_window.ui:169 msgid "Bold" msgstr "Lodia" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:98 data/ui/keyboard_shortcuts_window.ui:176 msgid "Italic" msgstr "Etzana" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:107 #: data/ui/keyboard_shortcuts_window.ui:232 msgid "Strikethrough" msgstr "Marratua" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:116 #: data/ui/keyboard_shortcuts_window.ui:190 msgid "Unordered List" msgstr "Ordenatu gabeko zerrenda" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:125 #: data/ui/keyboard_shortcuts_window.ui:197 msgid "Ordered List" msgstr "Zerrenda ordenatua" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:134 #: data/ui/keyboard_shortcuts_window.ui:204 msgid "Checkbox" msgstr "Kontrol-laukia" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:143 #: data/ui/keyboard_shortcuts_window.ui:218 msgid "Link" msgstr "Esteka" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Freskatu" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Hobespenak" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Laster-teklak" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Iotas aplikazioari buruz" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Menu nagusia" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Gaur" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Atzo" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Aste hau" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Hilabete hau" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Aurreko hilabetea" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Erakutsi aurreko hilabeteak" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Aurreko hilabetearen aurretik" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Erakutsi gehiago" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Ireki kategoriak" #. Translators: Button #: data/ui/index.ui:42 msgid "New Note" msgstr "Ohar berria" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:266 msgid "Search" msgstr "Bilatu" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Hautatu oharrak" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Zerbitzari-konexioa lineaz kanpo dago" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "Barneko aldaketen ondorioz (aplikazioak ID berria du) Iotas-ek berriro autentifikatu behar du Nextcloud zerbitzarian" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Autentifikatu" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "Nextcloud Notes aplikazioarekin sinkronizatzeko autentifikazio-tokena ezin da atzitu" #. Translators: Button #: data/ui/index.ui:111 msgid "OK" msgstr "Ados" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Oharren zerrenda hutsik dago" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Sartu bilaketa-terminoa" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Bilaketak ez du emaitzarik" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create New Note" msgstr "Sortu ohar berria" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show Sidebar" msgstr "Erakutsi alboko barra" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete Note" msgstr "Ezabatu oharra" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move Up List" msgstr "Eraman gora zerrendan" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move Down List" msgstr "Eraman behera zerrendan" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start Selection" msgstr "Hasi hautapena" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset Filter" msgstr "Berrezarri iragazkia" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open First Search Result" msgstr "Ireke bilaketaren lehen emaitza" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Editorea" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit Title" msgstr "Editatu izenburua" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_window.ui:93 iotas/export_dialog.py:129 msgid "Export" msgstr "Esportatu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create New Note Including Selection" msgstr "Sortu ohar berria hautapena barne" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Change Category" msgstr "Aldatu kategoria" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo Typing" msgstr "Desegin idaztea" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo Typing" msgstr "Berregin idaztea" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Insert Emoji" msgstr "Txertatu emojia" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Focus Text View" msgstr "Fokuratu testu-ikuspegia" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Focus Header Bar" msgstr "Fokuratu goiburu-barra" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:156 msgid "Focus Formatting Bar" msgstr "Fokuratu formatu-barra" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:164 msgid "Formatting" msgstr "Formateatzea" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:211 msgid "Toggle Checkbox" msgstr "Txandakatu kontrol-laukia" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:261 msgid "Editor Search" msgstr "Editorearen bilaketa" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:295 msgid "Editor Appearance" msgstr "Editorearen itxura" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:307 msgid "Increase Line Length" msgstr "Handitu lerro-luzera" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:314 msgid "Decrease Line Length" msgstr "Txikitu lerro-luzera" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:321 msgid "Increase Font Size" msgstr "Handitu letra-tamaina" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:328 msgid "Decrease Font Size" msgstr "Txikitu letra-tamaina" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:336 msgid "General" msgstr "Orokorra" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:341 msgid "Toggle Fullscreen" msgstr "Ikusi pantaila osoan" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:348 msgid "Show Preferences" msgstr "Erakutsi hobespenak" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:355 msgid "Show Shortcuts" msgstr "Erakutsi lasterbideak" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:362 msgid "Open Previous Note" msgstr "Ireki aurreko oharra" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:369 msgid "Go Back" msgstr "Joan atzera" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:376 msgid "Quit" msgstr "Irten" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URLa" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Testua" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud Notes konfigurazioa" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "Sakatu 'Jarraitu' aukera zure Nextcloud zerbitzariaren helbidea eta saio-hasiera emateko web-nabigatzaile baten bidez" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Jarraitu" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Jarraitu URL sarrerara" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Zerbitzu sekretua ez dago eskuragarri" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "Ezin izan da zerbitzu sekretua atzitu autentifikazio-xehetasunak biltegiratzeko. Ziurtatu gnome-keyring edo horrelako hornitzaile bat duzula. Gako sorta lehenetsi bat konfiguratu behar da, eta desblokeatuta egon behar du. Mahaigaineko ingurune askok horrelako bat dute. Berrabiarazi aplikazioa berriro saiatzeko." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Zerbitzariaren URLa" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Abiarazi saio-hasiera" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Ziurtagiri autosinatua" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "SSL ziurtagiri autosinatua erabiltzen ari zarela dirudi, eta zerbitzariaren identitatea ezin da egiaztatu. Hori espero bazenuen, jarraitu ohiko galderetan dauden argibideak ZE kate-fitxategi bat emateko." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Ireki ohiko galderak" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Konexioa ezarri da" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Eginda" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Osatu sinkronizazio-konfigurazioa" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Eskema" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Ez dago iragazkiarekin bat datorren izenbururik" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Ez da izenbururik aurkitu eskemarako" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Interfazea" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Erabili tarte bakarreko letra-tipoa" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Egiaztatu ortografia" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Aldatu hizkuntza editorearen laster-menuaren bidez" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Goiburu-barra" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Mugatu lerro-luzera" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "Batez ere mahaiganerako. Erabili teklatuko Ctrl + ↑ eta Ctrl + ↓ hobeto doitzeko." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown-a" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Detektatu sintaxia" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "Beharrezkoa sintaxia nabarmentzeko eta formaturako (tresna-barra eta laster-teklak). Desgaitu errendimendua pixka bat hobetzeko." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Gaia" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Formatu-barra" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Gaitu formatudun ikuspegia" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Desgaitu abioko denbora murrizteko" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Ireki formatudun ikuspegian" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Hau gaituz, ohar guztiak markdown errendatuarekin irekiko dira" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Onartu matematika-ekuazioak" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Pixka bat murrizten du errendatze-errendimendua" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Errendatu monospace letra-topoa erabiliz" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Tarte bakarreko letra-tamainaren erlazioarekiko proportzionala" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "Errendatutako ikuspegian. Erabili 1 ez doitzeko." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Eutsi motorrari memorian" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Ondorengo bihurketak azkarragoak izango dira, baina memoria-erabilera altuagoa" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Ainguratu alboko barra" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Mahaiganean, espazioa dagoenean" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Kategoria-etiketaren estiloa" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Datuak" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Reset Database" msgstr "Berrezarri datu-basea" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Delete all notes from the local database. The app will quit." msgstr "Ezabatu datu-base lokaleko ohar guztiak. Aplikazioa itxi egingo da." #. Translators: Button #: data/ui/preferences_dialog.ui:178 iotas/preferences_dialog.py:339 msgid "Reset" msgstr "Berrezarri" #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "Deskonektatu Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "Saioa amaitzen du Nextcloud Notes aplikazioan. Ohar guztiak kenduko dira eta aplikazioa itxi egingo da." #. Translators: Button #: data/ui/preferences_dialog.ui:199 iotas/preferences_dialog.py:360 msgid "Disconnect" msgstr "Deskonektatu" #. Translators: Title #: data/ui/preferences_dialog.ui:217 msgid "Debug" msgstr "Arazketa" #. Translators: Title #: data/ui/preferences_dialog.ui:223 msgid "Clear Sync Timestamp" msgstr "Garbitu sinkronizazioaren denbora-zigilua" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:225 msgid "Forces a pull of all notes from the sync server" msgstr "Ohar guztiak sinkronizazio-zerbitzaritik ateratzera behartzen du" #. Translators: Button #: data/ui/preferences_dialog.ui:232 msgid "Clear" msgstr "Garbitu" #. Translators: Button #: data/ui/selection_header_bar.ui:32 msgid "Delete Selected" msgstr "Ezabatu hautatutakoa" #. Translators: Button #: data/ui/selection_header_bar.ui:43 msgid "Toggle Favorite for Selected" msgstr "Aldatu gogokoa hautatuarekin" #. Translators: Button #: data/ui/selection_header_bar.ui:51 msgid "Change Category for Selected" msgstr "Aldatu hautatutakoaren kategoria" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Itxi kategoriak" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Kategoriak" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Txertatu taula" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Sortu" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Jarraitu sistemaren estiloa" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Estilo argia" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Estilo iluna" #. Translators: Description, CLI option #: iotas/application.py:266 msgid "Create a note" msgstr "Sortu ohar bat" #. Translators: Description, CLI option #: iotas/application.py:275 msgid "Create a backup" msgstr "Sortu babeskopia bat" #. Translators: Description, CLI option #: iotas/application.py:284 msgid "Restore a backup" msgstr "Leheneratu babeskopia bat" #. Translators: Description, CLI option #: iotas/application.py:293 msgid "Display backup path" msgstr "Bistaratu babeskopiaren bide-izena" #. Translators: Description, CLI option #: iotas/application.py:302 msgid "Display path for custom server SSL CA chain file" msgstr "Bistaratu SSL ZE kate-fitxategiaren zerbitzari pertsonalizatuaren bide-izena" #. Translators: Description, CLI option #: iotas/application.py:311 msgid "Toggle display of extended preferences in UI" msgstr "Aldatu hobespen hedatuen bistaratzea interfazean" #. Translators: Description, CLI option #: iotas/application.py:320 msgid "Quit any running instance" msgstr "Irten exekutatzen ari den edozein instantziatik" #. Translators: Description, CLI option #: iotas/application.py:329 msgid "Enable debug logging and functions" msgstr "Gaitu arazketa-egunkaria eta -funtzioak" #. Translators: Description, CLI option #: iotas/application.py:338 msgid "Open note by id" msgstr "Ireki oharra IDaren arabera" #. Translators: Description, CLI option #: iotas/application.py:347 msgid "Search in notes" msgstr "Bilatu oharretan" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:203 msgid "RESTORATION REMOTE ID CLASH" msgstr "LEHENERATZEAREN URRUNEKO IDAREN GATAZKA" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:221 msgid "RESTORATION TITLE CLASH" msgstr "LEHENERATZEAREN IZENBURUAREN GATAZKA" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Ohar guztiak" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Kategorizatu gabea" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:946 #, python-brace-format msgid "Line length now {0}px" msgstr "Lerro-luzera orain {0}px" #. Translators: Description, notification #: iotas/editor.py:952 msgid "Line length limit disabled" msgstr "Lerro-luzeraren muga desgaitu da" #: iotas/editor.py:1572 msgid "Opening link in browser" msgstr "Esteka nabigatzailean irekitzen" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} / {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:100 msgid "Exported to {}" msgstr "Hona esportatu da: {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:113 msgid "Failed to export to {}" msgstr "Huts egin du hona esportatzeak: {}" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:198 msgid "{} notes deleted" msgstr "{} ohar ezabatu dira" #. Translators: Description, notification #: iotas/index.py:201 msgid "Note deleted" msgstr "Oharra ezabatu da" #. Translators: Button #: iotas/index.py:206 msgid "Undo" msgstr "Desegin" #. Translators: Description, notification #: iotas/index.py:244 msgid "Sync conflict with note being edited" msgstr "Sinkronizazioa ez da bateragarria oharra edizioan egotearekin" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:252 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "Huts egin du zerbitzu sekretura sartzeak. Ziurtatu gnome-keyring edo antzeko beste hornitzaile bat duzula, gako sorta lehenetsia duena eta desblokeatuta dagoena." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:484 msgid "Syncing" msgstr "Sinkronizatzen" #. Translators: Description, notification, {} is a number #: iotas/index.py:503 msgid "{} change" msgid_plural "{} changes" msgstr[0] "Aldaketa {}" msgstr[1] "{} aldaketa" #. Translators: Description, notification #: iotas/index.py:519 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Sinkronizazioak huts egin du. Nextcloud Notes instalatuta al dago zerbitzarian?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:616 msgid "Loading" msgstr "Kargatzen" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Txertatu esteka" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Editatu esteka" #. Translators: Title #: iotas/nextcloud_login_dialog.py:107 msgid "Updating Notes" msgstr "Oharrak eguneratzen" #. Translators: Title #: iotas/nextcloud_login_dialog.py:111 msgid "Performing Initial Transfer" msgstr "Hasierako transferentzia gauzatzen" #. Translators: Title #: iotas/nextcloud_login_dialog.py:165 msgid "Connecting" msgstr "Konektatzen" #. Translators: Title #: iotas/nextcloud_login_dialog.py:187 msgid "Waiting for Login" msgstr "Saioa hasteko zain" #. Translators: Description #: iotas/nextcloud_login_dialog.py:189 msgid "Complete the authentication in your browser" msgstr "Osatu autentifikazioa nabigatzailean" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:205 msgid "Failed to start login with possible certificate issue" msgstr "Saio-hasierak huts egin du, balizko ziurtagiri-arazoa" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:208 msgid "Failed to start login. Wrong address?" msgstr "Saio-hasierak huts egin du. Helbide okerra?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:65 iotas/preferences_dialog.py:97 msgid "Monochrome" msgstr "Monokromoa" #. Translators: Description, a style name #: iotas/preferences_dialog.py:67 msgid "Muted Markup" msgstr "Markup mututua" #. Translators: Description, a style name #: iotas/preferences_dialog.py:69 msgid "Bold Markup" msgstr "Markup lodia" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:126 msgid "Disabled" msgstr "Desgaituta" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:99 msgid "Muted" msgstr "Mutututa" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:101 msgid "Blue" msgstr "Urdina" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:103 msgid "Orange" msgstr "Laranja" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Red" msgstr "Gorria" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "None" msgstr "Bat ere ez" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:120 iotas/preferences_dialog.py:140 msgid "Always Visible" msgstr "Beti ikusgai" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:122 iotas/preferences_dialog.py:142 msgid "Automatically Hide" msgstr "Ezkutatu automatikoki" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Auto Hide When Fullscreen" msgstr "Ezkutatu automatikoki pantaila osoan" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:278 #, python-brace-format msgid "Reducing in {0} presses" msgstr "{0} sakatze murrizten" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Extending in {0} presses" msgstr "{0} sakatze hedatzen" #. Translators: Description, notification #: iotas/preferences_dialog.py:286 msgid "Extended hidden" msgstr "Ezkutatze hedatua" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended shown" msgstr "Erakuste hedatua" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:312 msgid "Hiding discouraged on mobile" msgstr "Ezkutatzea ez da gomendatzen mugikorretan" #. Translators: Title #: iotas/preferences_dialog.py:332 msgid "Reset Database?" msgstr "Berrezarri datu-basea?" #. Translators: Description #: iotas/preferences_dialog.py:334 msgid "All notes will be deleted. Continue with the reset?" msgstr "Ohar guztiak ezabatuko dira. Jarraitu berrezarpenarekin?" #. Translators: Title #: iotas/preferences_dialog.py:353 msgid "Disconnect Nextcloud?" msgstr "Deskonektatu Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:355 msgid "All notes will be removed. Do you want to sign out?" msgstr "Ohar guztiak kenduko dira. Saioa amaitu nahi duzu?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Ezin da kategoria aldatu irakurtzeko soilik den oharrean" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} hautatu da" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:502 msgid "SYNC CONFLICT" msgstr "SINK GATAZKA" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Errorea" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/fi.po000066400000000000000000001242611507102636600217640ustar00rootroot00000000000000# Finnish translation for Iotas. # Copyright (C) 2025 Iotas's COPYRIGHT HOLDER # This file is distributed under the same license as the Iotas package. # Jiri Grönroos , 2025. # msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/-/issues\n" "POT-Creation-Date: 2025-04-03 11:17+0000\n" "PO-Revision-Date: 2025-04-05 13:01+0300\n" "Last-Translator: Jiri Grönroos \n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.4.4\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:4 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:6 msgid "Simple note taking with Nextcloud Notes" msgstr "Muistiinpanoja Nextcloud Notesin kanssa" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:14 msgid "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;" "document;gnome;gtk;" msgstr "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;" "document;gnome;gtk;muistilaput;muistiinpanot;huomiot;muokkain;" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Sovellus muistiinpanojen tekemiseen" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas tarjoaa häiriövapaan tavan tehdä muistiinpanoja mobiililähtöisen " "käyttöliittymän avulla." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Ominaisuudet" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Valinnainen nopea synkronointi Nextcloud Notesin kanssa" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "" "Muistilappujen muokkaus yhteydettömässä tilassa, synkronointi verkkoyhteyden " "ollessa käytössä" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Luokkien muokkaus ja suodatus" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Suosikit" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Oikoluku" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Etsi kokoelmasta tai yksittäisistä muistilapuista" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Keskittymistila ja valinnainen muokkaimen otsakkeen ja muotoilupalkin " "piilottaminen" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "Esikatselussa: vie PDF-, ODT- ja HTML-muotoon" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Haku Gnomen käyttöliittymästä" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Muistilappujen varmuuskopinti ja palautus (komentoriviltä, käyttöön ilman " "synkronointia)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Mahdollisuus muuttaa fontin kokoa ja tasalevyistä tyyliä" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Kirjoittaminen markdownilla on tuettu, mutta valinnaista, tarjoten" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Muotoilun työkalupalkin ja pikanäppäinten avulla" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Syntaksin korostuksen teemoilla" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Muotoillun näkymän" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Teknisiä yksityiskohtia niistä kiinnostuneille" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "Nextcloud Notes -synkronointi tapahtuu REST-rajapinnan kautta, ei WebDAV:in, " "eli se on nopeaa" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Synkronoinnin ristiriitojen yksinkertainen havainnointi" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Muistilaput tallennetaan jatkuvasti" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Suuret muistilappukokoelmat ladataan osissa, jotta käynnistyminen on nopeaa" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Muistilaput talletetaan SQLite-tietokantaan, tarjoten nopean haun (FTS). " "Tiedostot on mahdollista noutaa tekemällä varmuuskopio komentorivillä." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Luettelo" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Muokkausta markdownilla" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Muotoiltua markdownia" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Luettelo ja tumma tyyli" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobiilinäkymä" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Jiri Grönroos" #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Kumoa muutokset" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Toteuta muutokset" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Toteuta" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Tyhjennä ja toteuta" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Etsi" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Takaisin" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_window.ui:287 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Edellinen osuma" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_window.ui:280 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Seuraava osuma" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_window.ui:273 msgid "Replace" msgstr "Korvaa" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:300 msgid "Focus Mode" msgstr "Keskittymistila" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Etsi ja korvaa…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Siirry…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Muokkaa otsikkoa…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Vaihda luokka…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Poista" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Vie…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Takaisin muistilappuihin" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Muistilappu on \"vain luku\"-tilassa" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Muokkaimen valikko" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle Markdown Render" msgstr "Markdown-piirto päällä/pois" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Muokkaa muistilappua" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Ladataan piirtomoottoria" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:337 #: iotas/preferences_dialog.py:358 msgid "Cancel" msgstr "Peru" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As..." msgstr "Vie nimellä…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Exporting..." msgstr "Viedään…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:71 data/ui/export_dialog.ui:99 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Sulje" #. Translators: Button #: data/ui/export_dialog.ui:78 msgid "Show" msgstr "Näytä" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Tervetuloa, tämä on Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Käytä yllä olevaa otsakepalkkia…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Lisää muistilappu" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Synkronoi Nextcloud Notesin kanssa" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Loitonna" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Lähennä" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_window.ui:239 msgid "Horizontal Rule" msgstr "Vaakaviiva" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_window.ui:246 msgid "Quote" msgstr "Lainaus" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_window.ui:225 msgid "Code" msgstr "Koodi" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_window.ui:253 msgid "Table" msgstr "Taulukko" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Taso 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Taso 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Taso 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Taso 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Poista" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_window.ui:183 msgid "Heading" msgstr "Otsikko" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_window.ui:169 msgid "Bold" msgstr "Lihavointi" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_window.ui:176 msgid "Italic" msgstr "Kursivointi" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_window.ui:232 msgid "Strikethrough" msgstr "Yliviivaus" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_window.ui:190 msgid "Unordered List" msgstr "Järjestämätön luettelo" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_window.ui:197 msgid "Ordered List" msgstr "Järjestetty luettelo" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_window.ui:204 msgid "Checkbox" msgstr "Valintaruutu" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_window.ui:218 msgid "Link" msgstr "Linkki" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Päivitä" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Asetukset" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Pikanäppäimet" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Tietoja - Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Päävalikko" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Tänään" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Eilen" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Tällä viikolla" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Tässä kuussa" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Viime kuussa" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Näytä aiemmat kuukaudet" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Ennen edellistä kuukautta" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Näytä lisää" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Avaa luokat" #. Translators: Button #: data/ui/index.ui:42 msgid "New Note" msgstr "Uusi muistilappu" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:266 msgid "Search" msgstr "Etsi" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Valitse muistilaput" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Palvelinyhteys on katkaistu" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Tunnistaudu" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" #. Translators: Button #: data/ui/index.ui:111 msgid "OK" msgstr "OK" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Muistilappujen luettelo on tyhjä" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Anna hakuehto" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Ei hakutuloksia" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create New Note" msgstr "Luo uusi muistilappu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show Sidebar" msgstr "Näytä sivupalkki" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete Note" msgstr "Poista muistilappu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move Up List" msgstr "Siirry ylös luettelossa" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move Down List" msgstr "Siirry alas luettelossa" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start Selection" msgstr "Aloita valinta" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset Filter" msgstr "Poista suodatus" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open First Search Result" msgstr "Avaa ensimmäinen hakutulos" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Muokkain" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit Title" msgstr "Muokkaa otsikkoa" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_window.ui:93 iotas/export_dialog.py:129 msgid "Export" msgstr "Vie" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create New Note Including Selection" msgstr "Luo uusi muistilappu sisältäen valinnan" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Change Category" msgstr "Vaihda luokka" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo Typing" msgstr "Kumoa kirjoitus" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo Typing" msgstr "Tee uudelleen kirjoitus" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Insert Emoji" msgstr "Lisää emoji" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Focus Text View" msgstr "Kohdista tekstinäkymään" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Focus Header Bar" msgstr "Kohdista otsakepalkkiin" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:156 msgid "Focus Formatting Bar" msgstr "Kohdista muotoilupalkkiin" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:164 msgid "Formatting" msgstr "Muotoilu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:211 msgid "Toggle Checkbox" msgstr "" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:261 msgid "Editor Search" msgstr "Muokkaimen haku" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:295 msgid "Editor Appearance" msgstr "Muokkaimen ulkoasu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:307 msgid "Increase Line Length" msgstr "Suurenna rivin pituutta" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:314 msgid "Decrease Line Length" msgstr "Pienennä rivin pituutta" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:321 msgid "Increase Font Size" msgstr "Suurenna fontin kokoa" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:328 msgid "Decrease Font Size" msgstr "Pienennä fontin kokoa" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:336 msgid "General" msgstr "Yleiset" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:341 msgid "Toggle Fullscreen" msgstr "Koko näyttö päällä/pois" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:348 msgid "Show Preferences" msgstr "Näytä asetukset" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:355 msgid "Show Shortcuts" msgstr "Näytä pikanäppäimet" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:362 msgid "Open Previous Note" msgstr "Avaa edellinen muistilappu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:369 msgid "Go Back" msgstr "Takaisin" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:376 msgid "Quit" msgstr "Lopeta" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "Verkko-osoite" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Teksti" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud Notesin määritys" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Paina Jatka määrittääksesi Nextcloud-palvelimen osoitteen ja kirjautuaksesi " "selaimen kautta" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Jatka" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Palvelimen osoite" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Aloita kirjautuminen" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Varmenne on allekirjoitettu itse" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Avaa UKK" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Yhteys muodostettu" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Valmis" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Viimeistele synkronoinnin määritys" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Käyttöliittymä" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Käytä tasalevyistä fonttia" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Tarkista oikeinkirjoitus" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Vaihda kieltä muokkaimen kontekstivalikon kautta" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Otsakepalkki" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Rajoita rivin pituutta" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Ensisijaisesti työpöytäkäyttöä varten. Käytä Ctrl + ↑ ja Ctrl + ↓ " "hienosäätääksesi." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Havaitse syntaksi" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Teema" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Muotoilupalkki" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Käytä muotoiltua näkymää" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Poista käytöstä nopeuttaaksesi käynnistymistä" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Avaa muotoillussa näkymässä" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "" "Tämän käyttäminen tarkoittaa, että kaikki muistilaput avataan markdown-" "muotoiltuna" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Tue matemaattisia yhtälöitä" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Piirrä käyttäen tasalevyistä fonttia" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "" #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Säilytä moottori muistissa" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Kiinnitä sivupalkki" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Työpöydällä kun tilaa on saatavilla" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Luokkanimikkeen tyyli" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Data" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Reset Database" msgstr "Nollaa tietokanta" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Delete all notes from the local database. The app will quit." msgstr "" "Poista kaikki muistilaput paikallisesta tietokannasta. Sovellus sulkeutuu " "tämän jälkeen." #. Translators: Button #: data/ui/preferences_dialog.ui:178 iotas/preferences_dialog.py:339 msgid "Reset" msgstr "Nollaa" #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "Katkaise yhteys Nextcloudiin" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Kirjaudu ulos Nextcloud Notesista. Kaikki muistilaput poistetaan ja sovellus " "sulkeutuu." #. Translators: Button #: data/ui/preferences_dialog.ui:199 iotas/preferences_dialog.py:360 msgid "Disconnect" msgstr "Katkaise yhteys" #. Translators: Title #: data/ui/preferences_dialog.ui:217 msgid "Debug" msgstr "Virheenjäljitys" #. Translators: Title #: data/ui/preferences_dialog.ui:223 msgid "Clear Sync Timestamp" msgstr "Tyhjennä synkronoinnin aikaleima" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:225 msgid "Forces a pull of all notes from the sync server" msgstr "Pakottaa kaikkien muistilappujen noudon synkronointipalvelimelta" #. Translators: Button #: data/ui/preferences_dialog.ui:232 msgid "Clear" msgstr "Tyhjennä" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Poista valitut" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Vaihda valitun suosikkitilaa" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Vaihda valitun luokkaa" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Sulje luokat" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Luokat" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Lisää taulukko" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Luo" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Seuraa järjestelmän tyyliä" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Vaalea tyyli" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Tumma tyyli" #. Translators: Description, CLI option #: iotas/application.py:266 msgid "Create a note" msgstr "Luo muistilappu" #. Translators: Description, CLI option #: iotas/application.py:275 msgid "Create a backup" msgstr "Luo varmuuskopio" #. Translators: Description, CLI option #: iotas/application.py:284 msgid "Restore a backup" msgstr "Palauta varmuuskopio" #. Translators: Description, CLI option #: iotas/application.py:293 msgid "Display backup path" msgstr "Näytä varmuuskopion polku" #. Translators: Description, CLI option #: iotas/application.py:302 msgid "Display path for custom server SSL CA chain file" msgstr "Näytä polku mukautetun palvelimen SSL CA -ketjutiedostoon" #. Translators: Description, CLI option #: iotas/application.py:311 msgid "Toggle display of extended preferences in UI" msgstr "" #. Translators: Description, CLI option #: iotas/application.py:320 msgid "Quit any running instance" msgstr "Lopeta kaikki käynnissä olevat instanssit" #. Translators: Description, CLI option #: iotas/application.py:329 msgid "Enable debug logging and functions" msgstr "" #. Translators: Description, CLI option #: iotas/application.py:338 msgid "Open note by id" msgstr "Avaa muistilappu id-tunnisteen perusteella" #. Translators: Description, CLI option #: iotas/application.py:347 msgid "Search in notes" msgstr "Etsi muistilapuista" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:203 msgid "RESTORATION REMOTE ID CLASH" msgstr "" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:221 msgid "RESTORATION TITLE CLASH" msgstr "" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Kaikki muistilaput" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Luokittelematon" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:946 #, python-brace-format msgid "Line length now {0}px" msgstr "Rivin pituus on nyt {0} px" #. Translators: Description, notification #: iotas/editor.py:952 msgid "Line length limit disabled" msgstr "Rivin pituusrajoitus pois käytöstä" #: iotas/editor.py:1572 msgid "Opening link in browser" msgstr "Avataan linkki selaimessa" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0}/{1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:100 msgid "Exported to {}" msgstr "Viety muotoon {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:113 msgid "Failed to export to {}" msgstr "Vienti muotoon {} epäonnistui" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:198 msgid "{} notes deleted" msgstr "{} muistilappua poistettu" #. Translators: Description, notification #: iotas/index.py:201 msgid "Note deleted" msgstr "Muistilappu poistettu" #. Translators: Button #: iotas/index.py:206 msgid "Undo" msgstr "Kumoa" #. Translators: Description, notification #: iotas/index.py:244 msgid "Sync conflict with note being edited" msgstr "Synkronoinnin ristiriita muokattavassa muistilapussa" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:252 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:484 msgid "Syncing" msgstr "Synkronoidaan" #. Translators: Description, notification, {} is a number #: iotas/index.py:503 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} muutos" msgstr[1] "{} muutosta" #. Translators: Description, notification #: iotas/index.py:519 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "" "Synkronointivirhe. Onko Nextcloud Notes -sovellus asennettu palvelimelle?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:616 msgid "Loading" msgstr "Ladataan" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Lisää linkki" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Muokkaa linkkiä" #. Translators: Title #: iotas/nextcloud_login_dialog.py:107 msgid "Updating Notes" msgstr "Päivitetään muistilappuja" #. Translators: Title #: iotas/nextcloud_login_dialog.py:111 msgid "Performing Initial Transfer" msgstr "Suoritetaan ensimmäistä siirtoa" #. Translators: Title #: iotas/nextcloud_login_dialog.py:165 msgid "Connecting" msgstr "Yhdistetään" #. Translators: Title #: iotas/nextcloud_login_dialog.py:187 msgid "Waiting for Login" msgstr "Odotetaan kirjautumista" #. Translators: Description #: iotas/nextcloud_login_dialog.py:189 msgid "Complete the authentication in your browser" msgstr "Viimeistele tunnistautuminen selaimessa" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:205 msgid "Failed to start login with possible certificate issue" msgstr "" "Kirjautumisen aloittaminen epäonnistui mahdollisen varmenneongelman vuoksi" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:208 msgid "Failed to start login. Wrong address?" msgstr "Kirjautumisen aloittaminen epäonnistui. Onko osoite väärin?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:65 iotas/preferences_dialog.py:97 msgid "Monochrome" msgstr "Mustavalkoinen" #. Translators: Description, a style name #: iotas/preferences_dialog.py:67 msgid "Muted Markup" msgstr "Mykistetty merkkaus" #. Translators: Description, a style name #: iotas/preferences_dialog.py:69 msgid "Bold Markup" msgstr "Lihavoitu merkkaus" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:126 msgid "Disabled" msgstr "Ei käytössä" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:99 msgid "Muted" msgstr "Mykistetty" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:101 msgid "Blue" msgstr "Sininen" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:103 msgid "Orange" msgstr "Oranssi" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Red" msgstr "Punainen" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "None" msgstr "Ei mitään" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:120 iotas/preferences_dialog.py:140 msgid "Always Visible" msgstr "Aina näkyvissä" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:122 iotas/preferences_dialog.py:142 msgid "Automatically Hide" msgstr "Piilota automaattisesti" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Auto Hide When Fullscreen" msgstr "Piilota automaattisesti koko näytön tilassa" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:278 #, python-brace-format msgid "Reducing in {0} presses" msgstr "" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Extending in {0} presses" msgstr "" #. Translators: Description, notification #: iotas/preferences_dialog.py:286 msgid "Extended hidden" msgstr "" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended shown" msgstr "" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:312 msgid "Hiding discouraged on mobile" msgstr "Piilottamista ei suositella mobiililla" #. Translators: Title #: iotas/preferences_dialog.py:332 msgid "Reset Database?" msgstr "Tyhjennetäänkö tietokanta?" #. Translators: Description #: iotas/preferences_dialog.py:334 msgid "All notes will be deleted. Continue with the reset?" msgstr "Kaikki muistilaput poistetaan. Jatketaanko nollausta?" #. Translators: Title #: iotas/preferences_dialog.py:353 msgid "Disconnect Nextcloud?" msgstr "Katkaistaanko yhteys Nextcloudiin?" #. Translators: Description #: iotas/preferences_dialog.py:355 msgid "All notes will be removed. Do you want to sign out?" msgstr "Kaikki muistilaput poistetaan. Haluatko kirjautua ulos?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} valittu" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:502 msgid "SYNC CONFLICT" msgstr "SYNKRONOINNIN RISTIRIITA" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Virhe" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/fr.po000066400000000000000000001746761507102636600220140ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-01-12 14:56+1000\n" "PO-Revision-Date: 2025-01-20 18:25+0100\n" "Last-Translator: Irénée Thirion \n" "Language-Team: \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.5\n" #. (itstool) path: iotas-alpha-bold-dark-high-contrast.xml/style-scheme@_name #. (itstool) path: iotas-alpha-bold-high-contrast.xml/style-scheme@_name #: iotas-alpha-bold-dark-high-contrast.xml:3 #: iotas-alpha-bold-high-contrast.xml:3 msgid "Bold Markup (High Contrast)" msgstr "Marquage en gras (contraste élevé)" #. (itstool) path: iotas-alpha-bold.xml/style-scheme@_name #. Translators: Description, a style name #: iotas-alpha-bold.xml:3 iotas/preferences_dialog.py:70 msgid "Bold Markup" msgstr "Marquage en gras" #. (itstool) path: iotas-alpha-dark-high-contrast.xml/style-scheme@_name #. (itstool) path: iotas-alpha-high-contrast.xml/style-scheme@_name #: iotas-alpha-dark-high-contrast.xml:3 iotas-alpha-high-contrast.xml:3 msgid "Muted Markup (High Contrast)" msgstr "Marquage atténué (contraste élevé)" #. (itstool) path: iotas-alpha.xml/style-scheme@_name #. Translators: Description, a style name #: iotas-alpha.xml:3 iotas/preferences_dialog.py:68 msgid "Muted Markup" msgstr "Marquage atténué" #. (itstool) path: iotas-mono-dark-high-contrast.xml/style-scheme@_name #. (itstool) path: iotas-mono-high-contrast.xml/style-scheme@_name #: iotas-mono-dark-high-contrast.xml:3 iotas-mono-high-contrast.xml:3 msgid "Monochrome (High Contrast)" msgstr "Monochrome (contraste élevé)" #. (itstool) path: iotas-mono.xml/style-scheme@_name #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas-mono.xml:3 iotas/preferences_dialog.py:66 #: iotas/preferences_dialog.py:98 msgid "Monochrome" msgstr "Monochrome" #. (itstool) path: iotas-unstyled-dark-high-contrast.xml/style-scheme@_name #. (itstool) path: iotas-unstyled-high-contrast.xml/style-scheme@_name #: iotas-unstyled-dark-high-contrast.xml:3 iotas-unstyled-high-contrast.xml:3 msgid "Disabled (High Contrast)" msgstr "Désactivé (contraste élevé)" #. (itstool) path: iotas-unstyled.xml/style-scheme@_name #: iotas-unstyled.xml:3 msgid "Disable" msgstr "Désactiver" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:4 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:6 msgid "Simple note taking with Nextcloud Notes" msgstr "Prise de notes simple avec Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:14 msgid "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;" "document;gnome;gtk;" msgstr "" "notes;nextcloud;minimal;distraction;éditeur;focus;texte;écrire;write;" "markdown;document;gnome;gtk;" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Simple prise de notes" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas vise à fournir une prise de notes sans distraction avec un design " "conçu pour un usage sur mobile." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Fonctionnalités" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Synchronisation rapide optionnelle avec Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Édition de notes hors ligne, synchronisation lors du retour en ligne" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Modification et filtrage des catégories" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Favoris" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Vérification orthographique" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Recherche dans vos collections de notes ou par fichier" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Mode focus et possibilité de masquer la barre supérieure de l’éditeur et les " "barres de formatage" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "En prévisualisation : export en PDF, ODT et HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Un design convergent, permettant à Iotas de s’insérer parfaitement dans " "votre environnement de bureau sur mobile ou ordinateur" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Recherche depuis GNOME Shell" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Sauvegarde et restauration des notes (en ligne de commande, pour une " "utilisation sans synchronisation)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "" "Possibilité de changer la taille de la police et de basculer en style " "monospace" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "" "L’écriture en markdown est prise en charge mais optionnelle, fournissant" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formatage avec une barre d’outils et des raccourcis" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Une coloration syntaxique avec des thèmes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Une vue formatée" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "La possibilité de cocher des listes de tâches depuis la vue formatée" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Quelques détails plus techniques, pour les plus initiés" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "La synchronisation Nextcloud Notes se fait via l’API REST à la place de " "WebDAV, ce qui la rend plus rapide" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Il y a une détection basique des conflits de synchronisation" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Les notes sont constamment enregistrées" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Les grandes quantités de notes sont partiellement chargées pour accélérer le " "démarrage" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Les notes sont stockées dans SQLite, permettant une recherche rapide sans " "réinventer la roue. Les fichiers en texte clair peuvent être récupérés en " "faisant une sauvegarde (CLI)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Index" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Éditeur avec markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Rendu markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Index en style sombre" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobile" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Irénée THIRION" #. Translators: Button #: data/ui/category_header_bar.ui:14 data/ui/editor_rename_header_bar.ui:16 msgid "Revert Changes" msgstr "Annuler les changements" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:41 data/ui/editor_rename_header_bar.ui:39 msgid "Apply Changes" msgstr "Appliquer les changements" #. Translators: Button #: data/ui/category_header_bar.ui:43 data/ui/editor_rename_header_bar.ui:41 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Appliquer" #. Translators: Button #: data/ui/category_header_bar.ui:57 msgid "Clear and Apply" msgstr "Effacer et appliquer" #. Translators: Placeholder text #. Translators: Menu item #: data/ui/editor_search_entry.ui:14 data/ui/editor.ui:25 msgid "Find" msgstr "Chercher" #. Translators: Button #: data/ui/editor_search_header_bar.ui:15 data/ui/index_search_header_bar.ui:11 #: data/ui/render_search_header_bar.ui:14 data/ui/selection_header_bar.ui:16 msgid "Back" msgstr "Retour" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:42 #: data/ui/keyboard_shortcuts_window.ui:287 #: data/ui/render_search_header_bar.ui:35 msgid "Previous Match" msgstr "Correspondance précédente" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:50 #: data/ui/keyboard_shortcuts_window.ui:280 #: data/ui/render_search_header_bar.ui:43 msgid "Next Match" msgstr "Correspondance suivante" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:72 #: data/ui/editor_search_header_bar.ui:81 #: data/ui/keyboard_shortcuts_window.ui:273 msgid "Replace" msgstr "Remplacer" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:300 msgid "Focus Mode" msgstr "Mode focus" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:32 data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit Title" msgstr "Modifier le titre" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:37 data/ui/keyboard_shortcuts_window.ui:107 msgid "Change Category" msgstr "Changer la catégorie" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Delete" msgstr "Supprimer" #. Translators: Menu item #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/editor.ui:49 data/ui/keyboard_shortcuts_window.ui:93 #: iotas/export_dialog.py:127 msgid "Export" msgstr "Exporter" #. Translators: Button #: data/ui/editor.ui:83 msgid "Back to Notes" msgstr "Retour vers les notes" #. Translators: Description, tooltip #: data/ui/editor.ui:119 msgid "Note is Read-Only" msgstr "La note est en lecture seule" #. Translators: Button #: data/ui/editor.ui:129 msgid "Editor Menu" msgstr "Menu de l’éditeur" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:137 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle Markdown Render" msgstr "Activer / désactiver le rendu markdown" #. Translators: Button #: data/ui/editor.ui:145 msgid "Edit Note" msgstr "Éditer la note" #. Translators: Description, help #: data/ui/editor.ui:280 msgid "Render Engine Loading" msgstr "Chargement du moteur de rendu" #. Translators: Button #: data/ui/export_dialog.ui:21 iotas/preferences_dialog.py:337 #: iotas/preferences_dialog.py:358 msgid "Cancel" msgstr "Annuler" #. Translators: Title #: data/ui/export_dialog.ui:29 msgid "Export As..." msgstr "Exporter vers…" #. Translators: Title #: data/ui/export_dialog.ui:49 msgid "Exporting..." msgstr "Export…" #. Translators: Button #: data/ui/export_dialog.ui:68 data/ui/export_dialog.ui:95 iotas/ui_utils.py:92 msgid "Close" msgstr "Fermer" #. Translators: Button #: data/ui/export_dialog.ui:75 msgid "Show" msgstr "Afficher" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Bienvenue dans Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:29 msgid "Add a Note" msgstr "Ajouter une note" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:49 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Synchroniser avec Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Zoom arrière" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Zoom avant" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:157 #: data/ui/keyboard_shortcuts_window.ui:239 msgid "Horizontal Rule" msgstr "Règle horizontale" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:166 #: data/ui/keyboard_shortcuts_window.ui:246 msgid "Quote" msgstr "Citation" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:175 #: data/ui/keyboard_shortcuts_window.ui:225 msgid "Code" msgstr "Code" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:184 #: data/ui/keyboard_shortcuts_window.ui:253 msgid "Table" msgstr "Tableau" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Niveau 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Niveau 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Niveau 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Niveau 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Supprimer" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:80 data/ui/keyboard_shortcuts_window.ui:183 msgid "Heading" msgstr "En-tête" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:89 data/ui/keyboard_shortcuts_window.ui:169 msgid "Bold" msgstr "Gras" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:98 data/ui/keyboard_shortcuts_window.ui:176 msgid "Italic" msgstr "Italique" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:107 #: data/ui/keyboard_shortcuts_window.ui:232 msgid "Strikethrough" msgstr "Barré" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:116 #: data/ui/keyboard_shortcuts_window.ui:190 msgid "Unordered List" msgstr "Liste non ordonnée" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:125 #: data/ui/keyboard_shortcuts_window.ui:197 msgid "Ordered List" msgstr "Liste ordonnée" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:134 #: data/ui/keyboard_shortcuts_window.ui:204 msgid "Checkbox" msgstr "Case à cocher" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:143 #: data/ui/keyboard_shortcuts_window.ui:218 msgid "Link" msgstr "Lien" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Actualiser" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Préférences" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Raccourcis clavier" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "À propos de Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Menu principal" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Aujourd’hui" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Hier" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Cette semaine" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Ce mois-ci" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Le mois dernier" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Afficher les mois précédents" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Avant le mois dernier" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Afficher plus" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Afficher les catégories" #. Translators: Button #: data/ui/index.ui:42 msgid "New Note" msgstr "Nouvelle note" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:266 msgid "Search" msgstr "Rechercher" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Sélectionner des notes" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Connexion serveur hors-ligne" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Du fait de changements en coulisse (un nouvel identifiant d’application) " "Iotas nécessite que vous vous ré-authentifiez auprès de votre serveur " "Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "S’authentifier" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "Le jeton d’authentification pour la synchronisation avec Nextcloud Notes n’a " "pu être récupéré" #. Translators: Button #: data/ui/index.ui:111 msgid "OK" msgstr "OK" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Liste de notes vide" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Entrez un terme à rechercher" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Aucun résultat" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create New Note" msgstr "Créer une nouvelle note" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show Sidebar" msgstr "Afficher la barre latérale" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete Note" msgstr "Supprimer la note" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move Up List" msgstr "Déplacer la liste vers le haut" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move Down List" msgstr "Déplacer la liste vers le bas" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start Selection" msgstr "Commencer la sélection" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset Filter" msgstr "Réinitialiser le filtre" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open First Search Result" msgstr "Ouvrir le premier résultat de recherche" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Éditeur" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create New Note Including Selection" msgstr "Créer une nouvelle note incluant la sélection" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo Typing" msgstr "Annuler la saisie" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo Typing" msgstr "Rétablir la saisie" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Insert Emoji" msgstr "Insérer un emoji" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Focus Text View" msgstr "Mode focus de la vue du texte" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Focus Header Bar" msgstr "Mode focus de la barre supérieure" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:156 msgid "Focus Formatting Bar" msgstr "Mode focus de la barre de formatage" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:164 msgid "Formatting" msgstr "Formatage" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:211 msgid "Toggle Checkbox" msgstr "Cocher la case" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:261 msgid "Editor Search" msgstr "Recherche de l’éditeur" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:295 msgid "Editor Appearance" msgstr "Apparence de l’éditeur" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:307 msgid "Increase Line Length" msgstr "Augmenter la longueur des lignes" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:314 msgid "Decrease Line Length" msgstr "Réduire la longueur des lignes" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:321 msgid "Increase Font Size" msgstr "Augmenter la taille de police" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:328 msgid "Decrease Font Size" msgstr "Réduire la taille de police" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:336 msgid "General" msgstr "Général" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:341 msgid "Toggle Fullscreen" msgstr "Basculer en plein écran" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:348 msgid "Show Preferences" msgstr "Afficher les préférences" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:355 msgid "Show Shortcuts" msgstr "Afficher les raccourcis clavier" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:362 msgid "Go Back" msgstr "Retour" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:369 msgid "Quit" msgstr "Quitter" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Texte" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Configuration de Nextcloud Notes" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Cliquez sur Continuer pour fournir votre adresse de serveur Nextcloud et " "vous connecter via un navigateur web" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Continuer" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Continuer vers la saisie de l’URL" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Service secret inaccessible" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "Il n’a pas été possible d’accéder à Secret Service pour stocker les détails " "d’authentification. Assurez-vous que vous avez un fournisseur tel que gnome-" "keyring. Un trousseau de clés par défaut doit être configuré, et ce " "trousseau doit être déverrouillé. La plupart des environnements de bureau " "vous le fourniront. Redémarrez l’application pour réessayer." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "URL du serveur" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Commencer l’identification" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Certificat auto-signé" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Il semble que vous utilisiez un certificat SSL auto-signé, ce qui fait que " "l’identité du serveur n’est pas vérifiée. Si c’est le cas, veuillez suivre " "les instructions de la F.A.Q. pour fournir un fichier de chaîne d’autorité " "de certification." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Ouvrir la F.A.Q." #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Connexion établie" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Fait" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Terminer la configuration" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Interface" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Utiliser une police monospace" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Vérification orthographique" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Changez la langue via le menu contextuel de l’éditeur" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Barre supérieure" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Limiter la longueur des lignes" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Principalement pour un usage sur ordinateur. Ajustez avec les touches Ctrl + " "↑ et Ctrl + ↓." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Détecter la syntaxe" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "Requis pour le surlignage et le formatage syntaxique (barre d’outils et " "raccourcis clavier). Désactiver pour une légère amélioration des " "performances." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Thème" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Barre de formatage" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Activer la vue formatée" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Désactiver pour réduire le délai de démarrage" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Ouvrir avec une vue formatée" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "" "L’activation de cette option ouvrira toutes les notes dans un rendu markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Prise en charge des équations mathématiques" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Diminue quelque peu les performances du moteur de rendu" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Moteur de rendu utilisant une police monospace" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Ratio proportionnel à la taille de la police monospace" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "Dans la vue du rendu. Utiliser 1 pour ne faire aucun ajustement." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Garder le moteur de rendu en mémoire" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "" "Conversions ultérieures plus rapides pour une utilisation plus importante de " "la mémoire" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Épingler la barre latérale" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Sur ordinateur, lorsqu’il y a de la place" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Style des étiquettes de catégories" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Données" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Reset Database" msgstr "Réinitialiser la base de données" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Delete all notes from the local database. The app will quit." msgstr "" "Supprimer toutes les notes de la base de données locale. L’application se " "fermera." #. Translators: Button #: data/ui/preferences_dialog.ui:178 iotas/preferences_dialog.py:339 msgid "Reset" msgstr "Réinitialiser" #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "Déconnecter Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Déconnecte de Nextcloud Notes. Toutes les notes seront supprimées et " "l’application s'arrêtera." #. Translators: Button #: data/ui/preferences_dialog.ui:199 iotas/preferences_dialog.py:360 msgid "Disconnect" msgstr "Déconnexion" #. Translators: Title #: data/ui/preferences_dialog.ui:217 msgid "Debug" msgstr "Débogage" #. Translators: Title #: data/ui/preferences_dialog.ui:223 msgid "Clear Sync Timestamp" msgstr "Effacer l’horodatage de la synchronisation" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:225 msgid "Forces a pull of all notes from the sync server" msgstr "Force une extraction de toutes les notes du serveur de synchronisation" #. Translators: Button #: data/ui/preferences_dialog.ui:232 msgid "Clear" msgstr "Effacer" #. Translators: Button #: data/ui/selection_header_bar.ui:32 msgid "Delete Selected" msgstr "Supprimer la sélection" #. Translators: Button #: data/ui/selection_header_bar.ui:43 msgid "Toggle Favorite for Selected" msgstr "Mettre la sélection en favoris" #. Translators: Button #: data/ui/selection_header_bar.ui:51 msgid "Change Category for Selected" msgstr "Changer la catégorie de la sélection" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Fermer les catégories" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Catégories" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Insérer un tableau" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Créer" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Suivre le thème du système" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Style clair" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Style sombre" #. Translators: Description, CLI option #: iotas/application.py:266 msgid "Create a note" msgstr "Créer une note" #. Translators: Description, CLI option #: iotas/application.py:275 msgid "Create a backup" msgstr "Créer une sauvegarde" #. Translators: Description, CLI option #: iotas/application.py:284 msgid "Restore a backup" msgstr "Restaurer une sauvegarde" #. Translators: Description, CLI option #: iotas/application.py:293 msgid "Display backup path" msgstr "Afficher l’emplacement de sauvegarde" #. Translators: Description, CLI option #: iotas/application.py:302 msgid "Display path for custom server SSL CA chain file" msgstr "" "Afficher le chemin d’accès au fichier chaîne de l’autorité de certification " "SSL pour le serveur personnalisé" #. Translators: Description, CLI option #: iotas/application.py:311 msgid "Toggle display of extended preferences in UI" msgstr "Basculer l’affichage des préférences avancées dans l’interface" #. Translators: Description, CLI option #: iotas/application.py:320 msgid "Quit any running instance" msgstr "Quitter toute instance en cours" #. Translators: Description, CLI option #: iotas/application.py:329 msgid "Enable debug logging and functions" msgstr "Activer le journal et les fonctions de débogage" #. Translators: Description, CLI option #: iotas/application.py:338 msgid "Open note by id" msgstr "Ouvrir une note par identifiant" #. Translators: Description, CLI option #: iotas/application.py:347 msgid "Search in notes" msgstr "Rechercher dans les notes" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:203 msgid "RESTORATION REMOTE ID CLASH" msgstr "CONFLIT D’IDENTIFIANT DISTANT RESTAURATION" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:221 msgid "RESTORATION TITLE CLASH" msgstr "CONFLIT DE TITRE RESTAURATION" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Toutes les notes" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Non catégorisées" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:883 #, python-brace-format msgid "Line length now {0}px" msgstr "Longueur des lignes à {0}px" #. Translators: Description, notification #: iotas/editor.py:889 msgid "Line length limit disabled" msgstr "Limite de longueur de ligne" #: iotas/editor.py:1494 msgid "Opening link in browser" msgstr "Ouverture du lien dans le navigateur" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} sur {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:99 msgid "Exported to {}" msgstr "Exporté vers {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:112 msgid "Failed to export to {}" msgstr "Échec de l’export vers {}" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:198 msgid "{} notes deleted" msgstr "{} notes supprimées" #. Translators: Description, notification #: iotas/index.py:201 msgid "Note deleted" msgstr "Note supprimée" #. Translators: Button #: iotas/index.py:206 msgid "Undo" msgstr "Annuler" #. Translators: Description, notification #: iotas/index.py:244 msgid "Sync conflict with note being edited" msgstr "Conflit de synchronisation avec la note éditée" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:252 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Échec de l’accès à Secret Service. Assurez-vous d’avoir un fournisseur comme " "gnome-keyring qui a une configuration de trousseau par défaut qui est " "déverrouillée." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:484 msgid "Syncing" msgstr "Synchronisation" #. Translators: Description, notification, {} is a number #: iotas/index.py:503 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} changement" msgstr[1] "{} changements" #. Translators: Description, notification #: iotas/index.py:519 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "" "Échec de la synchronisation. L’appli Nextcloud Notes est-elle installée sur " "le serveur ?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:616 msgid "Loading" msgstr "Chargement" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Insérer un lien" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Modifier le lien" #. Translators: Title #: iotas/nextcloud_login_dialog.py:107 msgid "Updating Notes" msgstr "Mise à jour des notes" #. Translators: Title #: iotas/nextcloud_login_dialog.py:111 msgid "Performing Initial Transfer" msgstr "Exécution du premier transfert" #. Translators: Title #: iotas/nextcloud_login_dialog.py:165 msgid "Connecting" msgstr "Connexion" #. Translators: Title #: iotas/nextcloud_login_dialog.py:187 msgid "Waiting for Login" msgstr "En attente d’identification" #. Translators: Description #: iotas/nextcloud_login_dialog.py:189 msgid "Complete the authentication in your browser" msgstr "Veuillez terminer le processus d’identification dans votre navigateur" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:205 msgid "Failed to start login with possible certificate issue" msgstr "" "Échec du lancement de la connexion, avec une possible erreur de certificat" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:208 msgid "Failed to start login. Wrong address?" msgstr "Échec du lancement de la connexion. Adresse erronée ?" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:72 iotas/preferences_dialog.py:127 msgid "Disabled" msgstr "Désactivé" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:100 msgid "Muted" msgstr "Discret" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:102 msgid "Blue" msgstr "Bleu" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:104 msgid "Orange" msgstr "Orange" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:106 msgid "Red" msgstr "Rouge" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:108 msgid "None" msgstr "Aucun" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:121 iotas/preferences_dialog.py:141 msgid "Always Visible" msgstr "Toujours visible" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:123 iotas/preferences_dialog.py:143 msgid "Automatically Hide" msgstr "Masquer automatiquement" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:125 iotas/preferences_dialog.py:145 msgid "Auto Hide When Fullscreen" msgstr "Masquer automatiquement en plein écran" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:278 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Réduction dans {0} pressions" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Extending in {0} presses" msgstr "Extension dans {0} pressions" #. Translators: Description, notification #: iotas/preferences_dialog.py:286 msgid "Extended hidden" msgstr "Extension masquée" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended shown" msgstr "Extension affichée" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:312 msgid "Hiding discouraged on mobile" msgstr "Masquage déconseillé sur mobile" #. Translators: Title #: iotas/preferences_dialog.py:332 msgid "Reset Database?" msgstr "Réinitialiser la base de données ?" #. Translators: Description #: iotas/preferences_dialog.py:334 msgid "All notes will be deleted. Continue with the reset?" msgstr "Toutes les notes seront supprimées. Continuer la réinitialisation ?" #. Translators: Title #: iotas/preferences_dialog.py:353 msgid "Disconnect Nextcloud?" msgstr "Déconnecter Nextcloud ?" #. Translators: Description #: iotas/preferences_dialog.py:355 msgid "All notes will be removed. Do you want to sign out?" msgstr "Toutes les notes seront supprimées. Souhaitez-vous vous déconnecter ?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Impossible de changer la catégorie de la note en lecture seule" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} sélectionnée(s)" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:499 msgid "SYNC CONFLICT" msgstr "CONFLIT DE SYNCHRONISATION" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Erreur" #~ msgid "Return to Index" #~ msgstr "Retour vers l’index" #~ msgid "Line length limit already disabled" #~ msgstr "Limite de longueur de ligne déjà désactivée" #, python-brace-format #~ msgid "Font size now {0}pt" #~ msgstr "Taille de police à {0}pt" #~ msgid "Read-Only Note" #~ msgstr "Note en lecture seule" #~ msgid "Waiting for completion of login in browser" #~ msgstr "Attente de la complétion de la connexion dans le navigateur" #~ msgid "Syntax Theme" #~ msgstr "Thème syntaxique" #~ msgid "Finish" #~ msgstr "Terminer" #~ msgid "Auto Hide" #~ msgstr "Masquer automatiquement" #~ msgid "" #~ "Why \"Iotas\"? An iota is a little bit and this app is designed for " #~ "jotting down little things on little devices. Iota stems from the same " #~ "Greek word as jot and is commonly used in negative statements eg. \"not " #~ "one iota of …\", but we think the word has more to give. Maybe somebody " #~ "will take note?" #~ msgstr "" #~ "Pourquoi « Iotas » ? Un iota, c’est un petit peu et cette application est " #~ "conçue pour noter de petites choses sur de petits appareils. Iota vient " #~ "du même mot grec que « jot » (prendre note, en anglais) et est couramment " #~ "utilisé dans un sens négatif, par exemple « pas un iota de ... », mais " #~ "nous pensons que ce mot a plus à offrir. Peut-être que quelqu’un en " #~ "prendra note ?" #~ msgid "Let's get started" #~ msgstr "Commençons" #~ msgid "Add new feeds via URL" #~ msgstr "Ajouter de nouveaux flux via une URL" #~ msgid "Import an OPML file" #~ msgstr "Importer un fichier OPML" #~ msgid "Go back" #~ msgstr "Retour" #~ msgid "Highlight Syntax" #~ msgstr "Mise en évidence syntaxique" #~ msgid "Disable for slightly improved performance." #~ msgstr "Désactiver pour améliorer quelque peu les performances." #~ msgid "Editor with plain text" #~ msgstr "Éditeur avec texte brut" #~ msgid "1 change" #~ msgstr "1 changement" #~ msgid "notes;nextcloud;base;" #~ msgstr "notes;nextcloud;base;" #~ msgid "" #~ "Iotas is a simple note taking app with mobile-first design and a focus on " #~ "sync with Nextcloud Notes." #~ msgstr "" #~ "Iotas est une application de prise de notes simple, conçue pour mobiles " #~ "et axée sur la synchronisation avec Nextcloud Notes." #~ msgid "Although simple by design there are a few features" #~ msgstr "" #~ "Bien que conçue de manière simple, l’application contient quelques " #~ "fonctionnalités" #~ msgid "Basic search" #~ msgstr "Recherche basique" #~ msgid "Please quit the running instance of Iotas before creating the backup" #~ msgstr "" #~ "Veuillez quitter l’instance en cours d’exécution de Iotas avant de créer " #~ "la sauvegarde" #~ msgid "" #~ "Please quit the running instance of Iotas before restoring the backup" #~ msgstr "" #~ "Veuillez quitter l’instance en cours d’exécution de Iotas avant de " #~ "restaurer la sauvegarde" #~ msgid "No running instance found" #~ msgstr "Aucune instance en cours détectée" #~ msgid "Hiding extended preferences" #~ msgstr "Masquage des préférences avancées" #~ msgid "Showing extended preferences" #~ msgstr "Affichage des préférences avancées" #, python-brace-format #~ msgid "Failed to create backup directory at {0}: {1}" #~ msgstr "Échec de la création du répertoire de sauvegarde à {0} : {1}" #~ msgid "Failed to move previous backup to archive path" #~ msgstr "" #~ "Échec du déplacement de la sauvegarde précédente vers le chemin d’archive" #~ msgid "Backup created at {}" #~ msgstr "Sauvegarde créée dans {}" #~ msgid "" #~ "Backup restoration isn't possible with Nextcloud Notes sync configured" #~ msgstr "" #~ "La restauration de sauvegardes n’est pas possible quand une " #~ "synchronisation Nextcloud Notes est configurée" #~ msgid "Backup failed" #~ msgstr "Échec de la sauvegarde" #~ msgid "No backup exists at {}" #~ msgstr "Aucune sauvegarde existante dans {}" #~ msgid "Backup restoration can only be run when there are no existing notes" #~ msgstr "" #~ "La restauration de sauvegardes n’est possible que lorsqu’il n’y aucune " #~ "note existante" #~ msgid "Backup restoration failed" #~ msgstr "Échec de la restauration de la sauvegarde" #~ msgid "Backup restoration completed" #~ msgstr "Restauration de la sauvegarde terminée" #, python-brace-format #~ msgid "Failed to write metadata to {0}: {1}" #~ msgstr "Impossible d’écrire des métadonnées dans {0} : {1}" #~ msgid "Creating {}" #~ msgstr "Création de {}" #~ msgid "Skipping restoration of existing identical note \"{}\"" #~ msgstr "Restauration de la note identique existante « {} » ignorée" #~ msgid "Duplicating note \"{}\" due to matching remote id" #~ msgstr "" #~ "Duplication de la note « {} » à cause d’un identifiant distant " #~ "correspondant" #~ msgid "Updating metadata for note \"{}\"" #~ msgstr "Mise à jour des métadonnées pour la note « {} »" #~ msgid "" #~ "Skipping note \"{}\" with matching title, contents and a newer timestamp" #~ msgstr "" #~ "Note « {} » avec un titre et un contenu correspondants et un horodatage " #~ "plus récent ignorée" #~ msgid "Duplicating note \"{}\" due to matching title but different content" #~ msgstr "" #~ "Duplication de la note « {} » à cause d’un titre identique mais avec un " #~ "contenu différent" #, python-brace-format #~ msgid "Failed to remove backup archive directory at {0}: {1}" #~ msgstr "" #~ "Échec de la suppression du répertoire de l’archive de sauvegarde dans " #~ "{0} : {1}" #, python-brace-format #~ msgid "Failed to create backup archive directory at {0}: {1}" #~ msgstr "" #~ "Échec de la création du répertoire de l’archive de sauvegarde dans {0} : " #~ "{1}" #, python-brace-format #~ msgid "Failed to move {0} into {1}: {2}" #~ msgstr "Échec du déplacement de {0} dans {1} : {2}" #~ msgid "Skipping \"{}\" due to missing content" #~ msgstr "« {} » ignoré pour cause de contenu manquant" #, python-brace-format #~ msgid "Bailing \"{0}\" due to exceeding {1}MB" #~ msgstr "Libération de « {0} » à cause d’un dépassement de {1} MB" #, python-brace-format #~ msgid "Failed to read note content from {0}: {1}" #~ msgstr "Échec de la lecture du contenu de la note depuis {0} : {1}" #, python-brace-format #~ msgid "Failed to read note metadata from {0}: {1}" #~ msgstr "Échec de la lecture des métadonnées de la note depuis {0} : {1}" #~ msgid "Failed to parse note metadata from \"{}\"" #~ msgstr "Échec de l’analyse des métadonnées de la note depuis « {} »" #~ msgid "Theme used by editor view" #~ msgstr "Thème utilisé par l’affichage de l’éditeur" #~ msgid "The GtkSourceView style scheme id" #~ msgstr "id du schéma de style de GtkSourceView" #~ msgid "First start" #~ msgstr "Premier démarrage" #~ msgid "Whether starting for the first time." #~ msgstr "Indique s’il s’agit du premier démarrage." #~ msgid "Font size" #~ msgstr "Taille de police" #~ msgid "Font used in main editor view." #~ msgstr "Police utilisée dans la vue principale de l’éditeur." #~ msgid "" #~ "Line length used in both the editor and markdown render views (pixels)." #~ msgstr "" #~ "Longueur des lignes utilisée dans l’éditeur et la vue du rendu markdown " #~ "(en pixels)" #~ msgid "Whether to use a monospace font" #~ msgstr "Indique s’il faut utiliser une police monospace" #~ msgid "" #~ "The specific fonts are sourced from GNOME's monospace and document font " #~ "settings" #~ msgstr "" #~ "Les polices spécifiques proviennent des paramètres des polices monospace " #~ "et document de GNOME" #~ msgid "Markdown render view support" #~ msgstr "Prise en charge de la vue de rendu Markdown" #~ msgid "" #~ "Whether to support showing markdown render view (a temporary performance " #~ "concession for a WebKit issue)" #~ msgstr "" #~ "Indique s’il faut prendre en charge l’affichage de la vue de rendu " #~ "markdown (une concession temporaire de performance pour un problème " #~ "WebKit)" #~ msgid "Markdown syntax highlighting" #~ msgstr "Coloration syntaxique Markdown" #~ msgid "Whether to highlight markdown syntax." #~ msgstr "Indique s’il faut mettre en évidence la syntaxe markdown." #~ msgid "Markdown WebKit process retention." #~ msgstr "Conservation du processus markdown WebKit." #~ msgid "" #~ "When enabled the WebKit process is retained between uses of the render " #~ "view, decreasing load time and increasing memory usage." #~ msgstr "" #~ "Lorsque cette option est activée, le processus WebKit est conservé entre " #~ "les utilisations de la vue de rendu, ce qui réduit le temps de chargement " #~ "et augmente l’utilisation de la mémoire." #~ msgid "Markdown TeX support for maths equations." #~ msgstr "Prise en charge de Markdown TeX pour les équations mathématiques." #~ msgid "" #~ "Whether to support rendering maths equations. Slightly increases markdown " #~ "render time." #~ msgstr "" #~ "Indique s’il faut prendre en charge le rendu des équations mathématiques. " #~ "Augmente légèrement le délai du rendu markdown." #~ msgid "Markdown monospace font." #~ msgstr "Police Markdown monospace." #~ msgid "Whether to use a monospace font for the markdown render." #~ msgstr "" #~ "Indique s’il faut utiliser une police monospace pour le rendu Markdown." #~ msgid "Markdown default to render." #~ msgstr "Affichage du rendu markdown par défaut" #~ msgid "Whether to show the render view when opening the note." #~ msgstr "" #~ "Indique s’il faut afficher la vue du rendu à l’ouverture de la note." #~ msgid "Ratio adjusting proportional to monospace font in markdown render" #~ msgstr "" #~ "Ratio ajustant les proportions de la police monospace dans le rendu " #~ "markdown" #~ msgid "A value of 1 will result in no adjustment." #~ msgstr "Une valeur de 1 équivaut à aucun ajustement." #~ msgid "Nextcloud server to sync against" #~ msgstr "Serveur Nextcloud pour la synchronisation" #~ msgid "Path to the last Nextcloud sync instance." #~ msgstr "Chemin vers la dernière instance de synchronisation Nextcloud." #~ msgid "Username for the Nextcloud sync server" #~ msgstr "Nom d’utilisateur pour le serveur de synchronisation Nextcloud" #~ msgid "Login to use with the Nextcloud sync instance." #~ msgstr "" #~ "Identifiant à utiliser avec l’instance de synchronisation Nextcloud." #~ msgid "Prune threshold for Nextcloud sync" #~ msgstr "Seuil d’élagage pour la synchronisation Nextcloud" #~ msgid "" #~ "Used to reduce the number of records pulled from the Nextcloud server " #~ "during sync." #~ msgstr "" #~ "Utilisé pour réduire le nombre d’enregistrements tirés du serveur " #~ "Nextcloud pendant la synchronisation." #~ msgid "Whether to show a message on Secret Service failure" #~ msgstr "Afficher un message lors d’un échec de Secret Service" #~ msgid "" #~ "Disabling this provides for a cleaner startup if never intending to use " #~ "Nextcloud Notes sync. on a device without a Secret Service provider." #~ msgstr "" #~ "La désactivation de cette option permet un démarrage plus propre si vous " #~ "n’avez pas l’intention d’utiliser la synchronisation Nextcloud Notes sur " #~ "un appareil sans fournisseur Secret Service." #~ msgid "Whether to show a notification when syncing from the server" #~ msgstr "" #~ "Indique s’il faut afficher une notification lors de la synchronisation " #~ "depuis le serveur" #~ msgid "Useful for increasing visibility of network issues" #~ msgstr "Utile pour être informé des problèmes réseau" #~ msgid "Spelling enabled" #~ msgstr "Orthographe activée" #~ msgid "Whether spell checking is enabled." #~ msgstr "Indique si la vérification orthographique est activée." #~ msgid "Spelling language" #~ msgstr "Langage de vérification" #~ msgid "Language tag to attempt to use by default for spelling." #~ msgstr "" #~ "Balise de langue à essayer d’utiliser par défaut pour l’orthographe." #~ msgid "Colour scheme style" #~ msgstr "Style du schéma de couleurs" #~ msgid "" #~ "Choosing to follow desktop colour style or enforce dark or light visuals." #~ msgstr "" #~ "Choisir de suivre le style de couleur du bureau ou d’imposer des visuels " #~ "sombres ou clairs." #~ msgid "Sync interval" #~ msgstr "Intervalle de synchronisation" #~ msgid "Interval between pulling from the Nextcloud sync server (seconds)." #~ msgstr "" #~ "Intervalle entre les extractions depuis le serveur de synchronisation " #~ "Nextcloud (en secondes)." #~ msgid "Window size" #~ msgstr "Taille de la fenêtre" #~ msgid "Remember the window size." #~ msgstr "Se souvenir de la taille de la fenêtre." #~ msgid "Whether to persist the index sidebar in large windows" #~ msgstr "" #~ "Persistance ou non de la barre latérale de l’index dans les grandes " #~ "fenêtres" #~ msgid "" #~ "Whether to the index sidebar is permanently present in large windows " #~ "(generally desktop)" #~ msgstr "" #~ "Indique si la barre latérale de l’index est toujours présente ou non dans " #~ "les grandes fenêtres (généralement sur ordinateur)" #~ msgid "Whether to automatically hide the editor headerbar" #~ msgstr "" #~ "Indique s’il faut automatiquement masquer la barre supérieure de l’éditeur" #~ msgid "Setting to true automatically hides the editor headerbar" #~ msgstr "" #~ "Si cette option est activée, la barre supérieure de l’éditeur sera " #~ "masquée automatiquement" #~ msgid "Whether to hide the editor headerbar when fullscreen" #~ msgstr "" #~ "Indique s’il faut masquer la barre supérieure de l’éditeur en plein écran" #~ msgid "" #~ "Setting to true automatically hides the editor headerbar entering " #~ "fullscreen mode" #~ msgstr "" #~ "Si cette option est activée, la barre supérieure de l’éditeur sera " #~ "masquée en mode plein écran" #~ msgid "File extension for backed up notes" #~ msgstr "Extension de fichier pour les notes sauvegardées" #~ msgid "File extension added to each note when exporting for backup." #~ msgstr "" #~ "Extension de fichier ajoutée à chaque note lors d’une exportation pour " #~ "sauvegarde." #~ msgid "Index category style" #~ msgstr "Style de l’index de catégories" #~ msgid "Style options for category labels on index rows" #~ msgstr "" #~ "Options de style pour les étiquettes de catégories sur les lignes de " #~ "l’index" #~ msgid "Last launched version" #~ msgstr "Dernière version lancée" #~ msgid "The last version of the app that was run. Shouldn't be edited." #~ msgstr "" #~ "La dernière version de l’application qui a été exécutée. Ne devrait pas " #~ "être modifiée." #~ msgid "Directory last used for export" #~ msgstr "Dernier répertoire utilisé pour l’export" #~ msgid "" #~ "Only applies to instances with filesystem access. Shouldn't be edited." #~ msgstr "" #~ "Ne s’applique qu’aux instances ayant accès au système de fichiers. Ne " #~ "devrait pas être modifié." #~ msgid "Extra pandoc formats for exporting" #~ msgstr "Formats pandoc supplémentaires pour l’export" #~ msgid "See README for definition" #~ msgstr "Voir le fichier README pour la définition" #~ msgid "Perform full server refresh" #~ msgstr "Actualisation complète depuis le serveur" #~ msgid "" #~ "Whether to run a full update of all notes from the server. Used for eg. " #~ "schema migrations." #~ msgstr "" #~ "Indique s’il faut faire une mise à jour complète de toutes les notes " #~ "depuis le serveur." #~ msgid "Whether to show extended preferences" #~ msgstr "Indique s’il faut afficher les préférences avancées" #~ msgid "When enabled an excessive number of preferences are shown." #~ msgstr "" #~ "Si cette option est activée un nombre important de préférences sera " #~ "affiché." #~ msgid "Searching" #~ msgstr "Recherche" #~ msgid "Sync. with Nextcloud Notes" #~ msgstr "Synchronisation avec Nextcloud Notes" #~ msgid "Index on mobile" #~ msgstr "Index sur mobile" #~ msgid "Index on desktop" #~ msgstr "Index sur ordinateur" #~ msgid "Limited functionality on mobile for now." #~ msgstr "Fonctionnalité limitée sur mobile pour le moment." #~ msgid "" #~ "Note: It's fairly early days in development here, so please expect a few " #~ "rough edges." #~ msgstr "" #~ "Note : l’application étant toute récente et en cours de développement, il " #~ "faut vous attendre à quelques couacs." #~ msgid "Optional markdown syntax highlighting and rendered view" #~ msgstr "" #~ "Mise en évidence de la syntaxe markdown et affichage du rendu optionels" #~ msgid "Follow system-wide dark style preference or make own choice" #~ msgstr "" #~ "Suivre les préférences du système pour le style sombre ou faire son " #~ "propre choix" #~ msgid "Mobile editor" #~ msgstr "Éditeur mobile" #~ msgid "Desktop index" #~ msgstr "Index de bureau" #~ msgid "Desktop index dark style" #~ msgstr "Style sombre de l’index de bureau" #~ msgid "Sync. offline" #~ msgstr "Sync. hors-ligne" #~ msgid "Add Favorite" #~ msgstr "Ajouter aux favoris" #~ msgid "Remove Favorite" #~ msgstr "Retirer des favoris" #~ msgid "All" #~ msgstr "Toutes" #~ msgid "Current obvious feature omissions" #~ msgstr "Fonctionnalités intéressantes manquantes" #~ msgid "Load the Rest" #~ msgstr "Charger le reste" #~ msgid "The Rest" #~ msgstr "Le reste" #~ msgid "Sync" #~ msgstr "Synchronisation" #~ msgid "Temporary Debug Functions" #~ msgstr "Fonctions de débogage temporaires" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/he.po000066400000000000000000001347431507102636600217700ustar00rootroot00000000000000# Hebrew translation for Iotas. # Copyright (C) 2025 Iotas's COPYRIGHT HOLDER # This file is distributed under the same license as the Iotas package. # Yaron Shahrabani , 2025. # msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/-/issues\n" "POT-Creation-Date: 2025-07-29 08:18+0000\n" "PO-Revision-Date: 2025-08-02 23:58+0300\n" "Last-Translator: Yaron Shahrabani \n" "Language-Team: Hebrew \n" "Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==2 ? 1 : n>10 && n%10==0 ? 2 : 3);\n" "X-Generator: Poedit 3.6\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "כתיבת פתקיות פשוטה עם Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "" "פתקיות;nextcloud;נקסטקלאוד;מזערי;מינימליסטי;פשוט;פשטני;הסחה;הסחת " "דעת;עורך;ממוקד;מיקוד;טקסט;כתב;כתיבה;מכתבה;מרקדאון;markdown;גנום;gnome;gtk;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "פתקית חדשה" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "כתיבת פתקיות פשוטה" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "Iotas aims to provide distraction-free note taking via its mobile-first design." msgstr "המטרה של Iotas היא לספק חוויית רישום פתקיות ללא הסחות דעת דרך עיצוב מונחה מכשירים ניידים." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "יכולות" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "סנכרון מהיר מול Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "עריכת פתקיות ללא אינטרנט, תסתנכרנה עם החיבור" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "עריכת וסינון קטגוריות" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "מועדפים" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "בדיקת איות" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "חיפוש באוסף או בפתקיות הפרטניות" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "מצב מיקוד עם הסתרה של כותרת העורך וסרגלי העיצוב כרשות" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "בתצוגה מקדימה: ייצוא ל־PDF,‏ ODT ו־HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "עיצוב גמיש, מה שמאפשר להשתמש ב־Iotas במחשב בבית כמו במכשיר הנייד" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "חיפוש ישירות ממעטפת GNOME" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "גיבוי ושחזור פתקיות (משורת הפקודות, לשימוש ללא סנכרון)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "היכולת להחליף את גודל הגופן ולעבור בין סגנון רגיל לרוחב אחיד ולהפך" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "כתיבת Markdown נתמכת אך היא בגדר רשות, היא מספקת" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "עיצוב בעזרת סרגלי כלים וקיצורי מקלדת" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "הדגשת תחביר עם ערכות עיצוב" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "תצוגה מסוגננת" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "היכולת לסמן ביצוע ברשימת משימות מהתצוגה המסוגננת" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "פרטים מעט טכניים יותר, למי שזה מעניין אותו" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "הסנכרון של Nextcloud Notes מתבצע דרך REST API, במקום דרך WebDAV מה שהופך אותו למהיר יותר" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "זוהתה סתירת סנכרון בסיסית" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "הפתקיות נשמרות באופן רציף" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "אוספים גדולים של פתקיות נטענים באופן חלקי כדי להאיץ את העלייה" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without reinventing the wheel. " "Plain files can be retrieved by making a backup (CLI)." msgstr "" "פתקיות מאוחסנות ב־SQLite, בכך מתאפשר חיפוש מהיר (FTS) מבלי להמציא את הגלגל מחדש. אפשר למשוך " "קבצים על ידי יצירת גיבוי (שורת הפקודות)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 data/ui/keyboard_shortcuts_window.ui:12 #: data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "מפתח" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "עורך עם Markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Markdown שעבר עיבוד" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "מפתח בסגנון כהה" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "בנייד" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "ירון שהרבני " #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "הסגת השינויים" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "החלת השינויים" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "החלה" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "פינוי והחלה" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "איתור" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "חזרה" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 data/ui/keyboard_shortcuts_window.ui:287 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "התוצאה הקודמת" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 data/ui/keyboard_shortcuts_window.ui:280 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "התוצאה הבאה" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_window.ui:273 msgid "Replace" msgstr "החלפה" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:300 msgid "Focus Mode" msgstr "מצב מיקוד" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "איתור והחלפה…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "דילוג אל…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "עריכת כותרת…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "החלפת תיקייה…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "מחיקה" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "ייצוא…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "חזרה לפתקיות" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "הפתקית היא לקריאה בלבד" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "תפריט עורך" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle Markdown Render" msgstr "הפעלת/כיבוי עיבוד Markdown" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "עריכת פתקית" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "מנוע העיבוד נטען" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:338 iotas/preferences_dialog.py:359 msgid "Cancel" msgstr "ביטול" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As..." msgstr "ייצוא בתור…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Exporting..." msgstr "מתבצע ייצוא…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:71 data/ui/export_dialog.ui:99 data/ui/outline_dialog.ui:104 #: iotas/ui_utils.py:92 msgid "Close" msgstr "סגירה" #. Translators: Button #: data/ui/export_dialog.ui:78 msgid "Show" msgstr "הצגה" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "ברוך בואך ל־Iotas (יוטאס)" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "ניתן להשתמש בסרגל הכותרת שלעיל כדי…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "להוסיף פתקית" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "לסנכרן מול Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "להתרחק" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "להתקרב" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_window.ui:239 msgid "Horizontal Rule" msgstr "קו הפרדה אופקי" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_window.ui:246 msgid "Quote" msgstr "ציטוט" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_window.ui:225 msgid "Code" msgstr "קוד" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_window.ui:253 msgid "Table" msgstr "טבלה" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "רמה 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "רמה 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "רמה 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "רמה 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "הסרה" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_window.ui:183 msgid "Heading" msgstr "כותרת" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_window.ui:169 msgid "Bold" msgstr "מודגש" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_window.ui:176 msgid "Italic" msgstr "נטוי" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 data/ui/keyboard_shortcuts_window.ui:232 msgid "Strikethrough" msgstr "קו חוצה" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 data/ui/keyboard_shortcuts_window.ui:190 msgid "Unordered List" msgstr "רשימה ללא סדר" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 data/ui/keyboard_shortcuts_window.ui:197 msgid "Ordered List" msgstr "רשימה מסודרת" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 data/ui/keyboard_shortcuts_window.ui:204 msgid "Checkbox" msgstr "תיבת סימון" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 data/ui/keyboard_shortcuts_window.ui:218 msgid "Link" msgstr "קישור" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "רענון" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "העדפות" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "קיצורי מקלדת" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "על Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "תפריט ראשי" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "היום" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "אתמול" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "השבוע" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "החודש" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "החודש שעבר" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "להציג חודשים קודמים" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "לפני החודש הקודם" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "להציג עוד" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "פתיחת קטגוריות" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:266 msgid "Search" msgstr "חיפוש" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "בחירת פתקיות" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "החיבור לשרת מנותק" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to reauthenticate with your " "Nextcloud server" msgstr "" "עקב שינויים מאחורי הקלעים (מזהה יישום חדש) יש ליצור אימות מחדש של Iotas מול שרת ה־Nextcloud שלך" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "אימות" #. Translators: Description #: data/ui/index.ui:102 msgid "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "לא ניתן למשוך את אסימון האימות לסנכרון מול Nextcloud Notes" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "התעלמות" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "רשימת הפתקיות ריקה" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "נא למלא ביטוי לחיפוש" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "אין תוצאות חיפוש" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create New Note" msgstr "יצירת פתקית חדשה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show Sidebar" msgstr "הצגת סרגל צד" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete Note" msgstr "מחיקת פתקית" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move Up List" msgstr "העלאה במעלה הרשימה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move Down List" msgstr "הורדה במורד הרשימה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start Selection" msgstr "התחלת בחירה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset Filter" msgstr "איפוס המסנן" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open First Search Result" msgstr "פתיחת תוצאת החיפוש הראשונה" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "עורך" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit Title" msgstr "עריכת כותרת" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_window.ui:93 iotas/export_dialog.py:133 msgid "Export" msgstr "ייצוא" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create New Note Including Selection" msgstr "יצירת פתקית חדשה כולל הבחירה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Change Category" msgstr "החלפת קטגוריה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo Typing" msgstr "הסגת הקלדה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo Typing" msgstr "שחזור הקלדה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Insert Emoji" msgstr "הוספת אמוג׳י" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Focus Text View" msgstr "התמקדות על תצוגת טקסט" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Focus Header Bar" msgstr "התמקדות על סרגל הכותרת" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:156 msgid "Focus Formatting Bar" msgstr "התמקדות על סרגל העיצוב" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:164 msgid "Formatting" msgstr "עיצוב" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:211 msgid "Toggle Checkbox" msgstr "ביטול/סימון תיבה" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:261 msgid "Editor Search" msgstr "חיפוש בעורך" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:295 msgid "Editor Appearance" msgstr "המראה של העורך" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:307 msgid "Increase Line Length" msgstr "הארכת השורה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:314 msgid "Decrease Line Length" msgstr "קיצור השורה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:321 msgid "Increase Font Size" msgstr "הגדלת הכתב" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:328 msgid "Decrease Font Size" msgstr "הקטנת הכתב" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:336 msgid "General" msgstr "כללי" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:341 msgid "Toggle Fullscreen" msgstr "מסך מלא/רגיל" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:348 msgid "Show Preferences" msgstr "הצגת העדפות" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:355 msgid "Show Shortcuts" msgstr "הצגת קיצורי מקלדת" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:362 msgid "Open Previous Note" msgstr "פתיחת הפתקית הקודמת" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:369 msgid "Go Back" msgstr "חזרה" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:376 msgid "Quit" msgstr "יציאה" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "כתובת" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "טקסט" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "הגדרת Nextcloud Notes" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "Press Continue to provide your Nextcloud server address and login via a web browser" msgstr "יש ללחוץ על המשך כדי לספק את כתובת שרת ה־Nextcloud שלך ולהיכנס דרך דפדפן" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "להמשיך" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "להמשיך למילוי כתובת" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "שירות הסודות לא זמין" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. Ensure you have a " "provider such as gnome-keyring. A default keyring needs to be setup, and that keyring unlocked. " "Most desktop environments will provide this for you. Restart the app to try again." msgstr "" "לא ניתן לגשת לשירות החשאי לאחסון פרטי אימות. נא לוודא שיש לך ספק כגון gnome-keyring (מחזיק " "המפתחות של GNOME). יש להקים מחזיק מפתחות כברירת מחדל ומחזיק המפתחות הזה צריך להיות משוחרר " "מנעילה. רוב סביבות שולחן העבודה תספקנה את זה עבורך. יש להפעיל את היישום מחדש כדי לנסות שוב." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "כתובת שרת" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "התחלת כניסה" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "אישור בחתימה עצמית" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server identity not being " "verified. If this is expected please follow the instructions in the FAQ to provide a CA chain " "file." msgstr "" "נראה שאישור ה־SSL בשימוש נחתם עצמאית מה שגורם לכשל באימות זהות השרת. אם זאת התנהגות רצויה יש " "לעקוב אחר ההנחיות בשו״ת כדי לספק קובץ שרשרת רשות אישורים (CA chain)." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "פתיחת השו״ת" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "החיבור הוקם" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "הושלם" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "השלמת הגדרת סנכרון" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "מתאר" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "אין כותרות שתואמות למסנן" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "לא נמצאו כותרות למתאר" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "מנשק" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "להשתמש בגופן ברוחב אחיד" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "בדיקת איות" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "אפשר להחליף את השפה דרך תפריט ההקשר של העורך" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "סרגל כותרת" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "הגבלת אורך שורות" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "במיוחד לשולחן עבודה. יש להשתמש ב־Ctrl + ↑ וב־Ctrl + ↓ במקלדת כדי לכוון במדויק." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "זיהוי התחביר" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard shortcuts). Disable for " "slightly improved performance." msgstr "נחוץ להדגשת תחביר ועיצוב (קיצורי מקלדת וסרגלי כלים). יש להשבית כדי לשפר במעט את הביצועים." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "ערכת עיצוב" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "סרגל עיצוב" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "הפעלת תצוגה מסוגננת" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "יש להשבית כדי להריץ את זמן העלייה" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "פתיחה בתצוגה מסוגננת" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "הפעלת האפשרות פותחת את כל הפתקיות כאילו כתובות ב־Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "תמיכה במשוואות מתמטיות" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "פוגע קלות בביצועי העיבוד" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "לעבד באמצעות גופן ברוחב אחיד" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "יחס גודל גופן יחסי לרוחב אחיד" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "במצב עיבוד. להשתמש ב־1 כדי לא לכוונן." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "החזקת המנוע בזיכרון" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "המרות רציפות מהירות יותר להגברת השימוש בזיכרון" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "נעיצת סרגל צד" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "בשולחן העבודה, כשאין מקום" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "סגנון תוויות קטגוריות" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "נתונים" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Reset Database" msgstr "איפוס מסד נתונים" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Delete all notes from the local database. The app will quit." msgstr "למחוק את כל הפתקיות ממסד הנתונים המקומי. היישום ייסגר." #. Translators: Button #: data/ui/preferences_dialog.ui:178 iotas/preferences_dialog.py:340 msgid "Reset" msgstr "איפוס" #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "ניתוק Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "Signs out from Nextcloud Notes. All notes will be removed and the app will quit." msgstr "יציאה מ־Nextcloud Notes. כל הפתקיות תוסרנה והיישום ייסגר." #. Translators: Button #: data/ui/preferences_dialog.ui:199 iotas/preferences_dialog.py:361 msgid "Disconnect" msgstr "ניתוק" #. Translators: Title #: data/ui/preferences_dialog.ui:217 msgid "Debug" msgstr "ניפוי שגיאות" #. Translators: Title #: data/ui/preferences_dialog.ui:223 msgid "Clear Sync Timestamp" msgstr "פינוי חותמת הזמן של הסנכרון" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:225 msgid "Forces a pull of all notes from the sync server" msgstr "אילוץ משיכה של כל הפתקיות משרת הסנכרון" #. Translators: Button #: data/ui/preferences_dialog.ui:232 msgid "Clear" msgstr "פינוי" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "מחיקת הנבחרות" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "לסמן/לבטל סימון לנבחרות" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "להחליף את התיקיות של הנבחרות" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "סגירת קטגוריות" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "קטגוריות" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "הוספת טבלה" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "יצירה" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "כמו המערכת" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "סגנון בהיר" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "סגנון כהה" #. Translators: Description, CLI option #: iotas/application.py:300 msgid "Create a note" msgstr "יצירת פתקית" #. Translators: Description, CLI option #: iotas/application.py:309 msgid "Create a backup" msgstr "יצירת גיבוי" #. Translators: Description, CLI option #: iotas/application.py:318 msgid "Restore a backup" msgstr "שחזור גיבוי" #. Translators: Description, CLI option #: iotas/application.py:327 msgid "Display backup path" msgstr "הצגת נתיב גיבוי" #. Translators: Description, CLI option #: iotas/application.py:336 msgid "Display path for custom server SSL CA chain file" msgstr "הצגת נתיב לקובץ שרשור רשויות אישורי SSL" #. Translators: Description, CLI option #: iotas/application.py:345 msgid "Toggle display of extended preferences in UI" msgstr "הצגת/הסתרת העדפות מורחבות במנשק המשתמש" #. Translators: Description, CLI option #: iotas/application.py:354 msgid "Quit any running instance" msgstr "יציאה מעותק פעיל" #. Translators: Description, CLI option #: iotas/application.py:363 msgid "Enable debug logging and functions" msgstr "הפעלת תיעוד ופונקציות לניפוי שגיאות" #. Translators: Description, CLI option #: iotas/application.py:372 msgid "Open note by id" msgstr "פתיחת פתקית לפי מזהה" #. Translators: Description, CLI option #: iotas/application.py:381 msgid "Search in notes" msgstr "חיפוש בפתקיות" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "סתירת מזהה מרוחק בשחזור" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "סתירת כותרת בשחזור" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "כל הפתקיות" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "ללא קטגוריה" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:958 #, python-brace-format msgid "Line length now {0}px" msgstr "אורך השורה מעתה הוא {0} פיקסלים" #. Translators: Description, notification #: iotas/editor.py:964 msgid "Line length limit disabled" msgstr "מגבלת אורך השורה מושבתת" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "הקישור נפתח בדפדפן" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} מתוך {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:103 msgid "Exported to {}" msgstr "יוצא אל {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:116 msgid "Failed to export to {}" msgstr "הייצוא אל {} נכשל" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:203 msgid "{} notes deleted" msgstr "{} פתקיות נמחקו" #. Translators: Description, notification #: iotas/index.py:206 msgid "Note deleted" msgstr "הפתקית נמחקה" #. Translators: Button #: iotas/index.py:211 msgid "Undo" msgstr "ביטול" #. Translators: Description, notification #: iotas/index.py:249 msgid "Sync conflict with note being edited" msgstr "שגיאת סנכרון בזמן עריכת פתקית" #. Translators: Description, notification #: iotas/index.py:256 msgid "The note being edited was remotely deleted" msgstr "הפתקית שנערכת נמחקה בצד המרוחק" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:264 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-keyring which has a " "default keyring setup that is unlocked." msgstr "" "הגישה שירות הסודות נכשלה. נא לוודא שיש לך ספק כמו gnome-keyring שיש לו הגדרת מחזיק מפתחות " "כברירת מחדל ושהוא לא נעול." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:498 msgid "Syncing" msgstr "מתבצע סנכרון" #. Translators: Description, notification, {} is a number #: iotas/index.py:517 msgid "{} change" msgid_plural "{} changes" msgstr[0] "שינוי" msgstr[1] "שני שינויים" msgstr[2] "{} שינויים" msgstr[3] "{} שינויים" #. Translators: Description, notification #: iotas/index.py:533 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "סנכרון כושל. האם יישומון ה־Notes מותקן בשרת ה־Nextcloud?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:630 msgid "Loading" msgstr "בטעינה" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "הוספת קישור" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "עריכת קישורים" #. Translators: Title #: iotas/nextcloud_login_dialog.py:108 msgid "Updating Notes" msgstr "הפתקיות מתעדכנות" #. Translators: Title #: iotas/nextcloud_login_dialog.py:112 msgid "Performing Initial Transfer" msgstr "מתבצעת העברה ראשונית" #. Translators: Title #: iotas/nextcloud_login_dialog.py:168 msgid "Connecting" msgstr "מתבצעת התחברות" #. Translators: Title #: iotas/nextcloud_login_dialog.py:190 msgid "Waiting for Login" msgstr "בהמתנה לכניסה למערכת" #. Translators: Description #: iotas/nextcloud_login_dialog.py:192 msgid "Complete the authentication in your browser" msgstr "נא להשלים את האימות בדפדפן שלך" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:208 msgid "Failed to start login with possible certificate issue" msgstr "התחלת הכניסה עם בעיות אישור לכאורה נכשלה" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:211 msgid "Failed to start login. Wrong address?" msgstr "התחלת הכניסה נכשלה. הכתובת שגויה?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:65 iotas/preferences_dialog.py:97 msgid "Monochrome" msgstr "חד־גוני" #. Translators: Description, a style name #: iotas/preferences_dialog.py:67 msgid "Muted Markup" msgstr "סימון מושתק" #. Translators: Description, a style name #: iotas/preferences_dialog.py:69 msgid "Bold Markup" msgstr "סימון מודגש" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:124 msgid "Disabled" msgstr "מושבת" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:99 msgid "Muted" msgstr "מושתק" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:101 msgid "Blue" msgstr "כחול" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:103 msgid "Orange" msgstr "כתום" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Red" msgstr "אדום" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "None" msgstr "ללא" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:118 iotas/preferences_dialog.py:138 msgid "Always Visible" msgstr "גלוי תמיד" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:120 iotas/preferences_dialog.py:140 msgid "Automatically Hide" msgstr "להסתיר אוטומטית" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:122 iotas/preferences_dialog.py:142 msgid "Auto Hide When Fullscreen" msgstr "להסתיר אוטומטית במסך מלא" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:273 #, python-brace-format msgid "Reducing in {0} presses" msgstr "יצומצם ב־{0} לחיצות" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:276 #, python-brace-format msgid "Extending in {0} presses" msgstr "יורחב ב־{0} לחיצות" #. Translators: Description, notification #: iotas/preferences_dialog.py:281 msgid "Extended hidden" msgstr "מורחבים מוסתרים" #. Translators: Description, notification #: iotas/preferences_dialog.py:284 msgid "Extended shown" msgstr "מורחבים מוצגים" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:313 msgid "Hiding discouraged on mobile" msgstr "הסתרה לא מומלצת במכשירים ניידים" #. Translators: Title #: iotas/preferences_dialog.py:333 msgid "Reset Database?" msgstr "לאפס את מסד הנתונים?" #. Translators: Description #: iotas/preferences_dialog.py:335 msgid "All notes will be deleted. Continue with the reset?" msgstr "כל הפתקיות תימחקנה. להמשיך באיפוס?" #. Translators: Title #: iotas/preferences_dialog.py:354 msgid "Disconnect Nextcloud?" msgstr "להתנתק מ־Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:356 msgid "All notes will be removed. Do you want to sign out?" msgstr "כל הפתקיות תוסרנה. לצאת?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "לא ניתן לשנות את הקטגוריה של פתקית לקריאה בלבד" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} נבחרו" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:506 msgid "SYNC CONFLICT" msgstr "סתירת סנכרון" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "שגיאה" #~ msgid "OK" #~ msgstr "אישור" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/hu.po000066400000000000000000001333531507102636600220040ustar00rootroot00000000000000# Hungarian translation for Iotas. # Copyright (C) 2025 Free Software Foundation, Inc. # This file is distributed under the same license as the Iotas package. # # Balázs Meskó , 2025. # Balázs Úr , 2025. msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/-/issues\n" "POT-Creation-Date: 2025-07-29 08:18+0000\n" "PO-Revision-Date: 2025-09-03 13:56+0200\n" "Last-Translator: Balázs Úr \n" "Language-Team: Hungarian \n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 24.12.3\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Egyszerű jegyzetelés a Nextcloud Jegyzetekkel" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;documen" "t;gnome;gtk;" msgstr "" "jegyzetek;nextcloud;minimális;figyelemelterelés;szerkesztő;fókuszált;szöveg;ír" "ás;markdown;dokumentum;gnome;gtk;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Új jegyzet" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Egyszerű jegyzetelés" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Az Iotas célja, hogy zavaró tényezőktől mentes jegyzetelést biztosítson mobil " "eszközökhöz tervezett megjelenéssel." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Funkciók" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Választható gyors szinkronizálás a Nextcloud Jegyzetekkel" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Kapcsolat nélküli jegyzetszerkesztés, szinkronizálás kapcsolódáskor" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Kategóriák szerkesztése és szűrése" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Kedvencek" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Helyesírás-ellenőrzés" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Keresés a gyűjteményben vagy az egyes jegyzetekben" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Fókuszmód, valamint a szerkesztő fejlécének és formázási sávjainak " "választható elrejtése" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "Előnézetben: exportálás PDF-be, ODT-be és HTML-be" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Összehangolt megjelenés, az Iotas alkalmazás asztali számítógépen és mobil esz" "közön egyaránt otthonosan érzi magát" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Keresés a GNOME Shellből" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Jegyzetek biztonsági mentése és helyreállítása (CLI-ből, szinkronizálás " "nélküli használathoz)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "" "Lehetőség a betűméret megváltoztatására és a rögzített szélességű stílus be- é" "s kikapcsolására" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "" "A Markdownban való írás támogatott, de nem kötelező, ezeket biztosítja:" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formázás eszköztárral és gyorsbillentyűkkel" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Szintaxiskiemelés témákkal" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Formázott nézet" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Lehetőség a feladatlisták kipipálása a formázott nézetből" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Kissé műszakibb részletek azoknak, akik számára érdekes lehet" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "A Nextcloud Jegyzetek szinkronizálása REST API-t használ, nem WebDAV-ot, ami g" "yorsabbá teszi" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Rendelkezik alapvető szinkronizáció-ütközési feloldással" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "A jegyzetek folyamatosan mentve vannak" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "A nagy jegyzetgyűjtemények részlegesen vannak betöltve, hogy gyorsabb legyen " "az indulás" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "A jegyzetek SQLite-ban vannak tárolva, amely gyors keresést tesz lehetővé, a " "kerék újrafeltalálása nélkül. Az egyszerű szöveges fájlok biztonsági mentés " "készítésével kérhetők le (CLI-vel)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Kezdőlap" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Szerkesztő Markdownnal" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Megjelenített Markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Kezdőlap sötét stílusban" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobil" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Meskó Balázs , 2025." #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Változtatások visszavonása" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Változtatások alkalmazása" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Alkalmaz" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Törlés és alkalmazás" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Keresés" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Vissza" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_window.ui:287 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Előző egyezés" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_window.ui:280 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Következő egyezés" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_window.ui:273 msgid "Replace" msgstr "Csere" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:300 msgid "Focus Mode" msgstr "Fókuszmód" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Keresés és csere…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Ugrás ide…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Cím szerkesztése…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Kategória megváltoztatása…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Törlés" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Exportálás…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Vissza a jegyzetekhez" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "A jegyzet csak olvasható" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Szerkesztő menü" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle Markdown Render" msgstr "Markdown-megjelenítés be- és kikapcsolása" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Jegyzet szerkesztése" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Megjelenítő motor betöltése" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:338 #: iotas/preferences_dialog.py:359 msgid "Cancel" msgstr "Mégse" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As..." msgstr "Exportálás mint…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Exporting..." msgstr "Exportálás…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:71 data/ui/export_dialog.ui:99 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Bezárás" #. Translators: Button #: data/ui/export_dialog.ui:78 msgid "Show" msgstr "Megjelenítés" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Üdvözli az Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Használja a fenti eszköztársávot…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Jegyzet hozzáadása" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Szinkronizálás a Nextcloud Jegyzetekkel" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Kicsinyítés" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Nagyítás" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_window.ui:239 msgid "Horizontal Rule" msgstr "Vízszintes vonal" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_window.ui:246 msgid "Quote" msgstr "Idézet" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_window.ui:225 msgid "Code" msgstr "Kód" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_window.ui:253 msgid "Table" msgstr "Táblázat" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "1. szint" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "2. szint" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "3. szint" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "4. szint" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Eltávolítás" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_window.ui:183 msgid "Heading" msgstr "Címsor" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_window.ui:169 msgid "Bold" msgstr "Félkövér" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_window.ui:176 msgid "Italic" msgstr "Dőlt" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_window.ui:232 msgid "Strikethrough" msgstr "Áthúzott" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_window.ui:190 msgid "Unordered List" msgstr "Rendezetlen lista" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_window.ui:197 msgid "Ordered List" msgstr "Számozott lista" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_window.ui:204 msgid "Checkbox" msgstr "Jelölőnégyzet" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_window.ui:218 msgid "Link" msgstr "Hivatkozás" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Frissítés" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Beállítások" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Gyorsbillentyűk" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Az Iotas névjegye" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Főmenü" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Ma" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Tegnap" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Ezen a héten" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Ebben a hónapban" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Múlt hónapban" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Korábbi hónapok megjelenítése" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Múlt hónap előtti hónapban" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Továbbiak megjelenítése" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Kategóriák megnyitása" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:266 msgid "Search" msgstr "Keresés" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Jegyzetek kiválasztása" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "A kiszolgálókapcsolat nem érhető el" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "A háttérben történt változtatások miatt (új alkalmazásazonosító) az Iotasnak ú" "jra kell hitelesítenie a Nextcloud-kiszolgálójával" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Hitelesítés" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "A Nextcloud Jegyzetekkel való szinkronizálás hitelesítési tokenjét nem sikerül" "t lekérni" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Eltüntetés" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "A jegyzetlista üres" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Keresési kifejezés megadása" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Nincs találat" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create New Note" msgstr "Új jegyzet létrehozása" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show Sidebar" msgstr "Oldalsáv megjelenítése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete Note" msgstr "Jegyzet törlése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move Up List" msgstr "Lista feljebb helyezése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move Down List" msgstr "Lista lejjebb helyezése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start Selection" msgstr "Kijelölés indítása" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset Filter" msgstr "Szűrő visszaállítása" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open First Search Result" msgstr "Első keresési találat megnyitása" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Szerkesztő" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit Title" msgstr "Cím szerkesztése" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_window.ui:93 iotas/export_dialog.py:133 msgid "Export" msgstr "Exportálás" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create New Note Including Selection" msgstr "Új jegyzet létrehozása a kijelöléssel" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Change Category" msgstr "Kategória megváltoztatása" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo Typing" msgstr "Gépelés visszavonása" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo Typing" msgstr "Gépelés ismétlése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Insert Emoji" msgstr "Emodzsi beszúrása" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Focus Text View" msgstr "Fókuszálás a szövegnézetre" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Focus Header Bar" msgstr "Fókuszálás a fejlécsávra" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:156 msgid "Focus Formatting Bar" msgstr "Fókuszálás a formázási sávra" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:164 msgid "Formatting" msgstr "Formázás" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:211 msgid "Toggle Checkbox" msgstr "Jelölőnégyzet be- és kikapcsolása" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:261 msgid "Editor Search" msgstr "Szerkesztő keresője" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:295 msgid "Editor Appearance" msgstr "Szerkesztő megjelenése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:307 msgid "Increase Line Length" msgstr "Vonalhossz növelése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:314 msgid "Decrease Line Length" msgstr "Vonalhossz csökkentése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:321 msgid "Increase Font Size" msgstr "Betűméret növelése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:328 msgid "Decrease Font Size" msgstr "Betűméret csökkentése" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:336 msgid "General" msgstr "Általános" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:341 msgid "Toggle Fullscreen" msgstr "Teljes képernyő be- és kikapcsolása" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:348 msgid "Show Preferences" msgstr "Beállítások megjelenítése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:355 msgid "Show Shortcuts" msgstr "Gyorsbillentyűk megjelenítése" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:362 msgid "Open Previous Note" msgstr "Előző jegyzet megnyitása" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:369 msgid "Go Back" msgstr "Vissza" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:376 msgid "Quit" msgstr "Kilépés" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "Webcím" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Szöveg" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud Jegyzetek beállítása" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Kattintson a folytatás gombra, hogy megadja a Nextcloud-kiszolgáló címét, és b" "ejelentkezzen egy webböngészőben" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Folytatás" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Folytatás a webcím megadásához" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "A titokszolgáltatás nem érhető el" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "A titokszolgáltatást nem sikerült elérni a hitelesítési adatok tárolásához. " "Győződjön meg arról, hogy van olyan szolgáltatója, mint a gnome-keyring. Be " "kell állítani és fel kell oldani egy alapértelmezett kulcstartót. A legtöbb " "asztali környezet megteszi ezt Önnek. Futtassa újra az alkalmazást, és " "próbálja újra." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Kiszolgáló webcíme" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Bejelentkezés indítása" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Önaláírt tanúsítvány" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Úgy tűnik, hogy önaláírt SSL-tanúsítványt használ, amely azt eredményezi, hogy" " a kiszolgáló személyazonossága nincs megerősítve. Ha ez váratlan, akkor köves" "se a GYIK-ban leírt utasításokat a CA láncolatfájllal kapcsolatban." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "GYIK megnyitása" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Kapcsolat kiépítve" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Kész" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Szinkronizálás beállítása kész" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Vázlat" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Nincsenek a szűrőnek megfelelő címsorok" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Nem találhatók címsorok a vázlathoz" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Felület" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Rögzített szélességű betűkészlet használata" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Helyesírás-ellenőrzés" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Nyelv megváltoztatása a szerkesztő helyi menüjéből" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Fejlécsáv" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Sorhossz korlátozása" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Elsősorban asztali számítógéphez. Használja a Ctrl + ↑ és Ctrl + ↓ " "billentyűkombinációkat a finomhangoláshoz." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Szintaxis észlelése" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "A szintaxiskiemeléshez és a formázáshoz (eszköztár és gyorsbillentyűk) " "szükséges. Tiltsa le az enyhén jobb teljesítmény érdekében." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Téma" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Formázási sáv" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Formázott nézet engedélyezése" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Tiltsa le a gyorsabb indítási idő érdekében" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Megnyitás formázott nézetben" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "" "Az engedélyezés az összes jegyzetet megjelenített Markdownként nyitja meg" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Matematikai egyenletek támogatása" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Enyhén csökkenti a megjelenítési teljesítményt" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Megjelenítés rögzített szélességű betűkészlettel" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Arányos és rögzített szélességű betűkészlet méretaránya" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "Megjelenítési nézetben. Használjon 1-et, hogy ne legyen igazítás." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Motor memóriában tartása" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Gyorsabb későbbi átalakítások a magasabb memóriahasználatért cserében" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Oldalsáv rögzítése" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Asztali számítógépen, ha van hely" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Kategória címkestílusa" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Adatok" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Reset Database" msgstr "Adatbázis visszaállítása" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Delete all notes from the local database. The app will quit." msgstr "Az összes jegyzet törlése a helyi adatbázisból. Az alkalmazás kilép." #. Translators: Button #: data/ui/preferences_dialog.ui:178 iotas/preferences_dialog.py:340 msgid "Reset" msgstr "Visszaállítás" #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "Nextcloud leválasztása" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Kijelentkezik a Nextcloud Jegyzetekből. Az összes jegyzet el lesz távolítva, " "és az alkalmazás kilép." #. Translators: Button #: data/ui/preferences_dialog.ui:199 iotas/preferences_dialog.py:361 msgid "Disconnect" msgstr "Leválasztás" #. Translators: Title #: data/ui/preferences_dialog.ui:217 msgid "Debug" msgstr "Hibakeresés" #. Translators: Title #: data/ui/preferences_dialog.ui:223 msgid "Clear Sync Timestamp" msgstr "Szinkronizálási időbélyeg törlése" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:225 msgid "Forces a pull of all notes from the sync server" msgstr "" "Kikényszeríti az összes jegyzet lekérését a szinkronizálási kiszolgálóról" #. Translators: Button #: data/ui/preferences_dialog.ui:232 msgid "Clear" msgstr "Törlés" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Kijelöltek törlése" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Kijelöltek kedvencként való jelölésének be- és kikapcsolása" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Kijelöltek kategóriájának megváltoztatása" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Kategóriák bezárása" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Kategóriák" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Táblázat beszúrása" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Létrehozás" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Rendszerstílus követése" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Világos stílus" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Sötét stílus" #. Translators: Description, CLI option #: iotas/application.py:300 msgid "Create a note" msgstr "Jegyzet létrehozása" #. Translators: Description, CLI option #: iotas/application.py:309 msgid "Create a backup" msgstr "Biztonsági mentés létrehozása" #. Translators: Description, CLI option #: iotas/application.py:318 msgid "Restore a backup" msgstr "Biztonsági mentés helyreállítása" #. Translators: Description, CLI option #: iotas/application.py:327 msgid "Display backup path" msgstr "Biztonsági mentési útvonal megjelenítése" #. Translators: Description, CLI option #: iotas/application.py:336 msgid "Display path for custom server SSL CA chain file" msgstr "Az egyéni kiszolgáló SSL CA láncolatfájl útvonalának megjelenítése" #. Translators: Description, CLI option #: iotas/application.py:345 msgid "Toggle display of extended preferences in UI" msgstr "" "A felhasználói felületen lévő bővített beállítások megjelenítésének be- és kik" "apcsolása" #. Translators: Description, CLI option #: iotas/application.py:354 msgid "Quit any running instance" msgstr "Kilépés az összes futó példányból" #. Translators: Description, CLI option #: iotas/application.py:363 msgid "Enable debug logging and functions" msgstr "Hibakeresési naplózás és funkciók engedélyezése" #. Translators: Description, CLI option #: iotas/application.py:372 msgid "Open note by id" msgstr "Jegyzet megnyitása azonosító alapján" #. Translators: Description, CLI option #: iotas/application.py:381 msgid "Search in notes" msgstr "Keresés a jegyzetekben" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "HELYREÁLLÍTÁS – TÁVOLI AZONOSÍTÓ ÜTKÖZÉSE" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "HELYREÁLLÍTÁS – CÍM ÜTKÖZÉSE" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Összes jegyzet" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Nem kategorizált" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:958 #, python-brace-format msgid "Line length now {0}px" msgstr "A sorhossz jelenleg {0} képpont" #. Translators: Description, notification #: iotas/editor.py:964 msgid "Line length limit disabled" msgstr "A sorhosszkorlát le van tiltva" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Hivatkozás megnyitása a böngészőben" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} / {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:103 msgid "Exported to {}" msgstr "{} formátumba exportálva" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:116 msgid "Failed to export to {}" msgstr "Nem sikerült {} formátumba exportálni" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:203 msgid "{} notes deleted" msgstr "{} jegyzet törölve" #. Translators: Description, notification #: iotas/index.py:206 msgid "Note deleted" msgstr "Jegyzet törölve" #. Translators: Button #: iotas/index.py:211 msgid "Undo" msgstr "Visszavonás" #. Translators: Description, notification #: iotas/index.py:249 msgid "Sync conflict with note being edited" msgstr "Szinkronizálási ütközés a szerkesztett jegyzetben" #. Translators: Description, notification #: iotas/index.py:256 msgid "The note being edited was remotely deleted" msgstr "A szerkesztett jegyzetet távolról törölték" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:264 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Nem sikerült a titokszolgáltatás elérése. Győződjön meg arról, hogy fel van-e " "oldva egy alapértelmezett kulcstartót biztosító szolgáltató, például a gnome-" "keyring." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:498 msgid "Syncing" msgstr "Szinkronizálás" #. Translators: Description, notification, {} is a number #: iotas/index.py:517 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} változtatás" msgstr[1] "{} változtatás" #. Translators: Description, notification #: iotas/index.py:533 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "" "Szinkronizálási hiba. Telepítve van a Nextcloud Jegyzetek alkalmazás a " "kiszolgálóra?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:630 msgid "Loading" msgstr "Betöltés" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Hivatkozás beszúrása" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Hivatkozás szerkesztése" #. Translators: Title #: iotas/nextcloud_login_dialog.py:108 msgid "Updating Notes" msgstr "Jegyzetek frissítése" #. Translators: Title #: iotas/nextcloud_login_dialog.py:112 msgid "Performing Initial Transfer" msgstr "Kezdeti átvitel végrehajtása" #. Translators: Title #: iotas/nextcloud_login_dialog.py:168 msgid "Connecting" msgstr "Kapcsolódás" #. Translators: Title #: iotas/nextcloud_login_dialog.py:190 msgid "Waiting for Login" msgstr "Várakozás a bejelentkezésre" #. Translators: Description #: iotas/nextcloud_login_dialog.py:192 msgid "Complete the authentication in your browser" msgstr "Fejezze be a hitelesítést a böngészőjében" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:208 msgid "Failed to start login with possible certificate issue" msgstr "Nem sikerült a bejelentkezés indítása, lehetséges tanúsítványprobléma" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:211 msgid "Failed to start login. Wrong address?" msgstr "Nem sikerült a bejelentkezés indítása. Hibás cím?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:65 iotas/preferences_dialog.py:97 msgid "Monochrome" msgstr "Monokróm" #. Translators: Description, a style name #: iotas/preferences_dialog.py:67 msgid "Muted Markup" msgstr "Némított jelölőkód" #. Translators: Description, a style name #: iotas/preferences_dialog.py:69 msgid "Bold Markup" msgstr "Félkövér jelölőkód" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:124 msgid "Disabled" msgstr "Letiltva" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:99 msgid "Muted" msgstr "Némítva" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:101 msgid "Blue" msgstr "Kék" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:103 msgid "Orange" msgstr "Narancs" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Red" msgstr "Vörös" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "None" msgstr "Nincs" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:118 iotas/preferences_dialog.py:138 msgid "Always Visible" msgstr "Mindig látható" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:120 iotas/preferences_dialog.py:140 msgid "Automatically Hide" msgstr "Automatikus elrejtés" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:122 iotas/preferences_dialog.py:142 msgid "Auto Hide When Fullscreen" msgstr "Automatikus elrejtés teljes képernyőn" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:273 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Csökkentés {0} nyomással" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:276 #, python-brace-format msgid "Extending in {0} presses" msgstr "Kiterjesztés {0} nyomással" #. Translators: Description, notification #: iotas/preferences_dialog.py:281 msgid "Extended hidden" msgstr "Kiterjesztetten rejtett" #. Translators: Description, notification #: iotas/preferences_dialog.py:284 msgid "Extended shown" msgstr "Kiterjesztetten megjelenített" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:313 msgid "Hiding discouraged on mobile" msgstr "Az elrejtés nem ajánlott mobil eszközökön" #. Translators: Title #: iotas/preferences_dialog.py:333 msgid "Reset Database?" msgstr "Visszaállítja az adatbázist?" #. Translators: Description #: iotas/preferences_dialog.py:335 msgid "All notes will be deleted. Continue with the reset?" msgstr "Az összes jegyzet törölve lesz. Folytatja a visszaállítást?" #. Translators: Title #: iotas/preferences_dialog.py:354 msgid "Disconnect Nextcloud?" msgstr "Leválasztja a Nextcloud-kiszolgálót?" #. Translators: Description #: iotas/preferences_dialog.py:356 msgid "All notes will be removed. Do you want to sign out?" msgstr "Az összes jegyzet el lesz távolítva. Ki szeretne jelentkezni?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Nem lehet megváltoztatni a kategóriát csak olvasható jegyzetnél" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} kijelölve" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:506 msgid "SYNC CONFLICT" msgstr "SZINKRONIZÁLÁSI ÜTKÖZÉS" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Hiba" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/it.po000066400000000000000000001352721507102636600220060ustar00rootroot00000000000000# Italian translations for iotas package. # Copyright (C) 2022 THE iotas'S COPYRIGHT HOLDER # This file is distributed under the same license as the iotas package. # Daniele Verducci , 2024 # Davide Ferracin , 2025 # msgid "" msgstr "" "Project-Id-Version: iotas\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/-/issues\n" "POT-Creation-Date: 2025-03-10 23:44+0000\n" "PO-Revision-Date: 2025-03-19 14:38+0100\n" "Last-Translator: Davide Ferracin \n" "Language: it\n" "Language-Team: Italian\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.15.0\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:4 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:6 msgid "Simple note taking with Nextcloud Notes" msgstr "Una semplice app per scrivere note con Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or #. localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:14 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "notes;note;nota;nextcloud;minimale;distrazione;editor;concentrato;testo;scrivi;markdown;documento;" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Semplice app per note" #. Translators: Part of metainfo description. "Iotas" is the application name; #. do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas punta a fornire un modo di prendere appunti privo di distrazioni " "con il suo design incentrato sul mobile" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Funzionalità" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Sincronizzazione veloce opzionale con Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Modifica di note offline, sincronizzazione quando si torna online" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Modifica e filtraggio per categoria" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Preferiti" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Controllo dell'ortografia" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Ricerca all'interno della collezione o delle singole note" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Modalità concentrazione e opzione per nascondere automaticamente la barra" " d'intestazione o di formattazione dell'editor" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "In anteprima: esportazione verso PDF, ODT e HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Design convergente, Iotas è a suo agio sul PC desktop di casa come su " "mobile" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Ricerca da GNOME Shell" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Backup e ripristino delle note (da riga di comando, per l'uso senza " "sincronizzazione)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "" "Possibilità di cambiare dimensioni del tipo di carattere e usare tipi " "monospaziati" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "La scrittura in markdown è supportata, seppur opzionale, e comprende" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formattazione dalla barra degli strumenti e con scorciatoie" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Evidenziazione della sintassi con temi" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Una vista formattata" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "La possibilità di marcare come completati i compiti dalla vista formattata" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Alcuni dettagli più tecnici, per chi è interessato a questo tipo di cose" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it " "snappy" msgstr "" "Nextcloud Notes sincronizza tramite l'API REST, non WebDAV, il che lo " "rende veloce" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "C'è un basilare riconoscimento dei conflitti in fase di sincronizzazione" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Le note sono salvate continuamente" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Le collezioni di note grandi sono caricate parzialmente per velocizzare " "l'avvio" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup " "(CLI)." msgstr "" "Le note sono salvate in SQLite, fornendo una ricerca veloce (FTS) senza " "reinventare la ruota. File di testo semplice possono essere recuperati " "facendo un backup (CLI)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_window.ui:12 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Indice" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editor con markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Markdown renderizzato" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Indice in stile scuro" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobile" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "" "Daniele Verducci \n" "Davide Ferracin " #. Translators: Button #: data/ui/category_header_bar.ui:14 data/ui/editor_rename_header_bar.ui:16 msgid "Revert Changes" msgstr "Ripristina modifiche" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:41 data/ui/editor_rename_header_bar.ui:39 msgid "Apply Changes" msgstr "Applica modifiche" #. Translators: Button #: data/ui/category_header_bar.ui:43 data/ui/editor_rename_header_bar.ui:41 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Applica" #. Translators: Button #: data/ui/category_header_bar.ui:57 msgid "Clear and Apply" msgstr "Pulisci e applica" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Trova" #. Translators: Button #: data/ui/editor_search_header_bar.ui:15 data/ui/index_search_header_bar.ui:11 #: data/ui/render_search_header_bar.ui:14 data/ui/selection_header_bar.ui:16 msgid "Back" msgstr "Indietro" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:42 #: data/ui/keyboard_shortcuts_window.ui:287 #: data/ui/render_search_header_bar.ui:35 msgid "Previous Match" msgstr "Occorrenza precedente" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:50 #: data/ui/keyboard_shortcuts_window.ui:280 #: data/ui/render_search_header_bar.ui:43 msgid "Next Match" msgstr "Occorrenza successiva" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:72 #: data/ui/editor_search_header_bar.ui:81 #: data/ui/keyboard_shortcuts_window.ui:273 msgid "Replace" msgstr "Sostituisci" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:300 msgid "Focus Mode" msgstr "Modalità concentrazione" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Trova e sostituisci…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Salta a…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Modifica titolo…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Cambia categoria…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Elimina" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Esporta…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Torna alle note" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "La nota è in sola lettura" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Menù dell'editor" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_window.ui:114 msgid "Toggle Markdown Render" msgstr "Commuta visualizzazione markdown" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Modifica nota" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Caricamento del motore del render in corso" #. Translators: Button #: data/ui/export_dialog.ui:21 iotas/preferences_dialog.py:336 #: iotas/preferences_dialog.py:357 msgid "Cancel" msgstr "Annulla" #. Translators: Title #: data/ui/export_dialog.ui:29 msgid "Export As..." msgstr "Esporta come…" #. Translators: Title #: data/ui/export_dialog.ui:49 msgid "Exporting..." msgstr "Esportazione in corso…" #. Translators: Button #. Translators: Title #: data/ui/export_dialog.ui:68 data/ui/export_dialog.ui:95 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Chiudi" #. Translators: Button #: data/ui/export_dialog.ui:75 msgid "Show" msgstr "Mostra" #. Translators: Title. Iotas is the application name and shouldn't be #. translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Benvenuto su Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Usare la barra di intestazione qui sopra per…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Aggiungere una nota" # [DF] Qui la stringa finisce in una voce del menù hamburger che nella # descrizione di cosa fa l'app nella schermata iniziale. # Nel primo caso si traduce con "Sincronizzazione con Nextcloud Notes", nel # secondo con "Sincronizzare con Nextcloud Notes" (dato che è una prosecuzione # della frase "Usare la barra di intestazione qui sopra per…" qui sopra. # Andrebbe aperta una richiesta di merge agli sviluppatori per distinguere le # due stringhe. #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Sincronizzazione con Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Riduce l'ingrandimento" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Aumenta l'ingrandimento" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:157 #: data/ui/keyboard_shortcuts_window.ui:239 msgid "Horizontal Rule" msgstr "Linea orizzontale" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:166 #: data/ui/keyboard_shortcuts_window.ui:246 msgid "Quote" msgstr "Citazione" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:175 #: data/ui/keyboard_shortcuts_window.ui:225 msgid "Code" msgstr "Codice" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:184 #: data/ui/keyboard_shortcuts_window.ui:253 msgid "Table" msgstr "Tabella" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Livello 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Livello 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Livello 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Livello 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Rimuovi" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:80 data/ui/keyboard_shortcuts_window.ui:183 msgid "Heading" msgstr "Intestazione" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:89 data/ui/keyboard_shortcuts_window.ui:169 msgid "Bold" msgstr "Grassetto" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:98 data/ui/keyboard_shortcuts_window.ui:176 msgid "Italic" msgstr "Corsivo" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:107 #: data/ui/keyboard_shortcuts_window.ui:232 msgid "Strikethrough" msgstr "Barrato" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:116 #: data/ui/keyboard_shortcuts_window.ui:190 msgid "Unordered List" msgstr "Lista non numerata" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:125 #: data/ui/keyboard_shortcuts_window.ui:197 msgid "Ordered List" msgstr "Lista numerata" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:134 #: data/ui/keyboard_shortcuts_window.ui:204 msgid "Checkbox" msgstr "Casella di controllo" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:143 #: data/ui/keyboard_shortcuts_window.ui:218 msgid "Link" msgstr "Collegamento" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Aggiorna" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Impostazioni" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Scorciatoie da tastiera" #. Translators: Menu item, Iotas is the application name and shouldn't be #. translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Informazioni su Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Menù principale" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Oggi" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Ieri" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Questa settimana" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Questo mese" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Il mese scorso" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Mostra mesi precedenti" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Prima del mese scorso" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Mostra di più" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Apri categorie" #. Translators: Button #: data/ui/index.ui:42 msgid "New Note" msgstr "Nuova nota" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:266 msgid "Search" msgstr "Cerca" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Seleziona note" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Connessione al server interrotta" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "A causa di modifiche tecniche (una nuova id dell'app) Iotas deve essere " "riautenticata con il proprio server Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Autentica" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be " "retrieved" msgstr "" "Impossibile recuperare il token di autenticazione per sincronizzare con " "Nextcloud Notes" #. Translators: Button #: data/ui/index.ui:111 msgid "OK" msgstr "OK" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Lista vuota" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Inserisce il termine di ricerca" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Nessun risultato di ricerca" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create New Note" msgstr "Crea nuova nota" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:31 msgid "Show Sidebar" msgstr "Mostra barra laterale" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete Note" msgstr "Elimina nota" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move Up List" msgstr "Muove verso l'alto nella lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move Down List" msgstr "Muove verso il basso nella lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:59 msgid "Start Selection" msgstr "Avvia selezione" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:66 msgid "Reset Filter" msgstr "Reimposta il filtro" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:73 msgid "Open First Search Result" msgstr "Apre il primo risultato della ricerca" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:81 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:86 msgid "Edit Title" msgstr "Modifica titolo" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_window.ui:93 iotas/export_dialog.py:129 msgid "Export" msgstr "Esporta" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Create New Note Including Selection" msgstr "Crea nuova nota dalla selezione" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Change Category" msgstr "Cambia la categoria" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:121 msgid "Undo Typing" msgstr "Annulla l'inserimento" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:128 msgid "Redo Typing" msgstr "Ripete l'inserimento" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:135 msgid "Insert Emoji" msgstr "Inserisce un emoji" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:142 msgid "Focus Text View" msgstr "Attiva la casella di testo" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:149 msgid "Focus Header Bar" msgstr "Attiva la barra d'intestazione" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:156 msgid "Focus Formatting Bar" msgstr "Attiva la barra di formattazione" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:164 msgid "Formatting" msgstr "Formattazione" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:211 msgid "Toggle Checkbox" msgstr "Aggiunge/Rimuove la spunta alla casella di controllo" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:261 msgid "Editor Search" msgstr "Cerca nell'editor" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:295 msgid "Editor Appearance" msgstr "Aspetto dell'editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:307 msgid "Increase Line Length" msgstr "Aumenta la lunghezza di riga" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:314 msgid "Decrease Line Length" msgstr "Diminuisce la lunghezza di riga" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:321 msgid "Increase Font Size" msgstr "Aumenta la dimensione del tipo di carattere" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:328 msgid "Decrease Font Size" msgstr "Riduce la dimensione del tipo di carattere" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:336 msgid "General" msgstr "Generali" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:341 msgid "Toggle Fullscreen" msgstr "Attiva/Disattiva lo schermo intero" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:348 msgid "Show Preferences" msgstr "Mostra le impostazioni" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:355 msgid "Show Shortcuts" msgstr "Mostra le scorciatoie" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:362 msgid "Open Previous Note" msgstr "Apre la nota precedente" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:369 msgid "Go Back" msgstr "Va indietro" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:376 msgid "Quit" msgstr "Esce" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Testo" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Impostazione di Nextcloud Notes" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a " "web browser" msgstr "" "Premere Continua per fornire l'indirizzo del server Nextcloud e accedere " "tramite il browser web." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Continua" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Continua all'immissione dell'URL" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Servizio portachiavi non disponibile" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication " "details. Ensure you have a provider such as gnome-keyring. A default " "keyring needs to be setup, and that keyring unlocked. Most desktop " "environments will provide this for you. Restart the app to try again." msgstr "" "Non è stato possibile accedere al servizio portachiavi per salvare i " "dettagli di autenticazione. Controllare di avere un fornitore come gnome-" "keyring. È necessario impostare un portachiavi di default, e deve essere " "sbloccato. Gran parte degli ambienti desktop ne forniscono uno. Riavviare" " l'app per riprovare." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "URL del server" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Avvia accesso" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Certificato auto-firmato" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the " "server identity not being verified. If this is expected please follow the" " instructions in the FAQ to provide a CA chain file." msgstr "" "Sembra che si stia usando un certificato SSL auto-firmato, che comporta " "la mancata verifica dell'identità del server. Se questo è previsto, " "seguire le istruzioni nelle FAQ per fornire un CA chain file." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Apri le FAQ" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Connessione stabilita" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Fatto" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Completa l'impostazione della sincronizzazione" # [DF] Questo "outline" si riferisce ad una lista delle intestazioni presenti # nel documento, rilevate automaticamente dalla sintassi Markdown. #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Indice" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Nessuna intestazione corrisponde al filtro" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Nessuna intestazione trovata per l'indice" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Interfaccia" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Tipo di carattere monospaziato" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Controllo ortografico" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Cambiare la lingua tramite il menù contestuale dell'editor" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Barra di intestazione" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Limita la lunghezza di riga" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Principalmente per desktop. Usare Ctrl + ↑ e Ctrl + ↓ sulla tastiera per " "regolare." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Rileva sintassi" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "Richiesto per l'evidenziazione della sintassi e la formattazione (barra " "degli strumenti e scorciatoie da tastiera). Disabilitare per prestazioni " "leggermente migliori." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Tema" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Barra di formattazione" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Abilita vista formattata" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Disabilitare per ridurre il tempo di avvio" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Aprire in vista formattata" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "" "Attivando questa opzione, tutte le note saranno aperte con markdown " "renderizzato" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Supporta equazioni matematiche" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Riduce leggermente la velocità di render" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Render con tipo di carattere monospaziato" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Rapporto tra caratteri renderizzati e caratteri monospaziati" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "Nella vista renderizzata. Impostare a 1 per non regolarla." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Mantenere il motore in memoria" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "" "Conversioni successive più veloci a scapito di un utilizzo maggiore di " "memoria" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Fissa la barra laterale" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Sul desktop, quando c'è spazio" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Stile delle etichette delle categorie" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Dati" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Reset Database" msgstr "Reimposta database" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Delete all notes from the local database. The app will quit." msgstr "Elimina tutte le note dal database locale. L'app verrà chiusa." #. Translators: Button #: data/ui/preferences_dialog.ui:178 iotas/preferences_dialog.py:338 msgid "Reset" msgstr "Reimposta" #. Translators: Title #: data/ui/preferences_dialog.ui:190 msgid "Disconnect Nextcloud" msgstr "Disconnetti da Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:192 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app " "will quit." msgstr "" "Termina la sessione con Nextcloud Notes. Tutte le note saranno rimosse e " "l'app verrà chiusa." #. Translators: Button #: data/ui/preferences_dialog.ui:199 iotas/preferences_dialog.py:359 msgid "Disconnect" msgstr "Disconnetti" #. Translators: Title #: data/ui/preferences_dialog.ui:217 msgid "Debug" msgstr "Debug" #. Translators: Title #: data/ui/preferences_dialog.ui:223 msgid "Clear Sync Timestamp" msgstr "Cancella timestamp di sincronizzazione" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:225 msgid "Forces a pull of all notes from the sync server" msgstr "Forza il download di tutte le note dal server di sincronizzazione" #. Translators: Button #: data/ui/preferences_dialog.ui:232 msgid "Clear" msgstr "Pulisci" #. Translators: Button #: data/ui/selection_header_bar.ui:32 msgid "Delete Selected" msgstr "Elimina selezionate" #. Translators: Button #: data/ui/selection_header_bar.ui:43 msgid "Toggle Favorite for Selected" msgstr "Commuta preferito per la selezione" #. Translators: Button #: data/ui/selection_header_bar.ui:51 msgid "Change Category for Selected" msgstr "Cambia categoria per la selezione" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Chiudi categorie" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Categorie" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Inserisci tabella" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Crea" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Segui lo stile di sistema" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Stile chiaro" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Stile scuro" #. Translators: Description, CLI option #: iotas/application.py:266 msgid "Create a note" msgstr "Crea una nota" #. Translators: Description, CLI option #: iotas/application.py:275 msgid "Create a backup" msgstr "Crea un backup" #. Translators: Description, CLI option #: iotas/application.py:284 msgid "Restore a backup" msgstr "Ripristina un backup" #. Translators: Description, CLI option #: iotas/application.py:293 msgid "Display backup path" msgstr "Mostra percorso di backup" #. Translators: Description, CLI option #: iotas/application.py:302 msgid "Display path for custom server SSL CA chain file" msgstr "Mostra percorso per il file chiave SSL CA personalizzato del server" #. Translators: Description, CLI option #: iotas/application.py:311 msgid "Toggle display of extended preferences in UI" msgstr "Commuta visualizzazione delle preferenze estese nella UI" #. Translators: Description, CLI option #: iotas/application.py:320 msgid "Quit any running instance" msgstr "Esci da ogni istanza in esecuzione" #. Translators: Description, CLI option #: iotas/application.py:329 msgid "Enable debug logging and functions" msgstr "Abilita funzionalità e registro di debug" #. Translators: Description, CLI option #: iotas/application.py:338 msgid "Open note by id" msgstr "Apri nota dall'id" #. Translators: Description, CLI option #: iotas/application.py:347 msgid "Search in notes" msgstr "Cerca nelle note" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:203 msgid "RESTORATION REMOTE ID CLASH" msgstr "CONFLITTO ID REMOTO" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:221 msgid "RESTORATION TITLE CLASH" msgstr "CONFLITTO TITOLO" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Tutte le note" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Non categorizzate" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:946 #, python-brace-format msgid "Line length now {0}px" msgstr "La lunghezza di riga è ora {0} px" #. Translators: Description, notification #: iotas/editor.py:952 msgid "Line length limit disabled" msgstr "Limite alla lunghezza di riga disabilitato" #: iotas/editor.py:1572 msgid "Opening link in browser" msgstr "Apertura del collegamento in un browser" #. Translators: Description, {0} the current position in {1} a number of search #. results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} di {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:100 msgid "Exported to {}" msgstr "Esportata in {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:113 msgid "Failed to export to {}" msgstr "Esportazione in {} non riuscita" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:198 msgid "{} notes deleted" msgstr "{} note eliminate" #. Translators: Description, notification #: iotas/index.py:201 msgid "Note deleted" msgstr "Nota eliminata" #. Translators: Button #: iotas/index.py:206 msgid "Undo" msgstr "Annulla" #. Translators: Description, notification #: iotas/index.py:244 msgid "Sync conflict with note being edited" msgstr "Conflitto di sincronizzazione con la nota che si sta modificando" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" #. should #. likely not be translated. #: iotas/index.py:252 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Errore nell'accesso al servizio portachiavi. Controllare di avere un " "fornitore come gnome-keyring che abbia un portachiavi di default " "sbloccato." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:484 msgid "Syncing" msgstr "Sincronizzazione in corso" #. Translators: Description, notification, {} is a number #: iotas/index.py:503 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} modifica" msgstr[1] "{} modifiche" #. Translators: Description, notification #: iotas/index.py:519 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "" "Sincronizzazione non riuscita. L'app Nextcloud Notes è installata sul " "server?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:616 msgid "Loading" msgstr "Caricamento" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Inserire collegamento" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Modifica nota" #. Translators: Title #: iotas/nextcloud_login_dialog.py:107 msgid "Updating Notes" msgstr "Aggiornamento note" #. Translators: Title #: iotas/nextcloud_login_dialog.py:111 msgid "Performing Initial Transfer" msgstr "Trasferimento iniziale in corso" #. Translators: Title #: iotas/nextcloud_login_dialog.py:165 msgid "Connecting" msgstr "Connessione in corso" #. Translators: Title #: iotas/nextcloud_login_dialog.py:187 msgid "Waiting for Login" msgstr "In attesa di accedere" #. Translators: Description #: iotas/nextcloud_login_dialog.py:189 msgid "Complete the authentication in your browser" msgstr "Completare l'autenticazione nel proprio browser" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:205 msgid "Failed to start login with possible certificate issue" msgstr "Avvio dell'accesso non riuscito con possibile errore nel certificato" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:208 msgid "Failed to start login. Wrong address?" msgstr "Avvio dell'accesso non riuscito. L'indirizzo è sbagliato?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:65 iotas/preferences_dialog.py:97 msgid "Monochrome" msgstr "Monocromatico" #. Translators: Description, a style name #: iotas/preferences_dialog.py:67 msgid "Muted Markup" msgstr "Markup tenue" #. Translators: Description, a style name #: iotas/preferences_dialog.py:69 msgid "Bold Markup" msgstr "Markup in grassetto" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of #. visibility #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:126 msgid "Disabled" msgstr "Disabilitato" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:99 msgid "Muted" msgstr "Tenue" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:101 msgid "Blue" msgstr "Blu" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:103 msgid "Orange" msgstr "Arancione" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Red" msgstr "Rosso" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "None" msgstr "Nessuno" #. Translators: Description, for preference option - a description of #. visibility #: iotas/preferences_dialog.py:120 iotas/preferences_dialog.py:140 msgid "Always Visible" msgstr "Sempre visibile" #. Translators: Description, for preference option - a description of #. visibility #: iotas/preferences_dialog.py:122 iotas/preferences_dialog.py:142 msgid "Automatically Hide" msgstr "Nascondi automaticamente" #. Translators: Description, for preference option - a description of #. visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Auto Hide When Fullscreen" msgstr "Nascondi automaticamente a schermo intero" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:277 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Riducendo in {0} pressioni" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:280 #, python-brace-format msgid "Extending in {0} presses" msgstr "Estendendo in {0} pressioni" #. Translators: Description, notification #: iotas/preferences_dialog.py:285 msgid "Extended hidden" msgstr "Estesa nascosta" #. Translators: Description, notification #: iotas/preferences_dialog.py:288 msgid "Extended shown" msgstr "Estesa mostrata" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:311 msgid "Hiding discouraged on mobile" msgstr "Sconsigliato nascondere su mobile" #. Translators: Title #: iotas/preferences_dialog.py:331 msgid "Reset Database?" msgstr "Reimpostare il database?" #. Translators: Description #: iotas/preferences_dialog.py:333 msgid "All notes will be deleted. Continue with the reset?" msgstr "Tutte le note saranno eliminate. Reimpostare?" #. Translators: Title #: iotas/preferences_dialog.py:352 msgid "Disconnect Nextcloud?" msgstr "Disconnettere da Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:354 msgid "All notes will be removed. Do you want to sign out?" msgstr "Tutte le note saranno rimosse. Disconnettere?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Non è possibile cambiare la categoria su una nota in sola lettura" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} selezionate" #. Translators: Description, used as a prefix to the previous title for notes #. updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:502 msgid "SYNC CONFLICT" msgstr "CONFLITTO DI SINCRONIZZAZIONE" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Errore" #~ msgid "" #~ "Why \"Iotas\"? An iota is a little" #~ " bit and this app is designed " #~ "for jotting down little things on " #~ "little devices. Iota stems from the " #~ "same Greek word as jot and is " #~ "commonly used in negative statements eg." #~ " \"not one iota of …\", but we" #~ " think the word has more to " #~ "give. Maybe somebody will take note?" #~ msgstr "" #~ "Perché \"Iotas\"? Un iota è un " #~ "piccolo bit e quest'app è disegnata " #~ "per scribacchiare piccole cose in " #~ "piccoli dispositivi. Iota proviene dalla " #~ "parola Greca jot ed è comunemente " #~ "usata come negazione, ad es. \"neanche" #~ " un iota di ...\", ma pensiamo " #~ "che la parola abbia di più da " #~ "dare. Magari qualcuno può prenderne " #~ "nota?" #~ msgid "Read-only note" #~ msgstr "Nota in sola lettura" #~ msgid "Let's get started" #~ msgstr "Cominciamo" #~ msgid "Add new feeds via URL" #~ msgstr "Aggiungi nuovi feeds tramite URL" #~ msgid "Import an OPML file" #~ msgstr "Importa un file OPML" #~ msgid "Return to Index" #~ msgstr "Torna all'indice" #~ msgid "Go back" #~ msgstr "Indietro" #~ msgid "Waiting for completion of login in browser" #~ msgstr "In attesa del completamento della login nel browser" #~ msgid "Highlight Syntax" #~ msgstr "Evidenzia sintassi" #~ msgid "Disable for slightly improved performance." #~ msgstr "Disattiva per ottenere prestazioni lievemente migliori" #~ msgid "Syntax Theme" #~ msgstr "Tema dell'evidenziazione di sintassi" #~ msgid "Line length limit already disabled" #~ msgstr "Limite lunghezza linea già disabilitato" #~ msgid "Font size now {0}pt" #~ msgstr "La dimensione del font è ora {0}pt" #~ msgid "Finish" #~ msgstr "Completa" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/ka.po000066400000000000000000001631761507102636600217710ustar00rootroot00000000000000# Georgian translation for Iotas. # Copyright (C) 2025 Iotas's authors # This file is distributed under the same license as the Iotas package. # Ekaterine Papava , 2025. # msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-19 23:44+0000\n" "PO-Revision-Date: 2025-09-20 08:07+0200\n" "Last-Translator: Ekaterine Papava \n" "Language-Team: Georgian \n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.7\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "მარტივი შენიშვნები Nextcloud Notes-თან ერთად" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;შენიშვნები;ტექსტი;მინიმალური;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "ახალი ჩანაწერი" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "შენიშვნების მარტივი აპლიკაცია" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "Iotas aims to provide distraction-free note taking via its mobile-first design." msgstr "Iotas-ის მიზანია, მოგაწოდოთ ბლოკნოტი შენიშვნებისთვის ისე, რომ ყურადღება რამე სხვაზე არ გადაგიტანოთ." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "ფუნქციები" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "არასავალდებულო ჩქაროსნული სინქრონიზაცია Nextcloud Notes-თან" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "ინტერნეტგარეშე შენიშვნების ჩასწორება, სინქრონიზაცია, როცა ინტერნეტი ისევ ჩაირთვება" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "კატეგორიების ჩასწორება და გაფილტვრა" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "სანიშნეები" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "მართლწერის შემოწმება" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "ძებნა კოლექციებში, ან ინდივიდუალურ შენიშვნებში" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "ფოკუსის რეჟიმი და არასავალდებულო რედაქტორის თავსართის და დაფორმატების პანელების დამალვა" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "მინიატურაში: PDF-ში, ODT-ში და HTML-ში გატანა" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "კონვერგენტული დიზაინი - იგრძენით თავი სახლში Iotas-თან ერთად კომპიუტერზე და მობილურზე" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "ძებნა GNOME Shell-დან" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "შენიშვნების მარქაფი და აღდგენა (CLI-დან, სინქრონიზაციის გარეშე გამოსაყენებლად)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "შესაძლებლობა, შეცვალოთ ფონტის ზომა და გადართოთ ერთსივრციანი სტილი" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "მარკდაუნით წერა მხარდაჭერილია, მაგრამ არა სავალდებულო. მოგაწოდებთ" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "დაფორმატება ხელსაწყოების პანელით და მალსახმობებით" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "სინტაქსის გამოკვეთა თემებით" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "დაფორმატებული ხედი" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "შესაძლებლობა, ამოცანების სია დაფორმატებული ხედიდან შეამოწმოთ" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "ოდნავ მეტი ტექნიკური დეტალები მათთვის, ვისაც ასეთი რამები აინტერესებს" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "Nextclout Notes-თან სინქრონიზაცია REST API-ით მიმდინარეობს და არა WebDAV-ით, რაც მას ძალიან ასწრაფებს" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "აქვს საბაზისო სინქრონიზაციის კონფლიქტის დადგენის საშუალება" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "შენიშვნების შენახვა მუდმივად მიმდინარეობს" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "დიდი შენიშვნის კოლექციები ნაწილობრივ იტვირთება, რომ გაშვების დრო შემცირდეს" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without reinventing the wheel. Plain files can be retrieved by " "making a backup (CLI)." msgstr "" "შენიშვნების დამახსოვრება SQLite-ში ხდება, რაც სწრაფი ძებნის (DTS) საშუალებას ბორბლის თავიდან გამოგონების გარეშე გვაძლევს. " "უბრალო ფაილების მიღება მარქაფით შეგიძლიათ (CLI-დან)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "ინდექსი" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "რედაქტორი მარკდაუნით" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "დარენდერებული მარკდაუნი" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "ინდექსი მუქ სტილში" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "მობილური" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "თემური დოღონაძე" #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "ცვლილებების დაბრუნება" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "ცვლილებების გადატარება" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 iotas/link_dialog.py:52 msgid "Apply" msgstr "გადატარება" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "გასუფთავება და გადატარება" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "ძებნა" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 data/ui/render_search_header_bar.ui:15 #: data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "უკან" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 data/ui/keyboard_shortcuts_dialog.ui:289 data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "წინა დამთხვევა" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 data/ui/keyboard_shortcuts_dialog.ui:282 data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "შემდეგი დამთხვევა" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 data/ui/editor_search_header_bar.ui:82 data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "ჩანაცვლება" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "ფოკუსის რეჟიმი" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "ძებნა და შეცვლა…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "გადასვლა სად…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "სათაურის ჩასწორება…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "კატეგორიის შეცვლა…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "წაშლა" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "გატანა…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "შენიშვნებზე დაბრუნება" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "შენიშვნა მხოლოდ-წაკითხვადია" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "რედაქტორის მენიუ" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "მარკდაუნის რენდერის გადართვა" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "შენიშვნის ჩასწორება" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "მიმდინარეობს რენდერის ძრავას ჩატვირთვა" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "გაუქმება" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "გატანა, როგორც…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "გადმოწერა…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "გატანა…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "დახურვა" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "ჩვენება" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "ერთი ან მეტი მიმაგრებული ფაილის გადაცემა ჩავარდა." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "თავიდან ცდა" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "მაინც გატანა" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "მოგესალმებათ Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "გამოიყენეთ თავსართის ზოლი ზემოთ, რომ…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "შენიშვნის დამატება" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "სინქრონიზაცია Nextcloud Notes-თან" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "დაპატარავება" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "გადიდება" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "ჰორიზონტალური წესი" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "ციტირება" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "კოდი" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "ცხრილი" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "დონე 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "დონე 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "დონე 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "დონე 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "წაშლა" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "მიმართულება" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "გასქელება" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "დახრა" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "გადახაზული" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "დაულაგებელი სია" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "დალაგებული სია" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "ჩასართავი" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "ბმული" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "განახლება" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "მორგება" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "კლავიატურის მალსახმობები" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Iotas-ის შესახებ" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "მთავარი მენიუ" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "დღეს" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "გუშინ" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "ამ კვირაში" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "ამ თვეში" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "ბოლო თვე" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "წინა თვეების ჩვენება" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "ბოლო თვემდე" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "მეტის ჩვენება" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "კატეგორიების გახსნა" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "ძებნა" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "აირჩიეთ შენიშვნები" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "სერვერთან დაკავშირება გათიშულია" #. Translators: Description #: data/ui/index.ui:93 msgid "Due to behind-the-scenes changes (a new app id) Iotas needs to reauthenticate with your Nextcloud server" msgstr "" "კულისებს მიღმა ცვლილებების გამო (ახალი აპის ID) Iotas-ს თქვენს Nextcloud Notes-ის სერვერზე ავთენტიკაცია თავიდან სჭირდება" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "ავთენტიკაცია" #. Translators: Description #: data/ui/index.ui:102 msgid "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "შეუძლებელია ავთენტიკაციის კოდის მიღება Nextcloud Notes-თან სინქრონიზაციისთვის" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "მოცილება" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "შენიშნების სია ცარიელია" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "მოსაძებნი სტრიქონი" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "ძებნის შედეგების გარეშე" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "ახალი შენიშვნის შექმნა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "გვერდითი ზოლის ჩვენება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "შენიშვნის წაშლა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "სიის ატანა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "სიის ჩამოტანა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "მონიშვნის დაწყება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "პირველი ძებნის შედეგის გახსნა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "ფილტრის ჩამოყრა" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "რედაქტორი" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "სათაურის ჩასწორება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "კატეგორიის შეცვლა" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "გატანა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "გადასვლა სექციაზე" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "ახალი შენიშვნის შექმნა მონიშნულის ჩათვლით" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "აკრეფის გაუქმება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "აკრეფის გამეორება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "ემოჯის ჩასმა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "ფოკუსი ტექსტის ხედზე" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "ფოკუსი თავსართის ზოლზე" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "ფოკუსი დაფორმატების ზოლზე" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "ფორმატირება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "თოლიას გადართვა" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "რედაქტორის ძებნა" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "რედაქტორის გარეგნობა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "ხაზის სიგრძის გაზრდა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "ხაზის სიგრძის შემცირება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "ფონტის ზომის გაზრდა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "ფონტის ზომის შემცირება" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "ზოგადი" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "მთელ ეკრანზე გატანის ჩართ/გამორთ" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "მორგება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "მალსახმობების ჩვენება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "წინა შენიშვნის გახსნა" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "უკან დაბრუნება" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "გასვლა" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "ტექსტი" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud Notes-ის მორგება" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "Press Continue to provide your Nextcloud server address and login via a web browser" msgstr "დააჭირეთ გაგრძელებას, რომ შეიყვანოთ თქვენი Nextcloud-ის სერვერის მისამართი და ავთენტიკაციის დეტალები ბრაუზერიდან" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "გაგრძელება" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "გაგრძელება URL-ზე" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "საიდუმლო სერვისი ხელმიუწვდომელია" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. Ensure you have a provider such as gnome-" "keyring. A default keyring needs to be setup, and that keyring unlocked. Most desktop environments will provide this for you. " "Restart the app to try again." msgstr "" "საიდუმლო სერვისთან წვდომა ავთენტიკაციის დეტალების შესანახად შეუძლებელია. დარწმუნდით, რომ გაქვთ მომწოდებელი, მაგალითად gnome-" "keyring. საჭიროა ნაგულისხმევი ბრელოკის მორგება და მისი განბლოკვა. სამუშაო გარემოების უმრავლესობას ამისთვის თავისი პროგრამა " "აქვთ. გაუშვით თავიდან აპი და თავიდან სცადეთ." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "სერვერის URL" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "შესვლის დაწყება" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "თვითხელმოწერილი სერტიფიკატი" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server identity not being verified. If this is expected " "please follow the instructions in the FAQ to provide a CA chain file." msgstr "" "როგორც ჩანს, იყენებთ თვითხელმოწერილ SSL სერტიფიკატს, რაც სერვერის იდენტიფიკატორის არშემოწმას იწვევს. თუ ეს მოსალოდნელი იყო, " "მიჰყევით ინსტრუქციებს ხდკ-ში, თუ როგორც მოგვაწოდოთ CA ჯაჭვის ფაილი." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "ხდკ-ის გახსნა" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "კავშირი დამყარებულია" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "დასრულებული" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "სინქრონიზაციის მორგების დასრულება" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "კონტური" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "ფილტრის შესაბამისი სათაურის გარეშე" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "კონტურისთვის სათაური აღმოჩენილი არაა" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "ინტერფეისი" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "მონოდაშორებული ფონტის გამოყენება" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "მართლწერის შემოწმება" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "შეცვალეთ ენა რედაქტორის კონტექსტური მენიუდან" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "ზედა მენიუ" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "ხაზის სიგრძის შეზღუდვა" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "ძირიტადად კომპიუტერებისთვის. გამოიყენეთ Ctrl + ↑ და Ctrl + ↓ კლავიატურაზე, ზუსტად მოსარგებად." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "სინტაქსის დადგენა" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard shortcuts). Disable for slightly improved performance." msgstr "" "აუცილებელია სინტაქსის გამოკვეთისა და დაფორმატებისთვის (ხელსაწყოების პანელი და კლავიატურის მალსახმობები. გათიშვა წარმადობას " "ოდნავ გაზრდის." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "თემა" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "დაფორმატების ზოლი" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "დაფორმატებული ხედის ჩართვა" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "გამორთეთ გაშვების დროის შესამცირებლად" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "გახსნა დაფორმატებულ ხედში" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "ჩართვა ყველა შენიშვნას დარენდერებული მარკდაუნის სახით გახსნის" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "მათემატიკური განტოლებების მხარდაჭერა" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "ოდნავ ამცირებს რენდერის წარმადობას" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "რენდერი მონოდაშორებული ფონტის გამოყენებით" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "მონოდაშორებული ფონტის ზომის კოეფიციენტის პროპორციულად" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "რენდერის ხედში. გამოიყენეთ 1 არგასასწორებლად." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "ძრავის შენარჩუნება მეხსიერებაში" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "სწრაფი ამის შემდეგი გადაყვანები მეხსიერების უფრო დიდი ხარჯვისთვის" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "გვერდითი პანელის მიმაგრება" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "კომპიუტერზე, როცა არის ადგილი" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "კატეგორიის ჭდის სტილი" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "მონაცემები" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Nextcloud-თან დაკავშირება" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "სინქრონიზაციის დამყარება Nextcloud Notes-თან" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "შესვლა" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Nextcloud-თან კავშირის გათიშვა" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "Signs out from Nextcloud Notes. All notes will be removed and the app will quit." msgstr "გასვლა Nextcloud Notes-დან. ყველა შენიშვნა წაიშლება და აპი დაასრულებს მუშაობას." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "გათიშვა" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "მონაცემთა ბაზის ჩამოყრა" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "ყველა შენიშვნის წაშლა ლოკალური მონაცემთა ბაზიდან. აპი მუშაობას დაასრულებს." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "ჩამოყრა" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "გამართვა" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "სინქრონიზაციიცს დროის შტამპის გასუფთავება" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "ყველა შენიშვნის ნაძალადევი სინქრონიზაცია სერვერიდან" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "გასუფთავება" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "მონიშნულის წაშლა" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "რჩეულობის გადართვა მონიშნულისთვის" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "კატეგორიის შეცვლა მონიშნულისთვის" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "კატეგორიების დახურვა" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "კატეგორიები" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "ცხრილის ჩასმა" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "შექმნა" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "სისტემის სტილის მიყოლა" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "ღია სტილი" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "მუქი სტილი" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "შენიშვნის შექმნა" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "მარქაფის შექმნა" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "მარქაფის აღდგენა" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "მარქაფის ბილიკის ჩვენება" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "ბილიკის ჩვენება მორგებული სერვერის SSL CA ჯაჭვის ფაილისთვის" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "ინტერფეისში გაფართოებული პარამეტრების ჩვენების გადართვა" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "გადით გაშვებული ასლებიდან" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "გამართვის დონის ჟურნალისა და ფუნქციების ჩართვა" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "შენიშვნის გახსნა id-ით" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "ძებნა შენიშვნებში" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "RESTORATION REMOTE ID CLASH" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "RESTORATION TITLE CLASH" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "ყველა შენიშვნა" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "კატეგორიის გარეშე" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "ხაზის სიგრძე ახლა {0} პიქსელია" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "ხაზის სიგრძის შეზღუდვა გამორთულია" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "ბმულის გახსნა ბრაუზერში" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} {1}-დან" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "გატანილია ფაილში {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "{}-ში გატანა ჩავარდა" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "გადაცემა ჩავარდა" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} შენიშვნა წაიშალა" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "შენიშვნა წაიშალა" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "დაბრუნება" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "სინქრონიზაციის კონფლიქტი შენიშვნასთან, რომელსაც ასწორებთ" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "შენიშვნა, რომლის ჩასწორებაც მიმდინარეობს, დაშორებულად წაიშალა" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-keyring which has a default keyring setup that is " "unlocked." msgstr "" "საიდუმლო სერვისთან წვდომა ჩავარდა. დარწმუნდით, რომ გაქვთ gnome-keyring-ის მსგავსი პროვაიდერი, რომელსაც აქვს ნაგულისხმევი " "ბრელოკი მორგებული და რომ ის განბლოკილია." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "სინქრონიზაცია" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} ცვლილება" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "სინქრონიზაცია ჩავარდა. არის Nextcloud Notes-ის აპი დაყენებული სერვერზე?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "იტვირთება" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "ბმულის ჩასმა" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "ბმულის ჩასწორება" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "მიმდინარეობს შენიშვნების განახლება" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "სრულდება პირველი გადაცემა" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "დაკავშირება" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "შესვლის მოლოდინი" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "დაასრულეთ ავთენტიკაცია თქვენ ბრაუზერში" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "შესვლის დაწყება ჩავარდა შესაძლო სერტიფიკატის პრობლემის გამო" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "შესვლის დაწყება ჩავარდა. მისამართი არასწორია?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "შავთეთრი" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "დადუმებული Markup" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "სქელი Markup" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "გამორთული" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "ხმა გამორთული" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "ლურჯი" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "ნარინჯისფერი" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "წითელი" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "არცერთი" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "ყოველთვის ხილული" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "ავტომატურად დამალვა" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "ავტომატური დამალვა სრულ ეკრანზე" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "შემცირება {0} დაჭერაში" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "გაფართოება {0} დაჭერაში" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "გაფართოებული დამალული" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "გაფართოებული ნაჩვენები" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "დამალვა მობილურზე სასურველი არაა" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "ჩამოვყარო მონაცემთა ბაზა?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "ყველა შენიშვნა წაიშლება. გავაგრძელო ჩამოყრა?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "გავთიშო Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "წაიშლება ყველა შენიშვნა. გნებავთ, გახვიდეთ?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "მხოლოდ-წაკითხვის რეჟიმში კატეგორიის შეცვლა შეუძლებელია" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} მონიშნულია" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "SYNC CONFLICT" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "შეცდომა" #~ msgid "Export As..." #~ msgstr "გატანა, როგორც..." #~ msgid "Exporting..." #~ msgstr "გატანა…" #~ msgid "OK" #~ msgstr "დიახ" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/meson.build000066400000000000000000000001441507102636600231610ustar00rootroot00000000000000i18n = import('i18n') message('Update translations') i18n.gettext(gettext_package, preset: 'glib') iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/nl.po000066400000000000000000000701261507102636600217770ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Heimen Stoffels , 2023. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-02-06 14:56+1100\n" "PO-Revision-Date: 2023-02-11 11:08+0100\n" "Last-Translator: Heimen Stoffels \n" "Language-Team: Dutch\n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.2.2\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.gitlab.cheywood.Iotas.desktop.in.in:4 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.gitlab.cheywood.Iotas.desktop.in.in:6 msgid "Simple note taking with Nextcloud Notes" msgstr "Eenvoudige notitietoepassing met Nextcloud Notities-synchronisatie" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.gitlab.cheywood.Iotas.desktop.in.in:14 msgid "notes;nextcloud;base;" msgstr "notities;nextcloud;basis;" #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:7 msgid "Theme used by editor view" msgstr "Het thema van de bewerker" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:9 msgid "The GtkSourceView style scheme id" msgstr "De GtkSourceView-stijl-id" #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:14 msgid "First start" msgstr "Allereerste opstart" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:16 msgid "Whether starting for the first time." msgstr "Of het scherm na de allereerste opstart dient te worden getoond." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:21 msgid "Font size" msgstr "Tekstgrootte" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:23 msgid "Font used in main editor view." msgstr "De tekstgrootte in de bewerker." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:28 msgid "Whether to use a monospace font" msgstr "Of het vastebreedtelettertype gebruikt dient te worden" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:30 msgid "" "The specific fonts are sourced from GNOME's monospace and document font " "settings" msgstr "De gebruikte lettertypen zijn die uit GNOME's systeemvoorkeuren" #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:35 msgid "Markdown render view support" msgstr "Markdownweergave" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:37 msgid "" "Whether to support showing markdown render view (a temporary performance " "concession for a WebKit issue)" msgstr "" "Of de markdownweergave dient te worden opgemaakt (tijdelijke oplossing in " "verband met prestatieproblemen van WebKit)" #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:42 msgid "Markdown syntax highlighting" msgstr "Markdown-syntaxismarkering" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:44 msgid "Whether to highlight markdown syntax." msgstr "Of markdownsyntaxis dient te worden gemarkeerd." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:49 msgid "Markdown WebKit process retention." msgstr "Markdown WebKit-proces in geheugen houden" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:51 msgid "" "When enabled the WebKit process is retained between uses of the render view, " "decreasing load time and increasing memory usage." msgstr "" "Schakel in om het WebKit-proces te allen tijde in het geheugen te houden. " "Hierdoor wordt de laadtijd verkort, maar neemt het geheugengebruik toe." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:56 msgid "Nextcloud server to sync against" msgstr "Nextcloud-synchronisatieserver" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:58 msgid "Path to the last Nextcloud sync instance." msgstr "De locatie van de Nextcloud-synchronisatieserver." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:63 msgid "Username for the Nextcloud sync server" msgstr "Gebruikersnaam op Nextcloud-synchronisatieserver" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:65 msgid "Login to use with the Nextcloud sync instance." msgstr "De gebruikersnaam van de Nextcloud-synchronisatieserver." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:70 msgid "Prune threshold for Nextcloud sync" msgstr "Verwijderwaarde van Nextcloud-synchronisatie" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:72 msgid "" "Used to reduce the number of records pulled from the Nextcloud server during " "sync." msgstr "Wordt gebruikt om het aantal items van de server te beperken." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:77 msgid "Whether to show a message on Secret Service failure" msgstr "Bericht tonen bij foutmelding van Secret Service" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:79 msgid "" "Disabling this provides for a cleaner startup if never intending to use " "Nextcloud Notes sync. on a device without a Secret Service provider." msgstr "" "Schakel uit om ‘netter’ op te starten, maar alléén als u geen gebruik wenst " "te maken van Nextcloud-synchronisatie." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:84 msgid "Spelling enabled" msgstr "Spelling controleren" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:86 msgid "Whether spell checking is enabled." msgstr "Schakel spellingcontrole in/uit." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:91 msgid "Spelling language" msgstr "Controletaal" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:93 msgid "Language tag to attempt to use by default for spelling." msgstr "De taal waarin de spelling dient te worden gecontroleerd." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:103 msgid "Colour scheme style" msgstr "Thema" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:105 msgid "" "Choosing to follow desktop colour style or enforce dark or light visuals." msgstr "Kies uit het lichte, donkere of systeemthema." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:110 msgid "Sync interval" msgstr "Synchronisatieperiode" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:112 msgid "Interval between pulling from the Nextcloud sync server (seconds)." msgstr "" "De periode tussen het synchroniseren met de Nextcloud-server (in seconden)." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:117 msgid "Window size" msgstr "Vensterafmetingen" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:119 msgid "Remember the window size." msgstr "Onthoud de vensterafmetingen." #. Translators: GSettings summary (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:124 msgid "Whether to hide the editor headerbar when fullscreen" msgstr "" "Of de kopbalk automatisch moet worden verborgen in de schermvullende weergave" #. Translators: GSettings description (low translation priority) #: data/org.gnome.gitlab.cheywood.Iotas.gschema.xml.in:126 msgid "" "Setting to true automatically hides the editor headerbar entering fullscreen " "mode" msgstr "" "Schakel in om de kopbalk automatisch te verbergen in de schermvullende " "weergave" #. Translators: The application's summary / tagline #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Eenvoudige notitietoepassing" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:14 msgid "" "Note: It's fairly early days in development here, so please expect a few " "rough edges." msgstr "" "Let op: de toepassing staat nog in de kinderschoenen, dus nog niet alles is " "af." #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:16 msgid "" "Iotas is a simple note taking app with mobile-first design and a focus on " "sync with a Nextcloud Notes." msgstr "" "Iotas is een eenvoudige notitietoepassing met smartphone-ontwerp en " "Nextcloud Notities-synchronisatie." #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:18 msgid "Although consciously bare bones there are a few features" msgstr "De toepassing is eenvoudig doch voorzien van enkele functies" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:21 msgid "Sync. with Nextcloud Notes" msgstr "Synchronisatie met Nextcloud Notities" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:23 msgid "Offline note editing, syncing when back online" msgstr "Offline-notitiebewerking en synchronisatie nadien" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:25 msgid "Basic search" msgstr "Eenvoudig zoeken" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:27 #: data/ui/index.ui:222 msgid "Favorites" msgstr "Favorieten" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:29 msgid "Spell checking" msgstr "Spellingcontrole" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:31 msgid "Optional markdown syntax highlighting and rendered view" msgstr "Optioneel: markdown-syntaxismarkering en opgemaakte weergave" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:33 msgid "Follow system-wide dark style preference or make own choice" msgstr "Gebruik het systeemthema af kies een ander thema" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:35 msgid "Ability to change font size" msgstr "Pas de tekstgrootte aan" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:38 msgid "Slightly more technical details, for those into that type of thing" msgstr "" "Nu volgen enkele technische gegevens, voor zij die dat op prijs stellen" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:41 msgid "" "Nextcloud Notes sync. is via the REST API, not WebDAV, which makes it snappy" msgstr "" "Nextcloud Notities-synchronisatie met behulp van de REST-api, niet WebDAV, " "voor betere prestaties" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:43 msgid "There's basic sync. conflict detection" msgstr "Eenvoudige conflictdetectie tijdens synchronisaties" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:45 msgid "Notes are constantly saved" msgstr "Notities worden voortdurend opgeslagen" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:47 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Grote verzamelingen worden slechts deels ingeladen om het opstarten sneller " "te maken" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:50 msgid "Current obvious feature omissions" msgstr "Huidige opvallende tekortkomingen" #. Translators: Part of metainfo description #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:53 msgid "Categories" msgstr "Categorieën" #. Translators: Part of metainfo description. "Iotas" is the application name, do not translate. Left to your discretion whether it makes sense to translate "iota" or not. #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:56 msgid "" "Why \"Iotas\"? An iota is a little bit and this app is designed for jotting " "down little things on little devices. Iota stems from the same Greek word as " "jot and is commonly used in negative statements eg. \"not one iota of …\", " "but we think the word has more to give. Maybe somebody will take note?" msgstr "" "Hoe is de naam ‘Iotas’ ontstaan? Een ‘iota’ is een klein deeltje en deze " "toepassing is gemaakt voor het noteren van kleine dingen op kleine " "apparaten. ‘Iota’ is afgeleid van het Griekse woord ‘jot’ en wordt vaak " "gebruikt in negatieve zin, zoals “nog geen iota van…”. Wij zijn echter van " "mening dat het woord meer in zijn mars heeft. Noteer dat maar." #. Translators: A screenshot description. #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:61 msgid "Mobile index" msgstr "Mobiel overzicht" #. Translators: A screenshot description. #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:66 msgid "Mobile editor" msgstr "Mobiele bewerker" #. Translators: A screenshot description. #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:71 msgid "Mobile index dark style" msgstr "Mobiel overzicht (donker thema)" #. Translators: A screenshot description. #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:76 msgid "Desktop index" msgstr "Computeroverzicht" #. Translators: A screenshot description. #: data/org.gnome.gitlab.cheywood.Iotas.metainfo.xml.in.in:81 msgid "Desktop index dark style" msgstr "Computeroverzicht (donker thema)" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Heimen Stoffels " #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_window.ui:65 msgid "Edit title" msgstr "Titel wijzigen" #. Translators: Menu item #: data/ui/editor.ui:23 msgid "Find" msgstr "Zoeken" #. Translators: Menu item #: data/ui/editor.ui:28 data/ui/index_row_popover.ui:20 msgid "Delete" msgstr "Verwijderen" #. Translators: Button #: data/ui/editor.ui:43 msgid "Back to Notes" msgstr "Terug naar notities" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:72 data/ui/keyboard_shortcuts_window.ui:72 msgid "Display markdown render" msgstr "Markdownweergave tonen" #. Translators: Button #: data/ui/editor.ui:80 msgid "Edit note" msgstr "Notitie bewerken" #. Translators: Button #: data/ui/editor.ui:96 msgid "Revert changes" msgstr "Wijzigingen terugdraaien" #. Translators: Button tooltip #: data/ui/editor.ui:119 msgid "Apply changes" msgstr "Wijzigingen toepassen" #. Translators: Button #: data/ui/editor.ui:121 msgid "Apply" msgstr "Toepassen" #. Translators: Button #: data/ui/editor.ui:141 data/ui/index.ui:94 msgid "Back" msgstr "Terug" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:161 data/ui/keyboard_shortcuts_window.ui:134 msgid "Previous match" msgstr "Vorige overeenkomst" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:169 data/ui/keyboard_shortcuts_window.ui:127 msgid "Next match" msgstr "Volgende overeenkomst" #. Translators: Title #: data/ui/empty_state.ui:11 msgid "Let's get started" msgstr "Aan de slag" #. Translators: Description, help #: data/ui/empty_state.ui:43 msgid "Add new feeds via URL" msgstr "Feeds toevoegen via url" #. Translators: Description, help #: data/ui/empty_state.ui:54 msgid "Import an OPML file" msgstr "Opml-bestand importeren" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom out" msgstr "Uitzoomen" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom in" msgstr "Inzoomen" #. Translators: Menu item #: data/ui/index_row_popover.ui:8 msgid "Add Favorite" msgstr "Toevoegen aan favorieten" #. Translators: Menu item #: data/ui/index_row_popover.ui:14 msgid "Remove Favorite" msgstr "Verwijderen uit favorieten" #. Translators: Menu item #. Translators: Description, introduction help #: data/ui/index.ui:13 data/ui/index.ui:169 msgid "Sync with Nextcloud Notes" msgstr "Synchroniseren met Nextcloud Notities" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/index.ui:19 data/ui/keyboard_shortcuts_window.ui:31 msgid "Refresh" msgstr "Herladen" #. Translators: Menu item #: data/ui/index.ui:27 msgid "Preferences" msgstr "Voorkeuren" #. Translators: Menu item #: data/ui/index.ui:32 msgid "Keyboard Shortcuts" msgstr "Sneltoetsen" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index.ui:37 msgid "About Iotas" msgstr "Over Iotas" #. Translators: Button #: data/ui/index.ui:55 msgid "New note" msgstr "Notitie maken" #. Translators: Button #: data/ui/index.ui:63 msgid "Menu" msgstr "Menu" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:71 data/ui/keyboard_shortcuts_window.ui:24 #: data/ui/keyboard_shortcuts_window.ui:120 msgid "Search" msgstr "Zoeken" #. Translators: Tooltip #: data/ui/index.ui:79 msgid "Sync. offline" msgstr "Synchronisatie is offline" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/index.ui:130 msgid "Welcome to Iotas" msgstr "Welkom bij Iotas" #. Translators: Description, introduction help #: data/ui/index.ui:149 msgid "Add a note" msgstr "Notitie maken" #. Translators: Description, help #: data/ui/index.ui:184 msgid "Note list empty" msgstr "De lijst is blanco" #. Translators: Description, help #: data/ui/index.ui:191 msgid "Enter search term" msgstr "Voer een zoekopdracht in" #. Translators: Description, help #: data/ui/index.ui:198 msgid "No search results" msgstr "Er zijn geen zoekresultaten" #. Translators: Section title #: data/ui/index.ui:263 msgid "Today" msgstr "Vandaag" #. Translators: Section title #: data/ui/index.ui:295 msgid "Yesterday" msgstr "Gisteren" #. Translators: Section title #: data/ui/index.ui:327 msgid "This Week" msgstr "Deze week" #. Translators: Section title #: data/ui/index.ui:359 msgid "This Month" msgstr "Deze maand" #. Translators: Section title #: data/ui/index.ui:391 msgid "Last Month" msgstr "Vorige maand" #. Translators: Button, the rest here meaning the remainder / everything else #: data/ui/index.ui:422 msgid "Load the Rest" msgstr "Meer laden" #. Translators: Section title, the rest here meaning the remainder / everything else #: data/ui/index.ui:440 msgid "The Rest" msgstr "Meer" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:12 msgid "Index" msgstr "Overzicht" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:17 msgid "Create new note" msgstr "Notitie maken" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:38 msgid "Delete note" msgstr "Notitie verwijderen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:45 msgid "Move up list" msgstr "Omhoog verplaatsen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:52 msgid "Move down list" msgstr "Omlaag verplaatsen" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:60 data/ui/preferences_window.ui:16 msgid "Editor" msgstr "Bewerker" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:79 msgid "Toggle fullscreen" msgstr "Schermvullende weergave aan/uit" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:86 msgid "Toggle headerbar" msgstr "Kopbalk aan/uit" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:93 msgid "Undo typing" msgstr "Typen ongedaan maken" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:100 msgid "Redo typing" msgstr "Typen herhalen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_window.ui:107 msgid "Return to Index" msgstr "Terug naar overzicht" #. Translators: Title #: data/ui/keyboard_shortcuts_window.ui:115 msgid "Searching" msgstr "Zoeken" #. Translators: Button #: data/ui/nextcloud_login_window.ui:21 msgid "Cancel" msgstr "Annuleren" #. Translators: Button #: data/ui/nextcloud_login_window.ui:30 msgid "Continue" msgstr "Doorgaan" #. Translators: Description #: data/ui/nextcloud_login_window.ui:67 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Klik op ‘Doorgaan’ om een Nextcloud-serveradres en inloggegevens in te " "voeren met behulp van een webbrowser" #. Translators: Description #: data/ui/nextcloud_login_window.ui:95 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "De Secret Service kan niet worden gebruikt voor het bewaren van " "authenticatiegegevens. Zorg er voor dat u een dienst als gnome-keyring heeft " "ingesteld en dat de sleutelbos ontgrendeld is. De meeste werkomgevingen doen " "dit standaard voor u. Herstart om opnieuw te proberen." #. Translators: Description #: data/ui/nextcloud_login_window.ui:116 msgid "Nextcloud Server URL" msgstr "Nextcloud-server-url" #. Translators: Description #: data/ui/nextcloud_login_window.ui:148 msgid "Waiting for completion of login in browser" msgstr "Bezig met wachten op afronden van inlogproces…" #. Translators: Description #: data/ui/nextcloud_login_window.ui:181 msgid "Connection established with Nextcloud Notes" msgstr "Er is verbinding gemaakt met Nextcloud Notities" #. Translators: Title #: data/ui/preferences_window.ui:12 msgid "General" msgstr "Algemeen" #. Translators: Title #: data/ui/preferences_window.ui:20 msgid "Use Monospace Font" msgstr "Vastebreedtelettertype gebruiken" #. Translators: Title #: data/ui/preferences_window.ui:33 msgid "Check Spelling" msgstr "Spelling controleren" #. Translators: Description, preference #: data/ui/preferences_window.ui:35 msgid "Limited functionality on mobile for now." msgstr "" "Let op: in de mobiele weergave is het aantal functies momenteel beperkt." #. Translators: Title #: data/ui/preferences_window.ui:50 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_window.ui:54 msgid "Enable Render View" msgstr "Voorvertonen" #. Translators: Description, preference #: data/ui/preferences_window.ui:56 msgid "Disable to reduce startup time. Restart to update." msgstr "" "Schakel uit om het opstarten sneller te maken. Herstart om de wijziging toe " "te passen." #. Translators: Title #: data/ui/preferences_window.ui:69 msgid "Highlight Syntax" msgstr "Syntaxis markeren" #. Translators: Description, preference #: data/ui/preferences_window.ui:71 msgid "Disable for improved performance." msgstr "Schakel uit om de prestaties te verbeteren." #. Translators: Description, preference #: data/ui/preferences_window.ui:84 msgid "Syntax Theme" msgstr "Syntaxisschema" #. Translators: Title #: data/ui/preferences_window.ui:92 msgid "Sync" msgstr "Synchroniseren" #. Translators: Title #: data/ui/preferences_window.ui:96 msgid "Disconnect Nextcloud" msgstr "Nextcloud loskoppelen" #. Translators: Description, preference #: data/ui/preferences_window.ui:98 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Log uit van Nextcloud Notities. Hierdoor worden alle notities gewist en de " "toepassing afgesloten." #. Translators: Title #: data/ui/preferences_window.ui:122 msgid "Debug" msgstr "Foutopsporing" #. Translators: Title #: data/ui/preferences_window.ui:126 msgid "Temporary Debug Functions" msgstr "Tijdelijke foutopsporingsfuncties" #. Translators: Title #: data/ui/preferences_window.ui:130 msgid "Reset Database" msgstr "Databank herstellen" #. Translators: Description, preference #: data/ui/preferences_window.ui:132 msgid "Delete all notes from the local database. The app will quit." msgstr "" "Wis alle notities uit de lokale databank. Hierdoor wordt de toepassing " "afgesloten." #. Translators: Title #: data/ui/preferences_window.ui:150 msgid "Clear Sync Timestamp" msgstr "Synchronisatietijdstip wissen" #. Translators: Description, preference #: data/ui/preferences_window.ui:152 msgid "Forces a pull of all notes from the sync server." msgstr "Dwingt af om alle notities van de server op te halen." #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:26 data/ui/theme_selector.ui:29 msgid "Follow system style" msgstr "Systeemthema" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:45 data/ui/theme_selector.ui:48 msgid "Light style" msgstr "Licht thema" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:64 data/ui/theme_selector.ui:67 msgid "Dark style" msgstr "Donker thema" #. Translators: Description, notification #: iotas/index.py:154 iotas/index.py:412 msgid "Loading" msgstr "Bezig met laden…" #. Translators: Description, notification #: iotas/index.py:278 msgid "Note deleted" msgstr "De notitie is gewist" #. Translators: Button #: iotas/index.py:281 msgid "Undo" msgstr "Ongedaan maken" #. Translators: Description, notification #: iotas/index.py:291 msgid "Sync conflict with note being edited" msgstr "Synchronisatieconflict met bewerkte notitie" #. Translators: Description, notification #: iotas/index.py:769 msgid "Syncing" msgstr "Bezig met synchroniseren…" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" #. should likely not be translated. #: iotas/index.py:783 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "De Secret Service kan niet worden aangesproken. Zorg er voor dat u een " "dienst als gnome-keyring heeft ingesteld en dat de sleutelbos ontgrendeld is." #. Translators: Button #: iotas/index.py:789 msgid "OK" msgstr "Oké" #. Translators: Button #: iotas/nextcloud_login_window.py:93 msgid "Finish" msgstr "Afronden" #. Translators: Description, notification #: iotas/nextcloud_login_window.py:154 msgid "Failed to start login. Wrong address?" msgstr "Her inloggen is mislukt - controleer het adres." #. Translators: Description, used as a prefix to the previous title {} for notes updated #. both locally and remotely. #: iotas/sync_manager.py:385 msgid "SYNC CONFLICT - {}" msgstr "SYNCHRONISATIECONFLICT - {}" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/oc.po000066400000000000000000001616271507102636600217760ustar00rootroot00000000000000# Occitan translation file. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Quentin PAGÈS, 2024. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-20 06:08+0000\n" "PO-Revision-Date: 2025-09-20 08:32+0200\n" "Last-Translator: Quentin PAGÈS\n" "Language-Team: \n" "Language: oc\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.7\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Presa de nòtas facila amb Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "nòtas;nextcloud;minimal;distraccion;editor;concentracion;tèxte;escriure;markdown;document;gnome;gtk;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Nòta novèla" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Presa de nòtas facila" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "Iotas aims to provide distraction-free note taking via its mobile-first design." msgstr "" "Iotas a per objectiu de facilitar la presa de nòtas sens distraccion a travèrs de son primièr dessenh " "mobil." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Foncionalitats" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Sincro. rapida amb Nextcloud Notas opcionala" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Edicion de nòta fòra linha, sincro quand en linha de nòu" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Edicion e filtratge per categoria" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Marcapaginas" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Correccion ortografica" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Recercar dins la colleccion o dins las nòtas individualas" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "Mòde concentracion e opcion per rescondre opcionalament las barras d’entèsta e de formatatge" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "En apercebut : expòrt en PDF, ODT e HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "Una concepcion convergenta, per veire Iotas tant a l’ostal sul burèu coma sus mobil" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Cèrca a partir de GNOME Shell" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "Salvagarda e restauracion de las nòtas (via linha de comanda, per usatge sens sincronizacion)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "La possibilitat de modificar la talha de la polissa e bascular entre estil sens chassa" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Escriure en markdown es suportat mas opcional, en ofrissent" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formatatge via la barra d’aisinas e acorchis" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Coloracion sintaxica amb tèmas" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Una vista formatada" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "La capacitat de verificar las listas de prètzfaches de la vista formatada" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Un pauc mai de detalhs tecnics, per aqueles los que lor agrada aquel tipe de causas" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "La sincronizacion Nexcloud Notes es via REST API e non pas WebDAV, çò que l’accelèra" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "I a una deteccion de conflictes de sincronizacion basica" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Las nòtas son enregistradas en permanéncia" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "Las bravas colleccions de nòtas son cargadas en partida per accelerar l’aviada" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without reinventing the wheel. Plain files can " "be retrieved by making a backup (CLI)." msgstr "" "Las notas son gardadas dins SQLite, en fornissent una recèrca rapida (FTS) sens tornar inventar la ròda. " "Los fichièrs simples se pòdon recuperar en fasent una còpia de seguretat (CLI)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 data/ui/keyboard_shortcuts_dialog.ui:7 #: data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Indèx" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editor amb markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Rendut markflow" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Indèx en estil fosc" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobil" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Quentin PAGÈS" #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Anullacion de modificacions" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Aplicar las modificacions" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 iotas/link_dialog.py:52 msgid "Apply" msgstr "Aplicar" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Escafar e aplicar" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Trobar" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Tornar" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 data/ui/keyboard_shortcuts_dialog.ui:289 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Ocurréncia precedenta" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 data/ui/keyboard_shortcuts_dialog.ui:282 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Ocurréncia seguenta" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Remplaçar" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Mòde concentracion" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Recercar e remplaçar…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Anar a…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Modificar lo títol…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Cambiar de categoria…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Suprimir" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Exportar…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Tornar a las nòtas" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Nòta en lectura sola" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Menú de l'editor" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Alternar lo rendut markdown" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Editar la nòta" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Cargament del motor de rendut" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "Anullar" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Exportar coma…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "Telecargament…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Exportacion…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 data/ui/outline_dialog.ui:104 #: iotas/ui_utils.py:92 msgid "Close" msgstr "Tampar" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Mostrar" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "Un o mantun fichièr junt se podiá pas transferir." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Tornar ensajar" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "Exportar malgrat tot" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "La benvenguda a Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Utilizar la barra d’entèsta per…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Ajustar una nòta" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Sincro. amb Nextcloud Notas" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Zoom arrièr" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Zoom avant" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Barra orizontala" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Citacion" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Còdi" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Tablèu" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Nivèl 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Nivèl 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Nivèl 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Nivèl 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Levar" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Entèsta" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Gras" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Italica" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Raiat" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Lista non ordenada" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Lista ordenada" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Casa de marcar" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Ligam" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Actualizar" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Preferéncias" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Acorchis de clavièr" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "A prepaus de Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Menú principal" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Uèi" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Ièr" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Aquesta setmana" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Aqueste mes" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Lo mes passat" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Mostrar meses precedents" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Abans lo mes passat" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Ne veire mai" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Dobrir las categorias" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Recercar" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Seleccionar las nòtas" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Connexion al servidor fòra linha" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to reauthenticate with your Nextcloud server" msgstr "" "A causa de modificacion en colissa (un ID d’aplicacion novèl) Iotas requerís una autentificacion novèla " "amb vòstre servidor Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "S’autentificar" #. Translators: Description #: data/ui/index.ui:102 msgid "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "Lo geton d’autentificacion per la sincronizacion amb Nextcloud Notes se podiá pas recuperar" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Ignorar" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Lista de nòtas voida" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Picatz un tèrme de recercar" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Pas cap de resultats de recèrca" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Crear una nòta novèla" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Afichar lo panèl lateral" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Suprimir la nòta" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Montar dins la lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Davalar dins la lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Començar la seleccion" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "Dobrir en primièr los resultats de recèrca" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "Reïnicializar los filtres" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Modificar lo títol" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Cambiar de categoria" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Exportar" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Sautar a la seleccion" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Crear una nòta novèla en inclusent la seleccion" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Anullar la picada" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Restablir la picada" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Inserir un Emoji" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Metre lo fòcus sus la vista tèxte" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Metre lo fòcus sus la barra d’entèsta" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Metre lo fòcus sus la barra de formatatge" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Formatatge" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Alternar la casa" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Recèrca de l’editor" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Aparéncia de l’editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Aumentar la longor de linha" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Reduire la longor de linha" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Aumentar la talha de la polissa" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Reduire la talha de la polissa" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "General" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Bascular en mòde ecran complèt" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Afichar las preferéncias" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Afichar los acorchis" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Dobrir la nòta precedenta" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Tornar" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Quitar" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Tèxte" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Configuracion de Nextcloud Notas" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "Press Continue to provide your Nextcloud server address and login via a web browser" msgstr "" "Quichatz Contunhar per fornir l’adreça del servidor Nextcloud e los identificants via lo navegador web" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Contunhar" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Contunhar cap a l’URL" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Servici Secret inaccessible" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. Ensure you have a provider " "such as gnome-keyring. A default keyring needs to be setup, and that keyring unlocked. Most desktop " "environments will provide this for you. Restart the app to try again." msgstr "" "Se podiá pas accedir al servici Secret pels detalhs d’autentificacion. Asseguratz-vos d’aver un provesidor " "coma gnome-keyring. Cal aver un trossèl configurat e qu’aqueste trossèl siá desverrolhat. La màger part " "dels environaments de burèu vos'n fornisson un. Reaviatz l’aplicacion per tornar ensajar." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "URL servidor" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Començar l’autentificacion" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Certificats auto-signats" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server identity not being verified. " "If this is expected please follow the instructions in the FAQ to provide a CA chain file." msgstr "" "Sembla qu’utilizatz un certificat SSL auto-signat aquò fa que l’identitat del servidor es pas verificada. " "S’aquò es esperat, seguissètz las instruccions dins la FAQ per provesir un fichièr de cadena CA." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Dobrir la FAQ" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Connexion establida" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Acabat" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Configuracion de sincronizacion complèta" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Contorn" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Cap de títol correspondent pas al filtre" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Cap de títols pas trobat pel contorn" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Interfàcia" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Utilizar polissa de chassa fixa" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Verificar l'ortografia" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Modificar la lenga via lo menú de contextual de l'editor" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Barra d’entèsta" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Limit de longor linha" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "D’en primièr pels ordenadors de burèu. Utilizatz Ctrl + ↑ e Ctrl + ↓ sul clavièr per ajustar." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Detectar la sintaxi" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard shortcuts). Disable for slightly " "improved performance." msgstr "" "Necessari per a la mesa en fòrma de la sintaxi e lo formatatge (barra d'aisinas e acorchis clavièr). " "Desactivar per una leugièra melhora de performança." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Tèma" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Barra de formatatge" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Activar la vista formatada" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Desactivar per reduire lo temps d’aviada" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Dobrir la vista formatada" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "L’activacion dobrís totas las nòtas en rendut markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Presa en carga de las equacions matematicas" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Redusís leugièrament las performanças del motor de rendut" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Rendut en utilizant la polissa sens chassa" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Racio de talha de polissa de proporcional fins a sens chassa" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "En vista rendut. Utilizar 1 per cap d’ajustament." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Gardar lo motor en memòria" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Conversions de jos sequéncias mai rapidament amb usatge memòria mai naut" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Pegar lo panèl lateral" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Sus ordenador, quand i a de plaça" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Estil d’etiqueta de categoria" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Donadas" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Connectar Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Establir la sincro. amb Nextcloud Notas" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Connexion" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Desconnectar Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "Signs out from Nextcloud Notes. All notes will be removed and the app will quit." msgstr "Desconnècta de Nextcloud Notes. Totas las nòtas seràn levadas e l’aplicacion se tamparà." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Se desconnectar" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Reinicializar la basa de donadas" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "Suprimir totas las nòtas de la basa de donadas locala. L’aplicacion se tamparà." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Reïnicializar" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Desbugatge" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Escafar l’orodatatge de sincronizacion" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Fòrça una recuperacion de totas las nòtas d’al servidor de sincronizacion" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Escafar" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Suprimir la seleccion" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Alternar marcatge en favorit per la seleccion" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Modificar la categoria per la seleccion" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Tampar las categorias" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Categorias" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Inserir un tablèu" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Crear" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Seguir lo tèma del sistèma" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Estil clar" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Estil escur" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Crear una nòta" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Crear una salvagarda" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Restablir una salvagarda" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Mostrar l’emplaçament de salvagarda" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "Afichar l’emplaçament pel fichièr chain CA SSL del servidor personalizat" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "Alternar l’afichatge de las preferéncias espandidas dins l’interfàcia utilizaire" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Quitar tota instància en execucion" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Activar la jornalizacion e las foncions de desbugatge" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Dobrir nòta per ID" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Recercar dins las nòtas" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "RESTAURACION D'ID DISTANT EN CONFLICTE" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "RESTAURACION DEL TÍTOL CLASH" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Totas las nòtas" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Non categorizada" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "La longor de linha es ara {0} px" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Limit de longor linha desactivat" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Dobertura del ligam dins lo navegador" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} de {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "Exportat en {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "Fracàs de l'exportacion dins {}" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Fracàs del transferiment" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} nòtas suprimidas" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Nòta suprimida" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Desfar" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Conflicte de sincronizacion amb una nòta en edicion" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "La nòta en edicion es estada suprimida a distància" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-keyring which has a default " "keyring setup that is unlocked." msgstr "" "Fracàs de l’accès al servici Secret. Asseguratz-vos qu’avètz un provesidor coma gnome-keyring qu'a una " "configuracion de clau de defaut desverrolhat." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Sincronizacion" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} modificacion" msgstr[1] "{} modificacions" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Fracàs de la sincronizacion. Es l’aplicacion Nextcloud Notes installada sul servidor ?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Cargament" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Inserir un ligam" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Editar lo ligam" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Actualizacion de las nòtas" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "Realizacion del transferiment inicial" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "Connexion" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "En espèra d’autentificacion" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Terminar l’autentificacion dins vòstre navegador" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "Fracàs de la debuta de l’autentificacion amb un probable problèma de certificat" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Fracàs de la debuta de l’autentificacion. Marrida adreça ?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Monocròm" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Balisatge silenciós" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Balisatge en gras" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Desactivat" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Palle" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Blau" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Irange" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Roge" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "Pas cap" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Totjorn visible" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Amagar automaticament" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Amagar automaticament en ecran complèt" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Reduccion en {0} processús" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "Espandiada en {0} processús" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Espandida amagada" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Espandida mostrada" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "Amagar es pas recomandat sus mobil" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Reinicializar la basa de donadas ?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "Totas las nòtas seràn suprimidas. Validar la reïnicializacion ?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Se desconnectar Nextcloud ?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "Totas las nòtas seràn suprimidas. Validar la desconnexion ?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Impossible de cambiar la categorias de las nòtas en lectura sola" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} seleccionats" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "CONFLICTE SINCRO" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Error" #~ msgid "Exporting..." #~ msgstr "Exportacion..." #~ msgid "OK" #~ msgstr "D'acòrdi" #~ msgid "Bold Markup (High Contrast)" #~ msgstr "Balisatge gras (fòrt contrast)" #~ msgid "Muted Markup (High Contrast)" #~ msgstr "Balisatge silenciós (fòrt contrast)" #~ msgid "Monochrome (High Contrast)" #~ msgstr "Monocròm (fòrt contrast)" #~ msgid "Disabled (High Contrast)" #~ msgstr "Desactivat (fòrt contrast)" #~ msgid "Disable" #~ msgstr "Desactivar" #~ msgid "Return to Index" #~ msgstr "Tornar a l'indèx" #~ msgid "Line length limit already disabled" #~ msgstr "Lo limit de longor linha es ja desactivat" #~ msgid "Font size now {0}pt" #~ msgstr "La talha de polissa es ara {0} pt" #, fuzzy #~| msgid "Read-only note" #~ msgid "Read-Only Note" #~ msgstr "Nòta en lectura sola" #~ msgid "Waiting for completion of login in browser" #~ msgstr "En espèra de fin d’autentificacion dins lo navegador" #~ msgid "Syntax Theme" #~ msgstr "Tèma sintaxi" #~ msgid "Finish" #~ msgstr "Acabar" #~ msgid "" #~ "Why \"Iotas\"? An iota is a little bit and this app is designed for jotting down little things on " #~ "little devices. Iota stems from the same Greek word as jot and is commonly used in negative statements " #~ "eg. \"not one iota of …\", but we think the word has more to give. Maybe somebody will take note?" #~ msgstr "" #~ "Perque « Iotas » ? Un iota es un pauc e aquesta aplicacion es concebuda per escriure de causas pichonas " #~ "sus de dispositius pichons. Iota ven del meteis mot grèc que jot e es comunament utilizat dins de " #~ "declaracions negativas, per exemple, « pas una iota de... », mas pensam que lo mot a mai a donar. " #~ "Qualqu'un pòt prendre nòta ?" #~ msgid "Go back" #~ msgstr "Retorn" #~ msgid "Highlight Syntax" #~ msgstr "Metre en susbrilhança la sintaxi" #~ msgid "Disable for slightly improved performance." #~ msgstr "Desactivar per de pichonas melhoras performanças." #~ msgid "Let's get started" #~ msgstr "Comencem" #~ msgid "Add new feeds via URL" #~ msgstr "Apondre un flux novèl via URL" #~ msgid "Import an OPML file" #~ msgstr "Importar un fichièr OPML" #~ msgid "Editor with plain text" #~ msgstr "Editor amb tèxt brut" #~ msgid "1 change" #~ msgstr "1 modificacion" #~ msgid "notes;nextcloud;base;" #~ msgstr "nòtas;nexcloud;basa;" #~ msgid "" #~ "Iotas is a simple note taking app with mobile-first design and a focus on sync with Nextcloud Notes." #~ msgstr "" #~ "Iotas es una aplicacion de presa de nòtas simpla concebut pel mobil d’en primièr e una sincronizacion " #~ "amb Nextcloud Notes." #~ msgid "Although simple by design there are a few features" #~ msgstr "Malgrat que siá simpla de concepcion i a d’unas foncionalitats" #~ msgid "Basic search" #~ msgstr "Recèrca basica" #~ msgid "Please quit the running instance of Iotas before creating the backup" #~ msgstr "Mercés de quitar l’instància en execucion de Iotas abans de crear una salvagarda" #~ msgid "Please quit the running instance of Iotas before restoring the backup" #~ msgstr "Mercés de quitar l’instància en execucion de Iotas abans de restaurar una salvagarda" #~ msgid "No running instance found" #~ msgstr "Cap d’instància en execucion pas trobada" #~ msgid "Hiding extended preferences" #~ msgstr "Amagament de las preferéncias espandidas" #~ msgid "Showing extended preferences" #~ msgstr "Afichatge de las preferéncias espandidas" #~ msgid "Failed to create backup directory at {0}: {1}" #~ msgstr "Fracàs de la creacion de la salvagarda dins lo repertòri {0} : {1}" #~ msgid "Failed to move previous backup to archive path" #~ msgstr "Fracàs de desplaçament de la salvagarda precedenta dins l’emplaçament d’archius" #~ msgid "Backup created at {}" #~ msgstr "Salvagarda creada lo {}" #~ msgid "Backup restoration isn't possible with Nextcloud Notes sync configured" #~ msgstr "La restauracion de salvagarda es pas possibla amb una sincronizacion Nextcloud Notes configurada" #~ msgid "Backup failed" #~ msgstr "La salvagarda a fracassat" #~ msgid "No backup exists at {}" #~ msgstr "Cap de salvagarda dins {}" #~ msgid "Backup restoration can only be run when there are no existing notes" #~ msgstr "La restauracion de salvagarda se pòt sonque lançar quand i a pas cap de nòta existenta" #~ msgid "Backup restoration failed" #~ msgstr "Fracàs de la restauracion de la salvagarda" #~ msgid "Backup restoration completed" #~ msgstr "Restauracion de la salvagarda acabada" #~ msgid "Failed to write metadata to {0}: {1}" #~ msgstr "Fracàs de l’escritura de la metadonada dins {0} : {1}" #~ msgid "Creating {}" #~ msgstr "Creacion {}" #~ msgid "Skipping restoration of existing identical note \"{}\"" #~ msgstr "Nòta identica « {} » ignorada per la restauracion" #~ msgid "Duplicating note \"{}\" due to matching remote id" #~ msgstr "Duplicacion de la nòta « {} » a causa de la correspondéncia d’id distant" #~ msgid "Updating metadata for note \"{}\"" #~ msgstr "Actualizacion de las metadonadas per la nòta « {} »" #~ msgid "Failed to remove backup archive directory at {0}: {1}" #~ msgstr "Fracàs de la supression de l’archiu de salvagarda dins lo repertòri {0} : {1}" #~ msgid "Failed to create backup archive directory at {0}: {1}" #~ msgstr "Fracàs de la creacion de l’archiu de salvagarda dins lo repertòri {0} : {1}" #~ msgid "Failed to move {0} into {1}: {2}" #~ msgstr "Fracàs del desplaçament de {0} dins {1} : {2}" #~ msgid "Skipping \"{}\" due to missing content" #~ msgstr "« {} » ignorada a causa d’abséncia de contengut" #~ msgid "Failed to read note content from {0}: {1}" #~ msgstr "Fracàs de la lectura del contengut de la nòta a partir de {0} : {1}" #~ msgid "Failed to read note metadata from {0}: {1}" #~ msgstr "Fracàs de la lectura de las metadonadas de la nòta a partir de {0} : {1}" #~ msgid "Failed to parse note metadata from \"{}\"" #~ msgstr "Fracàs de l‘analisi de las metadonadas de la nòta a partir de « {} »" #~ msgid "Theme used by editor view" #~ msgstr "Tèma utilizat per la vista editor" #~ msgid "The GtkSourceView style scheme id" #~ msgstr "L’id esquèma d'estil GtkSourceView" #~ msgid "First start" #~ msgstr "Primièr lançament" #~ msgid "Whether starting for the first time." #~ msgstr "Indica se cal l’aviar a la primièra aviada." #~ msgid "Font size" #~ msgstr "Talha polissa" #~ msgid "Font used in main editor view." #~ msgstr "Polissa utiliza dins la vista principala de l'editor." #~ msgid "Line length used in both the editor and markdown render views (pixels)." #~ msgstr "Longor de linha utilizada per l’editor e lo rendut markdown (pixèls)." #~ msgid "Whether to use a monospace font" #~ msgstr "Indica se una polissa de chassa fixa es utilizada" #~ msgid "The specific fonts are sourced from GNOME's monospace and document font settings" #~ msgstr "" #~ "Las polissas especificas venon de polissas de chassa fixa de GNOME e dels paramètres de polissa de " #~ "document" #~ msgid "Markdown render view support" #~ msgstr "Presa en carga de la vista de rendut markdown" #~ msgid "Markdown syntax highlighting" #~ msgstr "Coloracion sintaxica del markdown" #~ msgid "Whether to highlight markdown syntax." #~ msgstr "Indica se cal utilizar la coloracion sintaxica per markdown." #~ msgid "Markdown monospace font." #~ msgstr "Polissa de chassa fixa per markdown." #~ msgid "Whether to show the render view when opening the note." #~ msgstr "Indica se cal afichar la vista rendut en dobrissent la nòta." #~ msgid "A value of 1 will result in no adjustment." #~ msgstr "Una valor d’1 menarà a pas cap d’ajustament." #~ msgid "Nextcloud server to sync against" #~ msgstr "Servidor Nextcloud de sincronizar" #~ msgid "Path to the last Nextcloud sync instance." #~ msgstr "Camin cap a la darrièra instància de sincronizacion Nextcloud." #~ msgid "Username for the Nextcloud sync server" #~ msgstr "Nom d’utilizaire pel servidor de sincro. Nextcloud" #~ msgid "Login to use with the Nextcloud sync instance." #~ msgstr "Identificant d’utilizar amb l’instància de sincronizacion Nextcloud." #~ msgid "Used to reduce the number of records pulled from the Nextcloud server during sync." #~ msgstr "" #~ "Utilizat per reduire lo nombre d’enregistraments recuperats a partir del servidor Nextcloud pendent la " #~ "sincronizacion." #~ msgid "Whether to show a notification when syncing from the server" #~ msgstr "Indica se cal mostrar una notificacion quand se sincroniza del servidor" #~ msgid "Useful for increasing visibility of network issues" #~ msgstr "Util per aumentar la visibilitat dels problèmas ret" #~ msgid "Spelling enabled" #~ msgstr "Verificacion ortografica activada" #~ msgid "Whether spell checking is enabled." #~ msgstr "Indica se la verificacion ortografica es activada." #~ msgid "Spelling language" #~ msgstr "Lenga de verificacion ortografica" #~ msgid "Language tag to attempt to use by default for spelling." #~ msgstr "Balisa de lenga per ensajar d’utilizar per defaut per l’ortografia." #~ msgid "Colour scheme style" #~ msgstr "Estil d'esquèma de color" #~ msgid "Choosing to follow desktop colour style or enforce dark or light visuals." #~ msgstr "Triada per seguir l’estil de color del burèu o renfortir los visuals escurs o clars." #~ msgid "Sync interval" #~ msgstr "Interval de sincro" #~ msgid "Interval between pulling from the Nextcloud sync server (seconds)." #~ msgstr "Interval entre las recuperacion a partir del servidor de sincronizacion Nextcloud (en segondas)." #~ msgid "Window size" #~ msgstr "Talha de la fenèstra" #~ msgid "Remember the window size." #~ msgstr "Memorizar la talha de la fenèstra." #~ msgid "Whether to automatically hide the editor headerbar" #~ msgstr "Indica se cal amagar automaticament la barra d'entèstas de l’editor" #~ msgid "Whether to hide the editor headerbar when fullscreen" #~ msgstr "Indica se cal amagar la barra d’entèsta de l’editor en mòde plen ecran" #~ msgid "File extension for backed up notes" #~ msgstr "Extension de fichièr per las nòtas salvagardadas" #~ msgid "File extension added to each note when exporting for backup." #~ msgstr "Extension de fichièr aponduda a cada nòta quand pendent un expòrt per una còpia de seguretat." #~ msgid "Index category style" #~ msgstr "Estil categoria indèx" #~ msgid "Last launched version" #~ msgstr "Darrièra version lançada" #~ msgid "The last version of the app that was run. Shouldn't be edited." #~ msgstr "La darrièra version d’apliacion lançada. Se deu pas modificar." #~ msgid "Directory last used for export" #~ msgstr "Darrièra repertòri utilizat per l’expòrt" #~ msgid "Extra pandoc formats for exporting" #~ msgstr "Formats pandoc suplementaris per expòrt" #~ msgid "See README for definition" #~ msgstr "Veire lo README per la definicion" #~ msgid "Perform full server refresh" #~ msgstr "Realizar una actualizacion complèta del servidor" #~ msgid "Whether to show extended preferences" #~ msgstr "Indica se cal mostrar las preferéncias espandidas" #~ msgid "When enabled an excessive number of preferences are shown." #~ msgstr "Quand es activat un nombre excessiu de preferéncias es mostrat." #~ msgid "Searching" #~ msgstr "Recèrca" #~ msgid "Sync. with Nextcloud Notes" #~ msgstr "Sincro. amb Nextcloud Notas" #~ msgid "Index on mobile" #~ msgstr "Indèx sus mobil" #~ msgid "Index on desktop" #~ msgstr "Indèx sus burèu" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/pt_BR.po000066400000000000000000001751531507102636600224020ustar00rootroot00000000000000# Brazilian Portuguese translations for iotas package. # Copyright (C) 2023 THE iotas'S COPYRIGHT HOLDER # This file is distributed under the same license as the iotas package. # Filipe Motta , 2023-2025. # Álvaro Burns <>, 2025. # Juliano de Souza Camargo , 2025. # msgid "" msgstr "" "Project-Id-Version: iotas\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-19 11:55+0000\n" "PO-Revision-Date: 2025-09-19 09:33-0300\n" "Last-Translator: Juliano de Souza Camargo \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Gtranslator 49.0\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Aplicativo simples de notas com Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "notas;nextcloud;minimalista;mínima;distração;editor;focado;foco;texto;escrever;markdown;documento;gnome;gtk;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Nova nota" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Anotações simples" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "O Iotas busca oferecer anotações livres de distrações por meio do seu design " "focado em dispositivos móveis." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Funcionalidades" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Sincronização opcional veloz com Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Edição offline de notas, sincronizando ao conectar-se novamente" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Edição e filtragem de categorias" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Favoritos" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Verificação ortográfica" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Busca dentro da coleção ou em notas individuais" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Modo de foco e opção de ocultar a barra superior do Editor e as barras de " "formatação" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "Na pré-visualização: exportar para PDF, ODT e HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Um design convergente, com o Iotas funcionando tão bem no desktop quanto nos " "dispositivos móveis" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Busca na pesquisa do GNOME" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Backup e restauração de notas (pela linha de comando, para o uso sem " "sincronização)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "" "Possibilidade de mudar o tamanho da fonte e ativar/desativar o estilo " "monoespaçado" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Há suporte para escrever em Markdown, mas é opcional, oferecendo" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formatação via barra de ferramentas e atalhos de teclado" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Realce de sintaxe com temas" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Visualização formatada" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "" "Possibilidade de marcar listas de tarefas a partir da visualização formatada" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Detalhes levemente mais técnicos, para quem curte esse tipo de coisa" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "A sincronização do Nextcloud Notes é pela API REST, e não WebDAV, o que faz " "com que ela seja rápida" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Há detecção básica de conflito de sincronização" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "As notas são constantemente salvas" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Coleções grandes de notas são parcialmente carregadas para acelerar a " "inicialização" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "As notas são armazenadas em SQLite, oferecendo busca rápida (FTS) sem " "precisar reinventar a roda. Arquivos individuais podem ser obtidos fazendo " "um backup (via CLI)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Índice" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editor com Markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Markdown renderizado" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Índice em modo escuro" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Em dispositivo móvel" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "" "Filipe Motta \n" "Juliano de Souza Camargo " #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Reverter alterações" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Aplicar alterações" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Aplicar" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Limpar e aplicar" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Encontrar" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Voltar" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_dialog.ui:289 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Resultado anterior" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_dialog.ui:282 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Próximo resultado" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Substituir" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Modo de foco" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Encontre e substitua…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Vá até…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Editar título…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Alterar categoria…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Excluir" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Exportar…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Voltar para Notas" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "A nota é somente leitura" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Menu do Editor" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Ativar/Desativar renderização de Markdown" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Editar nota" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "O motor (engine) de renderização está carregando" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 #: iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "Cancelar" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Exportar como…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "Baixando…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Exportando…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Fechar" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Mostrar" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "Um os mais anexos falharam ao transferir." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Repetir" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "Exportar assim mesmo" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Boas-vindas ao Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Use a barra de cabeçalho para…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Adicionar uma nota" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Sincronizar com Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Reduzir" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Ampliar" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Linha horizontal" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Citação" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Código" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Tabela" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Nível 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Nível 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Nível 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Nível 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Remover" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Título" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Negrito" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Itálico" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Tachado" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Lista não ordenada" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Lista ordenada" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Caixa de seleção" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Link" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Recarregar" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Preferências" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Atalhos de teclado" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Sobre o Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Menu principal" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Hoje" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Ontem" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Esta semana" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Este mês" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Mês passado" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Mostrar meses anteriores" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Antes do mês passado" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Mostrar mais" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Abrir categorias" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 #: data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Buscar" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Selecionar notas" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "A conexão com o servidor está offline" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Por causa de mudanças nos bastidores (uma nova id de aplicativo), o Iotas " "precisa reautenticar junto ao seu servidor Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Autenticar" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "O token de autenticação para sincronização com Nextcloud Notes não pôde ser " "obtido" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Descartar" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Lista de notas vazia" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Digite sua busca" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Nenhum resultado para sua busca" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Criar nova nota" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Exibir barra lateral" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Excluir nota" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Mover acima na lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Mover abaixo na lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Iniciar seleção" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "Abrir primeiro resultado da busca" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "Redefinir filtro" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Editar título" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Alterar categoria" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Exportar" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Pular para a seção" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Criar nova nota incluindo a seleção" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Desfazer digitação" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Refazer digitação" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Inserir emoji" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Focar visualização de texto" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Focar barra superior" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Focar barra de formatação" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Formatação" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Marcar/Desmarcar caixa de seleção" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Busca no Editor" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Aparência do Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Aumentar comprimento da linha" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Diminuir comprimento da linha" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Aumentar tamanho da fonte" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Diminuir tamanho da fonte" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "Geral" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Ativar/Desativar tela cheia" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Mostrar Preferências" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Mostrar atalhos de teclado" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Abrir nota anterior" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Voltar" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Encerrar" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Texto" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Configuração do Nextcloud Notes" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Aperte Continuar para fornecer o endereço e as credenciais do seu servidor " "Nextcloud por meio de um navegador web" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Continuar" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Continuar para a entrada de URL" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "O Secret Service está inacessível" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "O Secret Service não pôde ser acessado para armazenar os detalhes de " "autenticação. Assegure-se de que você tem um provedor, como o gnome-keyring. " "Um chaveiro padrão deve ser configurado e então desbloqueado. A maioria dos " "ambientes de desktop irão lhe oferecer isso. Reinicie o aplicativo para " "tentar novamente." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "URL do servidor" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Iniciar acesso" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Certificado autoassinado" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Você parece estar usando um certificado SSL autoassinado que faz com que a " "identidade do servidor não possa ser verificada. Se isso for esperado, por " "favor siga as instruções no FAQ para fornecer um arquivo de cadeia de CA." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Abrir FAQ" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Conexão estabelecida" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Concluído" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Completar configuração de sincronização" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Esboço" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Nenhum título corresponde ao filtro" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Nenhum título encontrado para o esboço" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Interface" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Usar fonte monoespaçada" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Verificar ortografia" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Mudar idioma por meio do menu de contexto do Editor" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Barra superior" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Limitar comprimento da linha" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Principalmente para o desktop. Use Ctrl + ↑ e Ctrl + ↓ no teclado para fazer " "o ajuste fino." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Detectar sintaxe" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "Necessário para destaque de sintaxe e formatação (barra de ferramentas e " "atalhos de teclado). Desabilite para melhorar ligeiramente a performance." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Tema" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Barra de formatação" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Habilitar visualização formatada" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Desabilite para reduzir o tempo de inicialização " #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Abrir na visualização formatada" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Habilitar essa opção abre todas as notas como Markdown renderizado" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Oferecer suporte a equações matemáticas" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Reduz ligeiramente a performance de renderização" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Renderizar usando fonte monoespaçada" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Proporção em relação ao tamanho da fonte monoespaçada" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "Na visualização de renderização. Use 1 para nenhum ajuste." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Manter motor (engine) na memória" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Conversões subsequentes mais rápidas em troca de maior uso de memória" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Fixar barra lateral" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "No desktop, quando houver espaço" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Estilo de etiqueta de categoria" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Dados" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Conectar Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Sincronização com Nextcloud Notes" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Iniciar sessão" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Desconectar Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Sai da sua conta no Nextcloud Notes. Todas as notas serão removidas e o " "aplicativo se encerrará." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Desconectar" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Redefinir base de dados" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "" "Excluir todas as notas da base de dados local. O aplicativo se encerrará." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Redefinir" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Depuração" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Limpar registro de data e hora da sincronização" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Força uma extração de todas as notas do servidor de sincronização" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Limpar" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Deletar selecionada(s)" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Marcar/desmarcar selecionada(s) como favorita(s)" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Mudar categoria da(s) selecionada(s)" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Fechar categorias" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Categorias" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Inserir tabela" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Criar" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Seguir estilo do sistema" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Modo claro" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Modo escuro" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Criar uma nota" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Criar um backup" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Restaurar um backup" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Exibir caminho do backup" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "" "Exibir caminho para arquivo de cadeia de CA de SSL de servidor personalizado" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "" "Ativar/Desativar exibição de preferências estendidas na Interface de Usuário" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Encerrar qualquer instância em execução" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Habilitar registro e funções de depuração" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Abrir nota por id" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Buscar nas notas" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "CONFLITO DE ID REMOTA NA RESTAURAÇÃO" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "CONFLITO DE TÍTULO NA RESTAURAÇÃO" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Todas as notas" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Não categorizadas" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "O comprimento de linha agora é de {0}px" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Limite de comprimento de linha desabilitado" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Abrindo link no navegador" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} de {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "Exportado para {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "Falha ao exportar para {}" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Transferência falhou" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} notas excluídas" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Nota excluída" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Desfazer" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Conflito de sincronização com a nota que está sendo editada" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "A nota sendo editada foi remotamente excluída" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Falha ao accessar o Secret Service. Assegure-se de que você tem um provedor " "como o gnome-keyring, que possua um chaveiro padrão que esteja desbloqueado." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Sincronizando" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} alteração" msgstr[1] "{} alterações" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "" "Falha na sincronização. O aplicativo Nextcloud Notes está instalado no " "servidor?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Carregando" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Inserir link" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Editar link" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Atualizando notas" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "Realizando transferência inicial" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "Conectando" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "Aguardando acesso" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Complete a verificação no seu navegador" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "Falha ao iniciar acesso com possível problema no certificado" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Falha ao iniciar acesso. Endereço errado?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Monocromático" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Markup esmaecido" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Markup em negrito" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Desabilitada" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Esmaecido" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Azul" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Laranja" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Vermelho" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "Nenhum" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Sempre visível" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Ocultar automaticamente" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Ocultar automaticamente quando em tela cheia" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Reduzindo em {0} toques" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "Extendendo em {0} toques" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Estendidas ocultas" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Estendidas exibidas" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "A ocultação é desencorajada em dispositivos móveis" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Redefinir base de dados?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "Todas as notas serão excluídas. Prosseguir com a redefinição?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Desconectar Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "Todas as notas serão removidas. Você deseja se desconectar?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Não é possível mudar a categoria em uma nota somente leitura" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} Selecionada(s)" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "CONFLITO DE SINCRONIZAÇÃO" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Erro" #~ msgid "Export As..." #~ msgstr "Exportar como..." #~ msgid "Exporting..." #~ msgstr "Exportando..." #~ msgid "OK" #~ msgstr "OK" #~ msgid "Bold Markup (High Contrast)" #~ msgstr "Markup em negrito (alto contraste)" #~ msgid "Muted Markup (High Contrast)" #~ msgstr "Markup esmaecido (alto contraste)" #~ msgid "Monochrome (High Contrast)" #~ msgstr "Monocromático (alto contraste)" #~ msgid "Disabled (High Contrast)" #~ msgstr "Desabilitado (alto contraste)" #~ msgid "Disable" #~ msgstr "Desabilitar" #~ msgid "Return to Index" #~ msgstr "Retornar ao Índice" #~ msgid "Line length limit already disabled" #~ msgstr "Limite de comprimento de linha já desabilitado" #, python-brace-format #~ msgid "Font size now {0}pt" #~ msgstr "O tamanho de fonte agora é {0}pt" #~ msgid "Read-Only Note" #~ msgstr "Nota somente leitura" #~ msgid "Waiting for completion of login in browser" #~ msgstr "Aguardando conclusão do acesso pelo navegador" #~ msgid "Syntax Theme" #~ msgstr "Tema de sintaxe" #~ msgid "Finish" #~ msgstr "Finalizar" #~ msgid "Auto Hide" #~ msgstr "Ocultar automaticamente" #~ msgid "" #~ "Why \"Iotas\"? An iota is a little bit and this app is designed for " #~ "jotting down little things on little devices. Iota stems from the same " #~ "Greek word as jot and is commonly used in negative statements eg. \"not " #~ "one iota of …\", but we think the word has more to give. Maybe somebody " #~ "will take note?" #~ msgstr "" #~ "Por que \"Iotas\"? Um iota é um pouquinho, e este aplicativo é feito para " #~ "anotar pequenas coisinhas em pequenos aparelhos. Iota vem da mesma " #~ "palavra grega que o verbo inglês \"jot\" (em português, \"anotar\") e é " #~ "comumente usado em afirmações negativas, como \"nem um iota de …\", mas " #~ "nós achamos que essa palavra tem mais a oferecer. Quem sabe alguém toma " #~ "nota disso?" #~ msgid "Let's get started" #~ msgstr "Vamos começar" #~ msgid "Add new feeds via URL" #~ msgstr "Adicionar feeds novos via URL" #~ msgid "Import an OPML file" #~ msgstr "Importar um arquivo OPML" #~ msgid "Go back" #~ msgstr "Voltar" #~ msgid "Highlight Syntax" #~ msgstr "Realçar Sintaxe" #~ msgid "Disable for slightly improved performance." #~ msgstr "Desabilite para uma performance ligeiramente melhor." #~ msgid "Editor with plain text" #~ msgstr "Editor com texto puro" #~ msgid "1 change" #~ msgstr "1 alteração" #~ msgid "notes;nextcloud;base;" #~ msgstr "notas;nextcloud;base;" #~ msgid "" #~ "Iotas is a simple note taking app with mobile-first design and a focus on " #~ "sync with Nextcloud Notes." #~ msgstr "" #~ "Iotas é um aplicativo simples de anotações com design que prioriza " #~ "dispositivos móveis e um foco na sincronização com Nextcloud Notes." #~ msgid "Although simple by design there are a few features" #~ msgstr "Apesar de intencionalmente simples, há sim algumas funções" #~ msgid "Basic search" #~ msgstr "Busca básica" #~ msgid "Please quit the running instance of Iotas before creating the backup" #~ msgstr "" #~ "Favor encerrar a instância do Iotas já em execução antes de criar o backup" #~ msgid "" #~ "Please quit the running instance of Iotas before restoring the backup" #~ msgstr "" #~ "Favor encerrar a instância do Iotas já em execução antes de restaurar o " #~ "backup" #~ msgid "No running instance found" #~ msgstr "Nenhuma instância em execução encontrada" #~ msgid "Hiding extended preferences" #~ msgstr "Ocultando preferências estendidas" #~ msgid "Showing extended preferences" #~ msgstr "Exibindo preferências estendidas" #, python-brace-format #~ msgid "Failed to create backup directory at {0}: {1}" #~ msgstr "Falha ao criar diretório de backup em {0}: {1}" #~ msgid "Failed to move previous backup to archive path" #~ msgstr "Falha ao mover backup anterior para o caminho de arquivo" #~ msgid "Backup created at {}" #~ msgstr "Backup criado em {}" #~ msgid "" #~ "Backup restoration isn't possible with Nextcloud Notes sync configured" #~ msgstr "" #~ "A restauração de backup não é possível com a sincronização de Nextcloud " #~ "Notes configurada" #~ msgid "Backup failed" #~ msgstr "O backup falhou" #~ msgid "No backup exists at {}" #~ msgstr "Não há nenhum backup em {}" #~ msgid "Backup restoration can only be run when there are no existing notes" #~ msgstr "" #~ "A restauração de backup só pode ser executada quando não há nenhuma nota " #~ "existente" #~ msgid "Backup restoration failed" #~ msgstr "A restauração de backup falhou" #~ msgid "Backup restoration completed" #~ msgstr "Restauração de backup concluída" #, python-brace-format #~ msgid "Failed to write metadata to {0}: {1}" #~ msgstr "Falha ao escrever metadados em {0}: {1}" #~ msgid "Creating {}" #~ msgstr "Criando {}" #~ msgid "Skipping restoration of existing identical note \"{}\"" #~ msgstr "Pulando restauração de nota idêntica já existente \"{}\"" #~ msgid "Duplicating note \"{}\" due to matching remote id" #~ msgstr "Duplicando nota \"{}\" devido a id remota correspondente" #~ msgid "Updating metadata for note \"{}\"" #~ msgstr "Atualizando metadados para a nota \"{}\"" #~ msgid "" #~ "Skipping note \"{}\" with matching title, contents and a newer timestamp" #~ msgstr "" #~ "Pulando nota \"{}\" com título e conteúdo correspondentes e registro mais " #~ "recente de data e hora" #~ msgid "Duplicating note \"{}\" due to matching title but different content" #~ msgstr "" #~ "Duplicando nota \"{}\" devido a título correspondente com conteúdo " #~ "diferente" #, python-brace-format #~ msgid "Failed to remove backup archive directory at {0}: {1}" #~ msgstr "Falha ao remover diretório de arquivo de backup em {0}: {1}" #, python-brace-format #~ msgid "Failed to create backup archive directory at {0}: {1}" #~ msgstr "Falha ao criar diretório de arquivo de backup em {0}: {1}" #, python-brace-format #~ msgid "Failed to move {0} into {1}: {2}" #~ msgstr "Falha ao mover {0} para {1}: {2}" #~ msgid "Skipping \"{}\" due to missing content" #~ msgstr "Pulando \"{}\" devido a conteúdo faltante" #, python-brace-format #~ msgid "Bailing \"{0}\" due to exceeding {1}MB" #~ msgstr "Cancelando \"{0}\" por exceder {1}MB" #, python-brace-format #~ msgid "Failed to read note content from {0}: {1}" #~ msgstr "Falha ao ler conteúdo de nota de {0}: {1}" #, python-brace-format #~ msgid "Failed to read note metadata from {0}: {1}" #~ msgstr "Falha ao ler metadados de nota de {0}: {1}" #~ msgid "Failed to parse note metadata from \"{}\"" #~ msgstr "Falha ao analisar metadados de nota de \"{}\"" #~ msgid "Theme used by editor view" #~ msgstr "Tema usado na visualização do editor" #~ msgid "The GtkSourceView style scheme id" #~ msgstr "A id do esquema de estilo do GtkSourceView" #~ msgid "First start" #~ msgstr "Primeiro início" #~ msgid "Whether starting for the first time." #~ msgstr "Se está iniciando pela primeira vez." #~ msgid "Font size" #~ msgstr "Tamanho da fonte" #~ msgid "Font used in main editor view." #~ msgstr "Fonte usada na visualização principal do editor." #~ msgid "" #~ "Line length used in both the editor and markdown render views (pixels)." #~ msgstr "" #~ "Comprimento de linha (em pixels) usado em ambas as visualizações de " #~ "editor e de renderização de markdown." #~ msgid "Whether to use a monospace font" #~ msgstr "Se deve usar uma fonte monoespaçada" #~ msgid "" #~ "The specific fonts are sourced from GNOME's monospace and document font " #~ "settings" #~ msgstr "" #~ "As fontes específicas são obtidas das configurações do GNOME sobre fontes " #~ "monoespaçadas e de documento" #~ msgid "Markdown render view support" #~ msgstr "Suporte a visualização de renderização de markdown" #~ msgid "" #~ "Whether to support showing markdown render view (a temporary performance " #~ "concession for a WebKit issue)" #~ msgstr "" #~ "Se deve oferecer suporte à visualização de renderização de markdown (uma " #~ "concessão temporária de performance por um problema do WebKit)" #~ msgid "Markdown syntax highlighting" #~ msgstr "Realce de sintaxe markdown" #~ msgid "Whether to highlight markdown syntax." #~ msgstr "Se deve realçar a sintaxe de markdown." #~ msgid "Markdown WebKit process retention." #~ msgstr "Retenção do processo WebKit de markdown." #~ msgid "" #~ "When enabled the WebKit process is retained between uses of the render " #~ "view, decreasing load time and increasing memory usage." #~ msgstr "" #~ "Quando ativado, o processo WebKit é retido entre os usos da visualização " #~ "de renderização, diminuindo o tempo de carregamento e aumentando o uso de " #~ "memória." #~ msgid "Markdown TeX support for maths equations." #~ msgstr "Suporte a Markdown TeX para equações matemáticas." #~ msgid "" #~ "Whether to support rendering maths equations. Slightly increases markdown " #~ "render time." #~ msgstr "" #~ "Se deve oferecer suporte à renderização de equações matemáticas. Aumenta " #~ "ligeiramente o tempo de renderização de markdown." #~ msgid "Markdown monospace font." #~ msgstr "Fonte monoespaçada para Markdown." #~ msgid "Whether to use a monospace font for the markdown render." #~ msgstr "" #~ "Se deve usar uma fonte monoespaçada para a renderização de markdown." #~ msgid "Markdown default to render." #~ msgstr "Renderização de markdown por padrão." #~ msgid "Whether to show the render view when opening the note." #~ msgstr "Se deve exibir a visualização de renderização ao abrir a nota." #~ msgid "Ratio adjusting proportional to monospace font in markdown render" #~ msgstr "" #~ "Ajuste de proporção em relação à fonte monoespaçada na renderização de " #~ "markdown" #~ msgid "A value of 1 will result in no adjustment." #~ msgstr "Um valor de 1 resultará em nenhum ajuste." #~ msgid "Nextcloud server to sync against" #~ msgstr "Servidor Nextcloud para sincronização" #~ msgid "Path to the last Nextcloud sync instance." #~ msgstr "Caminho para a última instância de sincronização Nextcloud." #~ msgid "Username for the Nextcloud sync server" #~ msgstr "Nume de usuário para o servidor de sincronização Nextcloud" #~ msgid "Login to use with the Nextcloud sync instance." #~ msgstr "Credenciais para usar com a instância de sincronização Nextcloud." #~ msgid "Prune threshold for Nextcloud sync" #~ msgstr "Limite de redução para a sincronização Nextcloud" #~ msgid "" #~ "Used to reduce the number of records pulled from the Nextcloud server " #~ "during sync." #~ msgstr "" #~ "Usado para reduzir o número de registros extraídos do servidor Nextcloud " #~ "durante a sincronização." #~ msgid "Whether to show a message on Secret Service failure" #~ msgstr "Se deve mostrar uma mensagem em caso de falha do Secret Service" #~ msgid "" #~ "Disabling this provides for a cleaner startup if never intending to use " #~ "Nextcloud Notes sync. on a device without a Secret Service provider." #~ msgstr "" #~ "Desativar este item oferece uma inicialização mais limpa caso você nunca " #~ "pretenda usar a sincronização de Nextcloud Notes em um dispositivo sem um " #~ "provedor de Secret Service." #~ msgid "Whether to show a notification when syncing from the server" #~ msgstr "Se deve mostrar uma notificação ao sincronizar com o servidor" #~ msgid "Useful for increasing visibility of network issues" #~ msgstr "Útil para aumentar a visibilidade de problemas de conexão" #~ msgid "Spelling enabled" #~ msgstr "Verificação ortográfica habilitada" #~ msgid "Whether spell checking is enabled." #~ msgstr "Se a verificação ortográfica está ativada." #~ msgid "Spelling language" #~ msgstr "Idioma da verificação ortográfica" #~ msgid "Language tag to attempt to use by default for spelling." #~ msgstr "" #~ "Etiqueta de idioma que tentará ser usada por padrão para a verificação " #~ "ortográfica." #~ msgid "Colour scheme style" #~ msgstr "Estilo de esquema de cores" #~ msgid "" #~ "Choosing to follow desktop colour style or enforce dark or light visuals." #~ msgstr "" #~ "Escolher seguir o estilo de cores do sistema ou aplicar modo escuro ou " #~ "claro." #~ msgid "Sync interval" #~ msgstr "Intervalo de sincronização" #~ msgid "Interval between pulling from the Nextcloud sync server (seconds)." #~ msgstr "" #~ "Intervalo (em segundos) entre extrações do servidor de sincronização " #~ "Nextcloud." #~ msgid "Window size" #~ msgstr "Tamanho da janela" #~ msgid "Remember the window size." #~ msgstr "Lembrar o tamanho da janela." #~ msgid "Whether to persist the index sidebar in large windows" #~ msgstr "Se a barra lateral de índice deve ser mantida em janelas grandes" #~ msgid "" #~ "Whether to the index sidebar is permanently present in large windows " #~ "(generally desktop)" #~ msgstr "" #~ "Se a barra lateral de índice fica permanentemente presente em janelas " #~ "grandes (geralmente desktop)" #~ msgid "Whether to automatically hide the editor headerbar" #~ msgstr "Se deve ocultar a barra superior do editor automaticamente" #~ msgid "Setting to true automatically hides the editor headerbar" #~ msgstr "Ativar essa opção oculta automaticamente a barra superior do editor" #~ msgid "Whether to hide the editor headerbar when fullscreen" #~ msgstr "Se deve ocultar a barra superior do editor ao entrar em tela cheia" #~ msgid "" #~ "Setting to true automatically hides the editor headerbar entering " #~ "fullscreen mode" #~ msgstr "" #~ "Ativar essa opção automaticamente oculta a barra superior do editor ao " #~ "entrar em modo tela cheia" #~ msgid "File extension for backed up notes" #~ msgstr "Extensão de arquivo para backup de notas" #~ msgid "File extension added to each note when exporting for backup." #~ msgstr "" #~ "Extensão de arquivo adicionada a cada nota ao exportá-la para backup." #~ msgid "Index category style" #~ msgstr "Estilo de categoria de índice" #~ msgid "Style options for category labels on index rows" #~ msgstr "Opções de estilos para etiquetas de categoria nas linhas de índice" #~ msgid "Last launched version" #~ msgstr "Última versão lançada" #~ msgid "The last version of the app that was run. Shouldn't be edited." #~ msgstr "" #~ "A última versão do aplicativo que foi executada. Não deve ser editada." #~ msgid "Directory last used for export" #~ msgstr "Último diretório usado para exportação" #~ msgid "" #~ "Only applies to instances with filesystem access. Shouldn't be edited." #~ msgstr "" #~ "Só se aplica a instâncias com acesso ao sistema de arquivos. Não deve ser " #~ "editado." #~ msgid "Extra pandoc formats for exporting" #~ msgstr "Formatos adicionais do pandoc para exportação" #~ msgid "See README for definition" #~ msgstr "Confira o README (em inglês) para ver a definição" #~ msgid "Perform full server refresh" #~ msgstr "Realizar recarregamento completo do servidor" #~ msgid "" #~ "Whether to run a full update of all notes from the server. Used for eg. " #~ "schema migrations." #~ msgstr "" #~ "Se deve executar uma atualização completa de todas as notas do servidor. " #~ "Usado, por exemplo, para migrações de esquemas." #~ msgid "Whether to show extended preferences" #~ msgstr "Se deve exibir as preferências estendidas" #~ msgid "When enabled an excessive number of preferences are shown." #~ msgstr "" #~ "Quando ativado, uma quantidade excessiva de preferências são mostradas." #~ msgid "Searching" #~ msgstr "Buscando" #~ msgid "Sync. with Nextcloud Notes" #~ msgstr "Sincronização com Nextcloud Notes" #~ msgid "Index on mobile" #~ msgstr "Índice em dispositivos móveis" #~ msgid "Index on desktop" #~ msgstr "Índice no desktop" #~ msgid "Formatted View Mode" #~ msgstr "Formatted View Mode" #~ msgid "Open In View Mode" #~ msgstr "Open In View Mode" #~ msgid "Keep Sidebar Open" #~ msgstr "Keep Sidebar Open" #~ msgid "View By Default" #~ msgstr "View By Default" #~ msgid "Limited functionality on mobile for now." #~ msgstr "Limited functionality on mobile for now." #~ msgid "" #~ "Task list items checked off in the rendered view are updated in the note " #~ "(and to the server)" #~ msgstr "" #~ "Task list items checked off in the rendered view are updated in the note " #~ "(and to the server)" #~ msgid "" #~ "Note: It's fairly early days in development here, so please expect a few " #~ "rough edges." #~ msgstr "" #~ "Note: It's fairly early days in development here, so please expect a few " #~ "rough edges." #~ msgid "Optional markdown syntax highlighting and rendered view" #~ msgstr "Optional markdown syntax highlighting and rendered view" #~ msgid "Follow system-wide dark style preference or make own choice" #~ msgstr "Follow system-wide dark style preference or make own choice" #~ msgid "Mobile editor" #~ msgstr "Mobile editor" #~ msgid "Desktop index" #~ msgstr "Desktop index" #~ msgid "Desktop index dark style" #~ msgstr "Desktop index dark style" #~ msgid "Sync. offline" #~ msgstr "Sync. offline" #~ msgid "Add Favorite" #~ msgstr "Add Favourite" #~ msgid "Remove Favorite" #~ msgstr "Remove Favourite" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/ro.po000066400000000000000000001334401507102636600220050ustar00rootroot00000000000000# Romanian translation for Iotas. # Copyright (C) 2025 Iotas's COPYRIGHT HOLDER # This file is distributed under the same license as the Iotas package. # Antonio Marin , 2025. # msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-10-02 02:43+0000\n" "PO-Revision-Date: 2025-10-02 18:56+0200\n" "Last-Translator: Antonio Marin \n" "Language-Team: Romanian \n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2);\n" "X-Generator: Gtranslator 48.0\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "O aplicație simplă de luat notițe cu Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;notițe;notiță;scris;listă;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Notiță nouă" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Aplicație simplă pentru notițe" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas își propune să ofere o modalitate de a lua notițe fără distrageri, " "fiind concepută pentru mobil." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Caracteristici" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Sincronizare rapidă facultativă cu Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "" "Modificarea notițelor fără conectare la internet, sincronizarea la " "reconectare" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Modificarea și filtrarea categoriilor" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Preferate" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Verificarea ortografiei" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Caută în toate notițele sau în fiecare notiță" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Mod Concentrare și ascundere facultativă a părții de sus a aplicației și a " "instrumentelor de formatare" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "În modul previzualizare: exportă în PDF, ODT și HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Un concept convergent, care face ca Iotas să arate la fel de bine pe " "calculator și pe mobil" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Căutare din interfața GNOME" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Copiere și recuperare notițe (din terminal, pentru utilizare fără " "sincronizare)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "" "Posibilitatea de a schimba mărimea literelor și de a folosi tipul monospațiat" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Scrierea în markdown este posibilă, dar facultativă, oferind" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formatare folosind instrumentele de formatare și scurtăturile" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Evidențierea sintaxei cu diferite aspecte" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "O vizualizare formatată" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Posibilitatea de a bifa elementele listei din vizualizarea formatată" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "" "Câteva detalii tehnice suplimentare, pentru cei interesați de acest gen de " "lucruri" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "Sincronizarea Nextcloud Notes se face prin API-ul REST, nu prin WebDAV, ceea " "ce o face rapidă" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Există o recunoaștere a conflictelor de sincronizare" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Notițele sunt salvate în mod constant" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Colecțiile mari de notițe sunt încărcate parțial pentru a accelera pornirea" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Notițele sunt stocate în SQLite, oferind o căutare rapidă (FTS) fără a " "reinventa roata. Fișierele de text simplu pot fi recuperate făcând o copie " "de rezervă (CLI)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Index" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Editor cu markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Markdown redat" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Index cu fond negru" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobil" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Antonio Marin , 2025" #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Anulează schimbările" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Aplică schimbările" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Aplică" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Șterge și aplică" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Caută" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Înapoi" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_dialog.ui:289 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Potrivirea precedentă" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_dialog.ui:282 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Potrivirea următoare" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Înlocuiește" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Mod Concentrare" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Caută și Înlocuiește…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Salt la…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Modifică titlul…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Schimbă categoria…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Șterge" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Exportă…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Înapoi la notițe" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Notiță doar de citit" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Opțiuni" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Întrerupător Markdown" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Modifică notița" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Se încarcă motorul de afișare" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 #: iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "Anulează" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Exportă ca…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "Descărcare…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Exportare…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Închide" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Arată" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "Unul sau mai multe fișiere atașate nu au putut fi transferate." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Încearcă" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "Exportă oricum" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Bun venit în Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Folosește partea de sus a aplicației pentru…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Adăugarea unei notițe" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Sincronizare cu Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Micșorare" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Mărire" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Linie orizontală" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Citat" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Cod" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Tabel" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Nivelul 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Nivelul 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Nivelul 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Nivelul 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Elimină" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Titlu" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Gros" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Înclinat" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Tăiat" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Listă punctată" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Listă numerotată" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Loc de bifat" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Legătură" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Actualizează" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Preferințe" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Scurtături" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Despre Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Opțiuni principale" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Azi" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Ieri" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Săptămâna asta" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Luna asta" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Luna trecută" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Arată lunile precedente" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Înainte de luna trecută" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Mai multe" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Arată categoriile" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 #: data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Caută" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Alege notițe" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Neconectat la server" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Datorită unor schimbări tehnice (un nou ID de aplicație), Iotas trebuie " "reautentificată pentru serverul Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Autentifică" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "Codul de autentificare pentru sincronizarea cu Nextcloud Notes nu a putut fi " "obținut" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Ignoră" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Listă goală" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Scrie cuvântul de căutat" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Niciun rezultat" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Notiță nouă" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Arată Panoul lateral" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Șterge notița" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Mută în sus în listă" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Mută în jos în listă" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Începe Selecția" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "Deschide primul rezultat al căutării" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "Restabilește filtrul" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Modifică titlul" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Schimbă categoria" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Exportă" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Salt la zonă" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Notiță nouă care conține selecția" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Anulează ultima scriere" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Refă ultima scriere" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Introduce Emoji" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Activează scrierea" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Activează partea de sus" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Activează partea de jos" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Formatare" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Bifat/Nebifat" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Căutare în Editor" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Aspect Editor" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Micșorează alineatul" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Mărește alineatul" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Mărește caracterele" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Micșorează caracterele" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "Generale" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Pe tot ecranul Activat/Dezactivat" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Arată preferințele" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Arată scurtăturile" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Deschide notița precedentă" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Înapoi" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Închide" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Text" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Configurare Nextcloud Notes" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Apasă Continuă pentru a furniza adresa serverului Nextcloud și pentru a te " "autentifica folosind un navigator web" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Continuă" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Continuă către introducerea URL-ului" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Inelul de chei e inaccesibil" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "Inelul de chei nu a putut fi accesat pentru stocarea detaliilor de " "autentificare. Este necesar un furnizor precum gnome-keyring. Trebuie " "configurat un inel de chei prestabilit, iar acel inel de chei trebuie " "deblocat. Majoritatea interfețelor grafice furnizează un inel de chei. " "Repornește aplicația pentru a încerca din nou." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "URL-ul serverului" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Începe autentificarea" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Certificat autosemnat" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Se pare că se utilizează un certificat SSL autosemnat, ceea ce face ca " "identitatea serverului să nu poată fi verificată. Dacă acest lucru este " "așteptat, se recomandă urmarea instrucțiunilor din FAQ pentru a furniza un " "fișier de certificare." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Deschide FAQ" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Conectare efectuată" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Gata" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Completează configurarea sincronizării" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Cuprins" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Niciun titlu care să corespundă filtrului" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Nu s-a găsit niciun titlu pentru cuprins" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Interfață" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Tip monospațiat de caractere" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Verifică ortografia" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Schimbă limba din opțiunile contextuale" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Partea de sus" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Limita alineatului" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Pentru computer. Folosește Ctrl + ↑ și Ctrl + ↓ de la tastatură pentru " "reglare fină." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Detectare sintaxă" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "Necesară pentru evidențierea sintaxei și formatare (instrumente și " "scurtături). Dezactivează pentru o performanță ușor îmbunătățită." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Aspect" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Instrumente de formatare" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Activează vizualizarea formatată" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Dezactivează pentru a reduce timpul de pornire" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Deschide în vizualizarea formatată" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Activarea deschide toate notițele ca markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Ecuații matematice" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Reduce ușor performanța de afișare" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Afișare cu caractere monospațiate" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Proporție între tipul de caractere monospațiat și cel standard" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "În modul afișare. Folosește 1 pentru nicio ajustare." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Păstrează motorul în memorie" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "" "Conversii ulterioare mai rapide, dar cu o utilizare mai mare a memoriei" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Fixează panolul lateral" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "La computer, când există spațiu" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Stilul etichetei categoriei" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Date" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Conectare Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Stabilește sincronizarea cu Nextcloud Notes" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Autentificare" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Deconectare Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Se deconectează de la Nextcloud Notes. Toate notițele vor fi șterse și " "aplicația se va închide." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Deconectează" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Restabilește baza de date" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "" "Șterge toate notițele din baza de date locală. Aplicația se va închide." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Restabilește" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Depanare" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Șterge data și ora sincronizării" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Descarcă forțat toate notițele de pe serverul de sincronizare" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Șterge" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Șterge cele bifate" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Preferată/Nepreferată la cele bifate" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Schimbă categoria celor bifate" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Închide categoriile" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Categorii" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Introdu un tabel" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Creează" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Aspectul sistemului" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Aspect luminos" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Aspect întunecos" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Creează o notiță" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Creează o copie de rezervă" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Recuperează o copie de rezervă" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Afișează calea copiei de rezervă" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "Afișează calea fișierului personalizat SSL CA al serverului" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "Arată/Ascunde preferințele extinse în interfața aplicației" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Închide orice instanță în execuție" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Activează diagnoza de depanare și funcțiile de depanare" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Deschide notița după ID" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Caută în notițe" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "CONFLICT ID LA RECUPERAREA COPIEI DE REZERVĂ" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "CONFLICT DE TITLU LA RECUPERAREA COPIEI DE REZERVĂ" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Toate notițele" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Neclasificate" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "Lungimea rândului acum: {0}px" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Limita lungimii rândului e dezactivată" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Deschide legătura în navigatorul web" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} din {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "Exportată în {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "Nu s-a reușit exportarea în {}" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Transfer nereușit" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} notițe șterse" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Notiță ștearsă" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Anulează" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Conflict de sincronizare cu notița în curs de modificare" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "Notița modificată a fost ștearsă de la distanță" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Eroare la accesarea inelului de chei. Este necesar un furnizor ca gnome-" "keyring care are un inel de chei deblocat în mod prestabilit." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Se sincronizează" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} schimbare" msgstr[1] "{} schimbări" msgstr[2] "{} de schimbări" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "" "Sincronizare nereușită. Aplicația Nextcloud Notes este instalată în server?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Se încarcă" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Introdu legătura" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Modifică legătura" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Actualizare notițe" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "Se efectuează transferul inițial" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "Se conectează" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "Se așteaptă autentificarea" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Completează autentificarea în propriul navigator web" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "" "Autentificarea a eșuat din cauza unei posibile probleme cu certificatul" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Autentificarea nu a putut fi începută. Adresa este greșită?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Monocromatic " #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Markup atenuat" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Markup îngroșat" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Dezactivat" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Atenuat" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Albastru" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Portocaliu" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Roșu" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "Nimic" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Vizibilă mereu" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Ascunsă automat" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Ascunsă automat în modul pe tot ecranul" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Reducere în {0} apăsări" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "Extindere în {0} apăsări" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Extinsă ascunsă" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Extinsă afișată" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "Ascunderea pe mobil nu e recomandată" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Se restabilește baza de date?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "Toate notițele vor fi șterse. Se continuă cu restabilirea?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Se deconectează Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "Toate notițele vor fi șterse. Te deconectezi?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Nu poate fi schimbată categoria unei notițe doar de citit" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} alese" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "CONFLICT DE SINCRONIZARE" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Eroare" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/ru.po000066400000000000000000001577211507102636600220230ustar00rootroot00000000000000# Russian translations for iotas package. # Copyright (C) 2022 iotas # This file is distributed under the same license as the iotas package. # Yaroslav Pronin , 2022. # David Sultaniiazov , 2025. # # SPDX-FileCopyrightText: 2025 Sergey Kazorin msgid "" msgstr "" "Project-Id-Version: iotas\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-19 05:31+0000\n" "PO-Revision-Date: 2025-09-19 17:02+0300\n" "Last-Translator: Artur So \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.7\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Простое ведение заметок с Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;заметки;текст;редактор;документ;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Новая заметка" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Простое ведение заметок" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "Iotas aims to provide distraction-free note taking via its mobile-first design." msgstr "Iotas стремится обеспечить создание заметок без отвлекающих факторов благодаря своему мобильному дизайну." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Функции" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Возможность быстрой синхронизации с Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Редактирование заметок в автономном режиме, синхронизация при подключении к сети" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Редактирование и фильтрация категорий" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Избранное" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Проверка орфографии" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Поиск по коллекции или отдельным заметкам" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "Режим фокусировки и возможность скрыть заголовка редактора и панелей форматирования" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "На этапе тестирования: экспорт в PDF, ODT и HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "Конвергентный дизайн, позволяющий использовать Iotas как дома, на настольных компьютерах, так и на мобильных устройствах" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Поиск из оболочки GNOME" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "Резервное копирование и восстановление заметок (из командной строки, для использования без синхронизации)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Возможность изменять размер шрифта и переключать моноширинное начертание" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Запись в Markdown поддерживается, но необязательна" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Форматирование с помощью панели инструментов и сочетания клавиш" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Подсветка синтаксиса с темами" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Отформатированный вид" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Возможность отмечать списки задач в отформатированном виде" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Ещё немного технических подробностей для тех, кто разбирается в подобных вещах" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "Синхронизация Nextcloud Notes осуществляется через REST API, а не WebDAV, что делает её более быстрой" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Существует базовая функция обнаружения конфликтов синхронизации" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Заметки постоянно сохраняются" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "Большие коллекции заметок загружаются по частям для ускорения запуска" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without reinventing the wheel. Plain files can be retrieved by " "making a backup (CLI)." msgstr "" "Заметки хранятся в SQLite, что обеспечивает быстрый поиск без необходимости изобретать велосипед. Обычные файлы можно " "восстановить, создав резервную копию (CLI)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Главная" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Редактор с использование Markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Отрисовка Markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Главная в тёмной теме" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Мобильный" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "" "Yaroslav Pronin \n" "David Sultaniiazov " #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Отменить изменения" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Применить изменения" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 iotas/link_dialog.py:52 msgid "Apply" msgstr "Применить" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Очистить и применить" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Найти" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 data/ui/render_search_header_bar.ui:15 #: data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Назад" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 data/ui/keyboard_shortcuts_dialog.ui:289 data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Предыдущее совпадение" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 data/ui/keyboard_shortcuts_dialog.ui:282 data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Следующее совпадение" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 data/ui/editor_search_header_bar.ui:82 data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Заменить" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Режим фокусировки" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Найти и заменить…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Перейти к…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Редактировать заголовок…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Изменить категорию…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Удалить" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Экспортировать…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Вернуться к заметкам" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Заметка только для чтения" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Меню редактора" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Переключить отрисовку Markdown" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Редактировать заметку" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Загрузка движка рендеринга" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "Отменить" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Экспортировать как…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "Загрузка…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Экспортирование…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Закрыть" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Показать" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "Одно или несколько вложений не удалось передать." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Повторить" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "Экспортировать все равно" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Добро пожаловать в Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Исполоьзовать строку заголовка выше, чтобы…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Добавить заметку" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Синхронизация с Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Уменьшить" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Увеличить" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Горизонтальный разделитель" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Цитата" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Код" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Таблица" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Уровень 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Уровень 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Уровень 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Уровень 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Удалить" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Заголовок" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Жирный" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Курсивный" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Зачёркнутый" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Ненумерованный список" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Нумерованный список" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Флажок" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Ссылка" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Обновить" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Параметры" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Комбинации клавиш" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "О приложении" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Главное меню" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Сегодня" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Вчера" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Эта неделя" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Этот месяц" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Прошлый месяц" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Показать предыдущие месяцы" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "До прошлого месяца" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Показать больше" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Открыть категории" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Поиск" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Выбрать заметки" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Подключение к серверу в автономном режиме" #. Translators: Description #: data/ui/index.ui:93 msgid "Due to behind-the-scenes changes (a new app id) Iotas needs to reauthenticate with your Nextcloud server" msgstr "" "В связи с внесёнными изменениями (новый идентификатор приложения) Iotas необходимо повторно пройти аутентификацию на вашем " "сервере Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Подтвердить" #. Translators: Description #: data/ui/index.ui:102 msgid "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "Не удалось получить токен аутентификации для синхронизации с Nextcloud Notes" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Отклонить" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Список заметок пуст" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Введите поисковый запрос" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Ничего не найдено" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Создать новую заметку" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Показать боковую панель" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Удалить заметку" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Переместить список выше" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Переместить список ниже" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Начать выбор" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "Открыть первый результат поиска" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "Сбросить фильтр" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Редактор" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Редактировать заголовок" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Изменить категорию" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Экспортировать" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Перейти к разделу" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Создать новую заметку из выделенного" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Отменить ввод" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Повторить ввод" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Ввести эмодзи" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Фокус на текстовый просмотр" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Фокус на строку заголовка" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Фокус на строку форматирования" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Форматирование" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Переключить флажок" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Поиск в редакторе" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Внешний вид редактора" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Увеличить длину строки" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Уменьшить длину строки" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Увеличить размер шрифта" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Уменьшить размер шрифта" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "Общие" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Переключить полноэкранный режим" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Показать параметры" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Показать комбинации клавиш" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Открыть предыдущую заметку" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Назад" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Выйти" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Текст" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Настройка Nextcloud Notes" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "Press Continue to provide your Nextcloud server address and login via a web browser" msgstr "Нажмите кнопку «Продолжить», чтобы указать адрес своего сервера Nextcloud и войти с помощью веб-браузера" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Продолжить" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Перейти к вводу URL" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Служба хранения данных аутентификации недоступна" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. Ensure you have a provider such as gnome-keyring. A " "default keyring needs to be setup, and that keyring unlocked. Most desktop environments will provide this for you. Restart the " "app to try again." msgstr "" "Не удалось получить доступ к службе хранения данных аутентификации. Убедитесь, что у вас есть провайдер, такой как gnome-" "keyring. Связка ключей по умолчанию должна быть настроена и разблокирована. Большинство сред рабочего стола обеспечивают это. " "Перезапустите приложение, чтобы повторить попытку." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "URL сервера" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Начать вход" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Самозаверенный сертификат" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server identity not being verified. If this is expected " "please follow the instructions in the FAQ to provide a CA chain file." msgstr "" "Похоже, вы используете самозаверенный SSL-сертификат, в результате чего идентификатор сервера не проверяется. Если это " "необходимо, пожалуйста, следуйте инструкциям в ЧаВо, чтобы предоставить файл цепочки сертификации." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Открыть ЧаВо" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Соединение установлено" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Готово" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Завершить настройку синхронизации" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Выделение" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Нет заголовков, подходящих под фильтр" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Не найдено заголовков для выделения" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Интерфейс" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Использовать моноширинный шрифт" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Проверка правописания" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Изменение языка через контекстное меню редактора" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Строка заголовка" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Ограничить длину строки" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "В основном для настольных компьютеров. Используйте Ctrl + ↑ и Ctrl + ↓ на клавиатуре для точной настройки." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Распознавать синтаксис" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard shortcuts). Disable for slightly improved performance." msgstr "" "Требуется для подсветки синтаксиса и форматирования (панель инструментов и сочетания клавиш). Отключите для незначительного " "повышения производительности." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Тема" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Строка форматирования" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Включить форматированный вид" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Отключите, чтобы сократить время запуска" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Открывать в отформатированном виде" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Включение открывает все заметки с отрисовкой Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Поддержка математический уравнений" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Незначительно снижает производительность отрисовки" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Отрисовывать с моноширинным начертанием" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Пропорция соотношению размеров моноширинного начертания" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "В отрисованном виде. Используйте 1, чтобы не изменять." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Удерживать движок в памяти" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Ускоренное последующее преобразование благодаря большему объёму используемой памяти" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Закрепить боковую панель" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "На компьютере, когда есть свободное место" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Стиль метки категории" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Данные" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Подключение Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Установить синхронизацию с Nextcloud Notes" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Войти" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Отключение Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "Signs out from Nextcloud Notes. All notes will be removed and the app will quit." msgstr "Выйти из Nextcloud Notes. Все заметки будут удалены, а приложение закроется." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Отключиться" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Сбросить базу данных" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "Удалить все заметки из локальной базы данных. Приложение будет закрыто." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Сбросить" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Отладка" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Очистить временную метку синхронизации" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Принудительно извлекает все заметки с сервера синхронизации" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Очистить" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Удалить выбранное" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Переключить «Избранное» для выбранного" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Изменить категорию для выбранного" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Закрыть категории" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Категории" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Вставить таблицу" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Создать" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Использовать системную тему" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Светлая тема" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Тёмная тема" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Создать заметку" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Создать резервную копию" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Восстановить из резервной копии" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Показать путь к резервной копии" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "Отобразить путь к пользовательскому файлу цепочки SSL CA сервера" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "Переключить отображение расширенных настроек в интерфейсе" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Закрыть любой запущенный экземпляр" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Включить логгирование и функции отладки" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Открыть заметку по ID" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Поиск в заметках" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "КОНФЛИКТ ВОССТАНОВЛЕНИЯ УДАЛЁННОГО ID" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "КОНФЛИКТ ВОССТАНОВЛЕНИЯ ЗАГОЛОВКА" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Все заметки" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Без категории" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "Длина строки сейчас {0} пикселей" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Ограничение длины строки отключено" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Открывать ссылки в браузере" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} из {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "Экспортировано из {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "Не удалось экспортировать {}" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Не удалось выполнить передачу" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "Заметок удалено {}" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Заметка удалена" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Отменить" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Конфликт синхронизации редактируемой заметкой" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "Редактируемая заметка была удаленно удалена" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-keyring which has a default keyring setup that is " "unlocked." msgstr "" "Не удалось получить доступ к службе хранения данных аутентификации. Убедитесь, что у вас есть провайдер, такой как gnome-" "keyring. Связка ключей по умолчанию должна быть настроена и разблокирована." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Синхронизация" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} изменение" msgstr[1] "{} изменения" msgstr[2] "{} изменений" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Сбой синхронизации. Установлено ли на сервере приложение Nextcloud Notes?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Загрузка" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Вставить сслыку" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Редактировать ссылку" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Обновление заметок" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "Выполнение начальной передачи" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "Подключение" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "Ожидание входа" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Завершите аутентификацию в браузере" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "Не удалось начать вход в систему из-за возможной проблемы с сертификатом" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Не удалось открыть окно авторизации. Неверный адрес?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Монохром" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Без выделения разметки" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Жирная разметка" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Выключено" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Не выделять" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Синий" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Оранженвый" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Красный" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "Нет" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Всегда виден" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Автоматически скрываться" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Автоматически скрывать в полноэкранном режиме" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Скроется через {0} нажатия" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "Раскроется через {0} нажатия" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Расширенные настройки скрыты" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Расширенные настройки отображены" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "Скрывать разочарование на мобильном телефоне" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Сбросить базу данных?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "Все заметки будут удалены. Продолжите сброс?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Отключить Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "Все заметки будут удалены. Вы хотите выйти?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Невозможно изменить категорию заметки только для чтения" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "Выбрано {}" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "КОНФЛИКТ СИНХРОНИЗАЦИИ" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Ошибка" #~ msgid "Iotas is a simple note taking app with mobile-first design and a focus on sync with a Nextcloud Notes." #~ msgstr "Iotas - это простое приложение для создания заметок с мобильным дизайном и акцентом на синхронизацию с Nextcloud Notes." #~ msgid "Although consciously bare bones there are a few features" #~ msgstr "Хотя это сознательно примитивное приложение, есть несколько особенностей" #~ msgid "Sync. with Nextcloud Notes" #~ msgstr "Синхронизация с Nextcloud Notes" #~ msgid "Basic search" #~ msgstr "Базовый поиск" #~ msgid "Follow system-wide dark style preference or make own choice" #~ msgstr "Системная тема или ручной выбор тёмной или светлой темы" #~ msgid "Чуть больше технических подробностей, для любителей подобных вещей" #~ msgstr "Detalles un poco más técnicos, para los interesados en ese tipo de cosas" #~ msgid "Current obvious feature omissions" #~ msgstr "Не реализованные функции" #~ msgid "" #~ "Why \"Iotas\"? An iota is a little bit and this app is designed for jotting down little things on little devices. Iota stems " #~ "from the same Greek word as jot and is commonly used in negative statements eg. \"not one iota of …\", but we think the word " #~ "has more to give. Maybe somebody will take note?" #~ msgstr "" #~ "Почему \"Iotas\"? Йота (Iota) - это немного, и это приложение предназначено для записи мелочей на маленьких устройствах. Йота " #~ "происходит от того же греческого слова, что и йот, и обычно используется в отрицательных утверждениях, например. \"ни на йоту " #~ "…\", но мы думаем, что это слово может дать больше. Может кто возьмёт на заметку?" #~ msgid "Initial release." #~ msgstr "Первый выпуск" #~ msgid "Mobile editor" #~ msgstr "Мобильный редактор" #~ msgid "Desktop index" #~ msgstr "Десктопный список" #~ msgid "Desktop index dark style" #~ msgstr "Десктопный список, тёмная тема" #~ msgid "Chris Heywood" #~ msgstr "Chris Heywood" #~ msgid "notes;nextcloud;base;" #~ msgstr "notes;nextcloud;base;заметки;" #~ msgid "Learn more about Iotas" #~ msgstr "Узнайте больше о Iotas" #~ msgid "Let's get started" #~ msgstr "Давайте начнём" #~ msgid "Add new feeds via URL" #~ msgstr "Добавить новые каналы с помощью URL" #~ msgid "Import an OPML file" #~ msgstr "Импорт OPML файла" #~ msgid "Add Favorite" #~ msgstr "Добавить в избранное" #~ msgid "Remove Favorite" #~ msgstr "Удалить из избранного" #~ msgid "Sync. offline" #~ msgstr "Синхронизация оффлайн" #~ msgid "Load The Rest" #~ msgstr "Загрузить остальные" #~ msgid "Rest" #~ msgstr "Остальные" #~ msgid "Return to Index" #~ msgstr "Вернуться к списку" #~ msgid "Waiting for completion of login in browser" #~ msgstr "Ожидание завершения входа в браузере" #~ msgid "Sync" #~ msgstr "Синхронизация" #~ msgid "Temporary Debug Functions" #~ msgstr "Временные функции отладки" #~ msgid "Finish" #~ msgstr "Финиш" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/sl.po000066400000000000000000001323131507102636600220010ustar00rootroot00000000000000# Slovenian translation for Iotas. # Copyright (C) 2025 Iotas's COPYRIGHT HOLDER # This file is distributed under the same license as the Iotas package. # Martin , 2025. # msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-19 12:34+0000\n" "PO-Revision-Date: 2025-09-19 23:40+0200\n" "Last-Translator: Martin Srebotnjak \n" "Language-Team: Slovenian \n" "Language: sl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0) ;\n" "X-Generator: Poedit 2.2.1\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Preprosto beleženje z Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "opombe;beležke;zabeležke;opomnik;beležka;zabeležka;opomba;zapisek;zapiski;beležnice;nextcloud;minimalna;distrakcija;urejevalnik;osredotočeno;besedilo;pisati;zapisati;zapisovanje;pisanje;markdown;dokument;gnome;gtk;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Nova opomba" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Enostavno ustvarjanje zapiskov" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "Iotas aims to provide distraction-free note taking via its mobile-first design." msgstr "Iotas si prizadeva zagotoviti beleženje brez motenj s svojim mobilni rabi posvečenim oblikovanjem." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Funkcionalnosti" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Izbirna hitra sinhronizacija z Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Urejanje zapiskov brez povezave, sinhronizacija ob ponovni povezavi" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Urejanje in filtriranje kategorij" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Priljubljeni" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Preverjanje črkovanja" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Iskanje po zbirki ali posameznih beležkah" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "Način pozornosti in izbirno skrivanje glave urejevalnika in vrstic za oblikovanje" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "V predogledu: izvoz v PDF, ODT in HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "Konvergentna zasnova, ki postavlja program Iotas na namizje in na mobilne naprave" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Iskanje iz lupine GNOME" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "Varnostno kopiranje in obnovitev beležk (iz CLI, za uporabo brez sinhronizacije)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Možnost spreminjanja velikosti pisave in preklapljanja sloga enakomernih pisav" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Pisanje v markdownu je podprto, vendar neobvezno" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Oblikovanje prek orodne vrstice in bližnjic" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Označevanje skladnje s temami" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Oblikovan pogled" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Možnost potrditve opravil na seznamih v pogledu oblikovanja" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Nekoliko več tehničnih podrobnosti, za tiste, ki se ukvarjajo s tovrstnimi stvarmi" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "Sinhronizacija Nextcloud Notes poteka prek API-ja REST, ne WebDAV, zaradi česar je hitra" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Na voljo je osnovno zaznavanje sporov pri sinhronizaciji" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Beležke se nenehno shranjujejo" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "Velike zbirke beležk so delno naložene za hitrejši zagon" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "Notes are stored in SQLite, providing for fast search (FTS) without reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "Beležke so shranjene v SQLite, kar omogoča hitro iskanje (FTS) brez ponovnega izumljanja kolesa. Navadne datoteke lahko pridobite z varnostno kopijo (CLI)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Kazalo" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Urejevalnik z markdownom" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Izrisani markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Kazalo v temnem slogu" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobilnik" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Martin Srebotnjak " #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Povrni spremembe" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Uveljavi spremembe" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 iotas/link_dialog.py:52 msgid "Apply" msgstr "Uveljavi" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Počisti in uveljavi" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Najdi" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Nazaj" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 data/ui/keyboard_shortcuts_dialog.ui:289 data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Prejšnji zadetek" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 data/ui/keyboard_shortcuts_dialog.ui:282 data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Naslednji zadetek" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 data/ui/editor_search_header_bar.ui:82 data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Zamenjaj" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Način izostritve" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Najdi in zamenjaj …" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Skoči na …" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Uredi naslov …" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Spremeni kategorijo ..." #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Izbriši" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Izvozi ..." #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Nazaj k beležkam" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Beležka je samo za branje" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Meni urejevalnika" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Preklopi izrisovanje Markdowna" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Uredi beležko" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Nalaganje pogona za izrisovanje" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "Prekliči" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Izvozi kot …" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "Prejemanje …" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Poteka izvažanje …" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Zapri" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Pokaži" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "Prenos ene ali več prilog ni uspel." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Poskusi znova" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "Vseeno izvozi" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Dobrodošli v Iotasu" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Uporabi zgornjo glavno vrstico za ..." #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Dodaj beležko" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Uskladi z Nextcloud Notes" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Oddalji" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Približaj" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Vodoravno ravnilo" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Citat" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Koda" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Tabela" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Raven 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Raven 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Raven 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Raven 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Odstrani" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Naslov" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Krepko" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Ležeče" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Prečrtano" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Označen seznam" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Oštevilčen seznam" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Potrditveno polje" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Povezava" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Osveži" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Nastavitve" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Tipke za bližnjice" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "O programu Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Glavni meni" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Danes" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Včeraj" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Ta teden" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Ta mesec" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Prejšnji Mesec" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Pokaži prejšnje mesece" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Pred prejšnjim mesecem" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Pokaži več" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Odpri kategorije" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Poišči" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Izberi beležke" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Povezava s strežnikom ni vzpostavljena" #. Translators: Description #: data/ui/index.ui:93 msgid "Due to behind-the-scenes changes (a new app id) Iotas needs to reauthenticate with your Nextcloud server" msgstr "Zaradi sprememb v zakulisju (nov ID programa) mora Iotas ponovno preveriti pristnost z vašim strežnikom Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Overi" #. Translators: Description #: data/ui/index.ui:102 msgid "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "Žetona za preverjanje pristnosti za sinhronizacijo z Nextcloud Notes ni bilo mogoče pridobiti" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Opusti" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Seznam beležk je prazen" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Vnesite iskalni izraz" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Ni zadetkov iskanja" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Ustvari novo beležko" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Pokaži stransko vrstico" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Izbriši zapisek" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Premakni navzgor po seznamu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Premakni navzdol po seznamu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Začetek izbora" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "Odpri prvi rezultat iskanja" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "" "Ponastavi\n" "filter" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Urejevalnik" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Uredi naslov" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Spremeni kategorijo" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Izvozi" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Skoči na razdelek" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Ustvari novo beležko, vključno z izborom" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Razveljavi tipkanje" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Ponovni tipkanje" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Vstavi izrazno ikono" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Pogled pozornosti na besedilu" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Pozornost na vrstico z glavo" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Pozornost na vrstico za oblikovanje" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Oblikovanje" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Preklopi potrditveno polje" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Iskanje v urejevalniku" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Videz urejevalnika" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Povečaj dolžino črte" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Zmanjšaj dolžino črte" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Povečaj pisavo" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Zmanjšaj pisavo" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "Splošno" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Vključi/izključi celozaslonski pogled" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Pokaži nastavitve" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Pokaži tipkovne bližnjice‫" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Odpri prejšnjo beležko" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Pojdi nazaj" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Izhod" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Besedilo" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nastavitev Nextcloud Notes" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "Press Continue to provide your Nextcloud server address and login via a web browser" msgstr "Pritisnite Nadaljuj, da vnesete naslov strežnika Nextcloud in se prijavite prek spletnega brskalnika" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Nadaljuj" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Nadaljuj na vnos URL-ja" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Varna storitev je nedostopna" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. Ensure you have a provider such as gnome-keyring. A default keyring needs to be setup, and that keyring unlocked. Most desktop environments " "will provide this for you. Restart the app to try again." msgstr "" "Do varne storitve ni bilo mogoče dostopati za shranjevanje podatkov o preverjanju pristnosti. Prepričajte se, da imate ponudnika, kot je gnome-keyring. Privzeto zbirko ključev je treba nastaviti in to zbirko ključev " "odkleniti. Večina namiznih okolij vam bo to omogočila. Znova zaženite program, da poskusite znova." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "URL strežnika" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Začni prijavo" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Samopodpisano potrdilo" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "You appear to be using a self-signed SSL certificate resulting in the server identity not being verified. If this is expected please follow the instructions in the FAQ to provide a CA chain file." msgstr "Zdi se, da uporabljate samopodpisano potrdilo SSL, zaradi česar identiteta strežnika ni preverjena. Če je to pričakovano, upoštevajte navodila v pogostih vprašanjih, da zagotovite verižno datoteko CA." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Odpri pogosta vprašanja" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Povezava vzpostavljena" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Končano" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Dokončajte nastavitev sinhronizacije" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Oris" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Brez filtra, ki se ujema z naslovi" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Za oris ni bilo najdenih naslovov" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Vmesnik" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Uporabi pisavo stalne širine" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Preveri črkovanje" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Spremeni jezik prek kontekstnega menija urejevalnika" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Naslovna vrstica" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Omeji dolžino vrstice" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "Predvsem za namizje. Za natančno nastavitev uporabite krmilka + ↑ in krmilka + ↓ na tipkovnici." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Zaznaj skladnjo" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "Required for syntax highlighting and formatting (toolbar and keyboard shortcuts). Disable for slightly improved performance." msgstr "Zahtevano za označevanje skladnje in oblikovanje (orodna vrstica in bližnjice na tipkovnici). Onemogočite za nekoliko hitrejše delovanje." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Tema" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Vrstica za oblikovanje" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Omogoči oblikovani pogled" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Onemogočite za skrajšanje zagonskega časa" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Odpri v oblikovanem pogledu" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Če možnost omogočite, odprete vse beležke kot izrisani markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Podpiraj matematične enačbe" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Rahlo zmanjša zmogljivost izrisovanja" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Upodobi s pisavo stalne širine" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Razmerje velikosti sorazmerne pisave glede na enakomerno" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "V pogledu izrisovanja. Uporabite 1 za izklop prilagajanja." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Drži pogon v pomnilniku" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Hitrejše nadaljnje pretvorbe za večjo porabo pomnilnika" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Pripni stransko vrstico" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Na namizju, ko je na voljo prostor" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Slog oznake kategorije" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Podatki" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Povežite Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Vzpostavi sinhronizacijo z Nextcloud Notes" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Prijava" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Prekini povezavo z Nextcloudom" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "Signs out from Nextcloud Notes. All notes will be removed and the app will quit." msgstr "Odjava iz Nextcloud Notes. Vse beležke bodo odstranjene in program se bo zaprl." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Prekini povezavo" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Ponastavi zbirko podatkov" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "Izbrišite vse beležke iz krajevne zbirke podatkov. Program se bo zaprl." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Ponastavi" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Razhrošči" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Počisti časovni žig sinhronizacije" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Prisilno povleče vse beležke s sinhronizacijskega strežnika" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Počisti" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Izbriši izbrane" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Preklopi priljubljeno za izbrano" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Spremeni kategorijo za izbrano" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Zapri kategorije" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Kategorije" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Vstavi tabelo" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Ustvari" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Sledi slogu sistema" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Svetla tema" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Temna tema" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Ustvarite novo beležko" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Ustvari varnostno kopijo" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Obnovi iz varnostne kopije" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Prikaži pot varnostne kopije" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "Prikaži pot za verižno datoteko SSL CA strežnika po meri" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "Preklopi prikaz razširjenih nastavitev v uporabniškem vmesniku" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Zapri vse zagnane primerke" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Omogoči beleženje in funkcije odpravljanja napak" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Odpri beležko po id-ju" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Iščite po beležkah" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "SPOR PRI OBNOVI ZARADI ODDALJENEGA ID-JA" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "SPOR PRI OBNOVI ZARADI NASLOVA" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Vse beležke" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Nekategorizirano" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "Dolžina črte je zdaj {0} sl. točk" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Omejitev dolžine črte je onemogočena" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Odpiranje povezave v brskalniku" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} od {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "Izvoženo v {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "Izvoz v {} ni bil uspešen" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Prenos ni uspel" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} beležk izbrisanih" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Beležka izbrisana" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Razveljavi" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Spor sinhronizacije za beležko v urejanju" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "Beležka, ki se ureja, je bila na daljavo izbrisana" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "Failure accessing Secret Service. Ensure you have a provider like gnome-keyring which has a default keyring setup that is unlocked." msgstr "Neuspeh pri dostopu do tajnostne storitve. Prepričajte se, da imate ponudnika, kot je gnome-keyring, ki ima privzeto nastavitev zbirke ključev, ki je odklenjena." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Sinhronizacija" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} sprememb" msgstr[1] "{} sprememba" msgstr[2] "{} spremembi" msgstr[3] "{} spremembe" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Sinhronizacija ni uspela. Ali je program Nextcloud Notes nameščen na strežniku?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Nalaganje" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Vstavi povezavo" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Uredi povezavo" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Posodabljanje beležk" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "Izvajanje začetnega prenosa" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "Povezovanje" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "Čakanje na prijavo" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Dokončaj preverjanja pristnosti v brskalniku" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "Prijava ni uspela zaradi morebitne težave s potrdilom" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Prijava ni uspela. Ali gre za napačen naslov?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Monokromatsko" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Izklopljeno označevanje" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Krepko označevanje" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Onemogočeno" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Utišano" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Modra" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Oranžna" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Rdeča" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "Brez" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Vedno vidno" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Samodejno skrij" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Samodejno skrij v celozaslonskem načinu" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Zmanjševanje v {0} stiskalnicah" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "Razširjanje v {0} stiskalnicah" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Razširjeno skrito" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Razširjeno prikazano" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "Skrivanje na mobilnih napravah ni zaželeno" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Ali želite ponastaviti zbirko podatkov?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "Vse beležke bodo izbrisane. Ali želite nadaljevati s ponastavitvijo?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Ali želite prekiniti povezavo z Nextcloudom?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "Vse beležke bodo odstranjene. Ali se želite odjaviti?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Kategorije ni mogoče spremeniti v beležki samo za branje" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} izbranih" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "SPOR PRI SINHRONIZACIJI" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Napaka" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/sv.po000066400000000000000000001330311507102636600220110ustar00rootroot00000000000000# Swedish translation for Iotas. # Copyright © 2025 Iotas's COPYRIGHT HOLDER # This file is distributed under the same license as the Iotas package. # Anders Jonsson , 2025. # msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-19 05:31+0000\n" "PO-Revision-Date: 2025-09-19 12:55+0200\n" "Last-Translator: Anders Jonsson \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.7\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Enkelt antecknande med Nextcloud Notes" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "notes;nextcloud;anteckningar;minimal;distraktion;redigerare;fokuserad;text;skriv;markdown;dokument;gnome;gtk;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Ny anteckning" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Enkelt antecknande" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "Iotas aims to provide distraction-free note taking via its mobile-first design." msgstr "Iotas eftersträvar att tillhandahålla distraktionsfritt antecknande genom sin design som prioriterar mobiler." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Funktioner" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Valfri snabb synkronisering med Nextcloud Notes" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Frånkopplad anteckningsredigering som synkroniserar när du är ansluten igen" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Kategoriredigering och filtrering" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Favoriter" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Stavningskontroll" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Sök i samlingen eller i enskilda anteckningar" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "Fokusläge och valfritt döljande av redigerarens rubrik- och formatrader" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "Förhandsversion: exportera till PDF, ODT och HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "En konvergent design, vilket gör Iotas lika hemma på skrivbordet som på mobilen" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Sök från GNOME Shell" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "Säkerhetskopiering och återställande av anteckningar (från kommandoraden, för användning utan synkronisering)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Förmågan att ändra typsnittsstorlek och att växla till och från fast breddsteg" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Att skriva i Markdown stöds men är valfritt, och tillhandahåller" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Formatering via verktygsfält och kortkommandon" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Syntaxmarkering med teman" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "En formaterad vy" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Förmågan att kryssa i uppgiftslistor från den formaterade vyn" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Något mer tekniska detaljer, för den som gillar sådant" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "Nextcloud Notes-synkronisering ges via REST-API:t, inte WebDAV, vilket gör den snabb" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Det finns grundläggande upptäckt av konflikter" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Anteckningar sparas konstant" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "Stora anteckningssamlingar läses in partiellt för snabbare uppstart" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without reinventing the wheel. Plain files can be " "retrieved by making a backup (CLI)." msgstr "" "Anteckningar lagras i SQLite, vilket ger snabb fulltextsökning utan att uppfinna hjulet på nytt. Klartextfiler kan " "erhållas genom att göra en säkerhetskopia (kommandoraden)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 data/ui/keyboard_shortcuts_dialog.ui:7 #: data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Index" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Redigerare med markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Renderad markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Index i mörk stil" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobil" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "" "Anders Jonsson , 2025\n" "\n" "Skicka synpunkter på översättningen till\n" "" #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Återställ ändringar" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Verkställ ändringar" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 iotas/link_dialog.py:52 msgid "Apply" msgstr "Verkställ" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Rensa och verkställ" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Sök" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 data/ui/render_search_header_bar.ui:15 #: data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Bakåt" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 data/ui/keyboard_shortcuts_dialog.ui:289 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Föregående matchning" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 data/ui/keyboard_shortcuts_dialog.ui:282 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Nästa matchning" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Ersätt" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Fokusläge" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Sök och ersätt…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Hoppa till…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Redigera titel…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Ändra kategori…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Ta bort" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Exportera…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Tillbaka till anteckningar" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Anteckningen är skrivskyddad" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Redigerarmeny" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Växla rendering av Markdown" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Redigera anteckning" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Renderingsmotor läses in" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "Avbryt" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Exportera som…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "Hämtar…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Exporterar…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Stäng" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Visa" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "En eller flera bilagor kunde inte överföras." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Försök igen" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "Exportera ändå" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Välkommen till Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Använd rubrikraden ovanför för att…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Lägga till en anteckning" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Synkronisera med Nextcloud-anteckningar" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Zooma ut" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Zooma in" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Horisontell linjal" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Citat" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Kod" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Tabell" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Nivå 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Nivå 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Nivå 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Nivå 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Ta bort" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Rubrik" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Fet" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Kursiv" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Genomstruken" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Oordnad lista" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Ordnad lista" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Kryssruta" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Länk" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Uppdatera" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Inställningar" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Tangentbordsgenvägar" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Om Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Huvudmeny" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "I dag" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "I går" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Denna vecka" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Denna månad" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Förra månaden" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Visa tidigare månader" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Före förra månaden" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Visa mer" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Öppna kategorier" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Sök" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Välj anteckningar" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Serveranslutning frånkopplad" #. Translators: Description #: data/ui/index.ui:93 msgid "Due to behind-the-scenes changes (a new app id) Iotas needs to reauthenticate with your Nextcloud server" msgstr "" "På grund av ändringar bakom ridåerna (ett nytt program-ID) så behöver Iotas återautentisera med din Nextcloud-server" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Autentisera" #. Translators: Description #: data/ui/index.ui:102 msgid "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "Autentiseringstoken för synkronisering med Nextcloud Notes kunde inte hämtas" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Avfärda" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Anteckningslistan tom" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Ange sökterm" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Inga sökresultat" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Skapa ny anteckning" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Visa sidopanel" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Ta bort anteckning" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Gå uppåt i lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Gå nedåt i lista" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Starta markering" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "Öppna första sökresultat" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "Nollställ filter" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Redigerare" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Redigera titel" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Ändra kategori" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Exportera" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Hoppa till avsnitt" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Skapa ny anteckning som inkluderar markeringen" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Ångra skrivande" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Gör om skrivande" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Infoga emoji" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Fokusera textvy" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Fokusera rubrikrad" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Fokusera formatrad" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Formatering" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Växla kryssruta" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Redigerarsökning" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Redigerarutseende" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Öka radlängd" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Minska radlängd" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Öka typsnittsstorlek" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Minska typsnittsstorlek" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "Allmänt" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Växla helskärmsläge" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Visa inställningar" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Visa kortkommandon" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Öppna föregående anteckning" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Gå tillbaka" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Avsluta" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Text" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud Notes-konfiguration" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "Press Continue to provide your Nextcloud server address and login via a web browser" msgstr "Tryck Fortsätt för att ange din Nextcloud-serveradress och inloggning via en webbläsare" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Fortsätt" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Fortsätt till URL-fält" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Secret Service ej åtkomlig" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. Ensure you have a provider such as " "gnome-keyring. A default keyring needs to be setup, and that keyring unlocked. Most desktop environments will " "provide this for you. Restart the app to try again." msgstr "" "Secret Service kunde inte kommas åt för lagring av autentiseringsdetaljer. Säkerställ att du har en leverantör " "såsom gnome-keyring. En standardnyckelring behöver konfigureras, och den nyckelringen behöver låsas upp. De flesta " "skrivbordsmiljöer tillhandahåller detta åt dig. Starta om programmet för att försöka igen." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Server-URL" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Starta inloggning" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Självsignerat certifikat" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server identity not being verified. If this " "is expected please follow the instructions in the FAQ to provide a CA chain file." msgstr "" "Du verkar använda ett självsignerat SSL-certifikat vilket resulterar i att serverns identitet inte verifieras. Om " "detta är förväntat, följ gärna instruktionerna i ”Frågor och svar” för att tillhandahålla en CA-kedjefil." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Öppna ”Frågor och svar”" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Anslutning etablerad" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Klar" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Slutför synkroniseringskonfiguration" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Översikt" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Inga rubriker matchade filter" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Inga rubriker hittades för översikten" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Gränssnitt" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Använd typsnitt med fast breddsteg" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Kontrollera stavning" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Ändra språk genom redigerarens snabbvalsmeny" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Rubrikrad" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Begränsa radlängd" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "Främst för skrivbordet. Använd Ctrl + ↑ och Ctrl + ↓ på tangentbordet för att finjustera." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Upptäck syntax" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard shortcuts). Disable for slightly improved " "performance." msgstr "" "Krävs för syntaxmarkering och formatering (verktygsfält och tangentbordsgenvägar). Inaktivera för något förbättrad " "prestanda." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Tema" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Formatrad" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Aktivera formaterad vy" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Inaktivera för att reducera uppstartstid" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Öppna i formaterad vy" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Aktivering öppnar alla anteckningar som renderad markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Stöd matematiska ekvationer" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Minskar renderingsprestanda något" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Rendera med typsnitt med fast breddsteg" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Proportionell med storleksförhållande för typsnitt med fast breddsteg" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "I renderingsvy. Använd 1 för ingen justering." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Håll motorn i minnet" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Snabbare efterföljande konverteringar men högre minnesanvändning" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Nåla sidopanel" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "På skrivbordet då det finns plats" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Stil på kategorietikett" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Data" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Anslut till Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Etablera synkronisering med Nextcloud-anteckningar" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Logga in" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Koppla från Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "Signs out from Nextcloud Notes. All notes will be removed and the app will quit." msgstr "Loggar ut från Nextcloud Notes. Alla anteckningar kommer tas bort och programmet kommer avslutas." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Koppla från" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Nollställ databas" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "Ta bort alla anteckningar från den lokala databasen. Programmet kommer avsluta." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Nollställ" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Felsök" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Rensa tidsstämpel för synkronisering" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Tvingar hämtning av alla anteckningar från synkroniseringsservern" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Rensa" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Ta bort markerade" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Växla favorit för markerad" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Ändra kategori för markerad" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Stäng kategorier" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Kategorier" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Infoga tabell" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Skapa" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Följ systemets stil" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Ljus stil" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Mörk stil" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Skapa en anteckning" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Skapa en säkerhetskopia" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Återställ en säkerhetskopia" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Visa sökväg till säkerhetskopia" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "Visa sökväg för anpassad SSL CA-kedjefil för server" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "Växla visning av utökade inställningar i användningsgränssnittet" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Avsluta alla körande instanser" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Aktivera felsökningsloggning och funktioner" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Öppna anteckning efter ID" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Sök i anteckningar" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "FJÄRR-ID-KONFLIKT VID ÅTERSTÄLLNING" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "TITELKONFLIKT VID ÅTERSTÄLLNING" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Alla anteckningar" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Okategoriserade" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "Radlängd är nu {0} bildpunkter" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Radlängdsgräns inaktiverad" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Öppnar länk i webbläsare" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} av {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "Exporterade till {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "Misslyckades med att exportera till {}" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Överföring misslyckades" # TODO: ngettext #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} anteckningar togs bort" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Anteckning borttagen" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Ångra" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Synkroniseringskonflikt med anteckning som redigeras" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "Anteckningen som redigeras togs bort från en annan plats" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-keyring which has a default keyring setup " "that is unlocked." msgstr "" "Fel vid åtkomst till Secret Service. Säkerställ att du har en leverantör som gnome-keyring som har en standard-" "nyckelringskonfiguration som är upplåst." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Synkroniserar" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} ändring" msgstr[1] "{} ändringar" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Synkroniseringsfel. Är programmet Nextcloud Notes installerat på servern?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Läser in" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Infoga länk" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Redigera länk" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Uppdaterar anteckningar" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "Utför initial överföring" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "Ansluter" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "Väntar på inloggning" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Slutför autentiseringen i din webbläsare" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "Misslyckades med att starta inloggning med möjligt certifikatproblem" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Misslyckades med att starta inloggning. Fel adress?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Svartvit" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Dämpad markup" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Fetstilsmarkup" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Inaktiverad" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Dämpad" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Blå" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Orange" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Röd" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "Ingen" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Alltid synlig" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Dölj automatiskt" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Dölj automatiskt i helskärmsläge" # TODO: ngettext? #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Reducerar om {0} tryck" # TODO: ngettext? #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "Utökar om {0} tryck" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Utökning dold" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Utökning visad" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "Döljande avråds från på mobil" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Nollställ databas?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "Alla anteckningar kommer tas bort. Fortsätt med nollställningen?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Koppla från Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "Alla anteckningar kommer tas bort. Vill du logga ut?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Kunde inte ändra kategori för skrivskyddad anteckning" # TODO: ngettext?? #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} markerade" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "SYNKRONISERINGSKONFLIKT" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Fel" #~ msgid "Exporting..." #~ msgstr "Exporterar…" #~ msgid "OK" #~ msgstr "OK" #~ msgid "Bold Markup (High Contrast)" #~ msgstr "Fetstilsmarkup (hög kontast)" #~ msgid "Muted Markup (High Contrast)" #~ msgstr "Tystad markup (hög kontast)" #~ msgid "Monochrome (High Contrast)" #~ msgstr "Svartvit (hög kontast)" #~ msgid "Disabled (High Contrast)" #~ msgstr "Inaktiverad (hög kontast)" #~ msgid "Disable" #~ msgstr "Inaktivera" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/tr.po000066400000000000000000001330271507102636600220130ustar00rootroot00000000000000# Turkish translations for iotas package # Copyright (C) 2022-2025 the iotas copyright holder # This file is distributed under the same license as the iotas package. # # Sabri Ünal , 2022-2025. # Emin Tufan Çetin , 2025. # msgid "" msgstr "" "Project-Id-Version: iotas master\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-19 05:31+0000\n" "PO-Revision-Date: 2025-09-20 08:00+0300\n" "Last-Translator: Emin Tufan Çetin \n" "Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.7\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Nextcloud Notes ile basit not alma" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;notlar;dikkat;dikkat " "dağıtmayan;düzenleyici;editör;odaklanmış;odak;metin;yazma;belge;doküman;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Yeni Not" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Basit not alma" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas, mobil öncelikli tasarımıyla dikkat dağıtmayan not alma olanağı sunar." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Öne çıkanlar" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Nextcloud Notes ile isteğe bağlı hızlı eşzamanlama" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "Çevrim dışı not düzenleme, çevrim içi olunca eşzamanlama" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Kategori düzenleme ve süzme" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Gözdeler" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Yazım denetimi" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Derleme içinde ya da tek tek notlarda arama" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Odak kipi ve düzenleyici başlığı ve biçimlendirme çubuklarının isteğe bağlı " "olarak gizlenmesi" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "Ön izlemede: PDF, ODT ve HTML olarak dışa aktarma" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Masaüstünde olduğu kadar mobil aygıtlarda da güzel görünen yakınsak tasarım" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "GNOME Shell’den Ara" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Not yedekleme ve geri yükleme (komut satırından, eşzamanlama olmadan " "kullanmak için)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "" "Yazı tipi boyutunu değiştirme ve eş aralıklı biçemi değiştirme yeteneği" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "Markdown ile yazmak desteklenmektedir ancak isteğe bağlıdır" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "Araç çubuğu ve kısayollar aracılığıyla biçimlendirme" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Temalarla söz dizimi vurgulama" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Biçimlendirilmiş görünüm" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Biçimlendirilmiş görünümden görev listelerini imleme yeteneği" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Meraklıları için daha teknik ayrıntılar" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "Nextcloud Notlar eşzamanlaması WebDAV değil, REST API aracılığıyladır, bu da " "onu çok daha hızlı yapar" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Temel eşzamanlama çakışması algılandı" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Notlar düzenli kaydedilir" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "Büyük not derlemeleri, başlatmayı hızlandırmak için parçalı yüklenir" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Notlar SQLite olarak saklanır ve hızlı arama sağlar. Düz dosyalar yedekleme " "(CLI) yapılarak geri alınabilir." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Ana Sayfa" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Markdown ile düzenleyici" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "İşlenmiş markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Ana sayfa, koyu biçemde" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Mobil" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "" "Sabri Ünal \n" "Emin Tufan Çetin " #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Değişiklikleri Geri Al" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Değişiklikleri Uygula" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Uygula" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Temizle ve Uygula" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Bul" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Geri" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_dialog.ui:289 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Önceki Eşleşme" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_dialog.ui:282 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Sonraki Eşleşme" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Değiştir" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Odak Kipi" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Bul ve Değiştir…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Git…" # Başlık düzeni tercih ediyoruz. Menü öğesi. #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Başlığı Düzenle…" # Başlık Düzeni tercih edildi. #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Kategori Değiştir…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Sil" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Dışa Aktar…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Notlara Dön" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Not Salt Okunur" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Düzenleyici Menüsü" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Markdown İşlemeyi Aç/Kapat" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Notu Düzenle" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "İşleme Motoru Yükleniyor" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 #: iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "İptal" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Dışa Farklı Aktar…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "İndiriliyor…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Dışa Aktarılıyor…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Kapat" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Göster" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "Bir ya da daha çok ek aktarılamadı." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Yeniden Dene" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "Yine De Dışa Aktar" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Iotasʼa Hoş Geldiniz" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Yukarıdaki başlık çubuğunu kullanın…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Not Ekle" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Nextcloud Notes ile Eşzamanla" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Uzaklaştır" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Yakınlaştır" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Yatay Çizgi" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Alıntı" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Kod" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Tablo" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Düzey 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Düzey 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Düzey 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Düzey 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Kaldır" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Başlık" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Kalın" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Eğik" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Üstü Çizili" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Sırasız Liste" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Sıralı Liste" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Onay Kutusu" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Bağlantı" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Yenile" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Tercihler" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Klavye Kısayolları" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Iotas Hakkında" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Ana Menü" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Bugün" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Dün" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Bu Hafta" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Bu Ay" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Geçen Ay" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Önceki Ayları Göster" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "Geçen Aydan Önce" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Daha Çok Göster" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Kategorileri Aç" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 #: data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Ara" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Notları Seç" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Sunucu bağlantısı çevrim dışı" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Perde arkasındaki değişiklikler (yeni uygulama kimliği) nedeniyle Iotas’ın " "Nextcloud sunucunuzla yeniden kimlik doğrulaması gerekiyor" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Kimlik Doğrula" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "Nextcloud Notes ile eşzamanlama için kimlik doğrulama jetonu alınamadı" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Gözden Çıkar" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Not Listesi Boş" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Arama Terimi Gir" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Arama Sonucu Yok" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Yeni Not Oluştur" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Kenar Çubuğunu Göster" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Notu Sil" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Listeyi Yukarı Taşı" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Listeyi Aşağı Taşı" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Seçimi Başlat" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "İlk Arama Sonucunu Aç" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "Süzgeci Sıfırla" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Düzenleyici" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Başlığı Düzenle" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Kategori Değiştir" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Dışa Aktar" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Bölüme Atla" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Seçimi İçeren Yeni Not Oluştur" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Yazımı Geri Al" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Yazımı Yinele" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Emoji Ekle" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Metin Görünümüne Odaklan" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Başlık Çubuğuna Odaklan" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Biçimlendirme Çubuğuna Odaklan" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Biçimlendirme" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Onay Kutusunu Değiştir" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Düzenleyici Arama" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Düzenleyici Görünümü" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Satır Uzunluğunu Artır" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Satır Uzunluğunu Azalt" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Yazı Tipi Boyutunu Büyüt" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Yazı Tipi Boyutunu Küçült" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "Genel" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Tam Ekranı Aç/Kapat" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Tercihleri Göster" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Kısayolları Göster" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Önceki Notu Aç" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Geri Git" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Çık" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Metin" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud Notes Kurulumu" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Nextcloud sunucu adresinizi sağlamak ve web tarayıcısı aracılığıyla oturum " "açmak için Sürdür düğmesine basın" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Sürdür" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "URL Girişine Sürdür" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "Giz Hizmetine Erişilemiyor" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "Kimlik doğrulama ayrıntılarını depolamak için Giz Servisi’ne erişilemedi. " "Gnome-keyring gibi bir sağlayıcınız olduğundan emin olun. Öntanımlı " "anahtarlığın ayarlanması ve bu anahtarlığın kilidinin açılması gerekir. Çoğu " "masaüstü ortamı bunu sizin için sağlar. Yeniden denemek için uygulamayı " "yeniden başlatın." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Sunucu URL’si" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Girişi Başlat" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Kendinden İmzalı Sertifika" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Kişisel imzalanmış SSL sertifikası kullanıyorsunuz, bu da sunucu kimliğinin " "doğrulanmamasına neden oluyor. Bu beklenen bir durumsa, bir CA zincir " "dosyası sağlamak için lütfen SSS’deki yönergeleri izleyin." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "SSS’yi aç" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "Bağlantı Kuruldu" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Bitti" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Eşzamanlama Kurulumu Tamamlandı" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Ana Hat" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Süzgeçle eşleşen başlık yok" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Anahat için başlık bulunamadı" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Arayüz" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Eş Aralıklı Yazı Tipi Kullan" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Yazım Denetimi Yap" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Düzenleyici içerik menüsü aracılığıyla dil değiştir" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Başlık Çubuğu" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Satır Uzunluğunu Sınırla" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "Öncelikle masaüstü için. İnce ayar yapmak için klavyede Ctrl + ↑ ve Ctrl + ↓ " "tuşlarını kullanın." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Söz Dizimini Algıla" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "Söz dizimi vurgulama ve biçimlendirme için gereklidir (araç çubuğu ve klavye " "kısayolları). Daha iyi başarım için devre dışı bırakın." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Tema" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Biçimlendirme Çubuğu" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Biçimlendirilmiş Görünümünü Etkinleştir" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Başlatma süresini azaltmak için devre dışı bırak" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Biçimlendirilmiş Görünümde Aç" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Etkinleştirilirse tüm notları işlenmiş markdown olarak açar" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Matematik Denklemleri Desteği" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "İşleme başarımını biraz azaltır" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Eş Aralıklı Yazı Tipi Kullanarak İşle" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Eş Aralıklı Yazı Tipi Boyutu Oranıyla Orantılı" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "İşleme görünümünde. Ayarlama yapılmaması için 1’i kullanın." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Motoru Bellekte Tut" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "" "Daha yüksek bellek kullanımına neden olurken sonraki dönüşümleri hızlandırır" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Kenar Çubuğunu Sabitle" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Masaüstünde, boşluk olduğunda" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Kategori Etiket Biçemi" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Veri" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Nextcloudʼa Bağlan" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Nextcloud Notes ile eşzamanlama oluştur" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Oturum Aç" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Nextcloud Bağlantısını Kes" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Nextcloud Notes’tan çıkış yap. Tüm notlar kaldırılır ve uygulamadan çıkılır." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Bağlantıyı Kes" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Veri Tabanını Sıfırla" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "Yerel veri tabanındaki tüm notları sil. Uygulamadan çıkılır." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Sıfırla" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Hata Ayıklama" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Eşzamanlama Zaman Damgasını Temizle" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Eşzamanlama sunucusundan tüm notları almaya zorlar" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Temizle" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Seçileni Sil" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Seçilen İçin Gözdeyi Değiştir" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Seçilen İçin Kategoriyi Değiştir" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Kategorileri Kapat" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Kategoriler" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Tablo Ekle" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Oluştur" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Sistem Biçemini İzle" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Açık Biçem" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Koyu Biçem" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Not oluştur" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Yedek oluştur" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Yedeği geri yükle" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Yedekleme yolunu göster" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "Özel sunucu SSL CA zincir dosyası yolunu göster" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "" "Kullanıcı arayüzünde genişletilmiş tercihlerin görüntülenmesini aç/kapat" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Çalışan herhangi bir örnekten çık" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Hata ayıklama günlüğünü ve işlevlerini etkinleştir" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Notları kimliğiyle aç" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Notlarda ara" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "GERİ YÜKLEME UZAK KİMLİK ÇATIŞMASI" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "GERİ YÜKLEME BAŞLIK ÇATIŞMASI" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Tüm Notlar" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Kategorisiz" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "Satır yüksekliği {0}px" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Satır uzunluğu sınırı devre dışı" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Bağlantıyı tarayıcıda aç" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} / {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "{} olarak dışa aktarıldı" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "{} dışa aktarılamadı" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Aktarılamadı" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} not silindi" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Not silindi" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Geri Al" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Düzenlenmekte olan notla eşzamanlama çakışması" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "Düzenlenen not uzaktan silindi" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Giz Servisi’ne erişim hatası. Kilidi açılmış, öntanımlı anahtarlığı kurulmuş " "gnome-keyring gibi bir sağlayıcınız olduğundan emin olun." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Eşzamanlanıyor" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} değişiklik" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Eşzamanlama hatası. Nextcloud Notes uygulaması sunucuda kurulu mu?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Yükleniyor" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Bağlantı Ekle" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Bağlantıyı Düzenle" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Notlar Güncelleniyor" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "İlk Aktarım Gerçekleştiriliyor" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "Bağlanılıyor" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "Giriş için Bekleniyor" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Kimlik doğrulama işlemini tarayıcınızda tamamlayın" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "Sertifika sorunu nedeniyle oturum açma başlatılamadı" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Giriş başlatılamadı. Adres yanlış mı?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Tek renkli" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Sessiz İmleme" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Kalın Biçimlendirme" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Devre Dışı" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Sessiz" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Mavi" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Turuncu" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Kırmızı" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "Hiçbiri" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Her Zaman Görünür" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Kendiliğinden Gizle" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Tam Ekranken Kendiliğinden Gizle" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "{0} basışta azaltılıyor" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "{0} basışta genişletiliyor" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Genişletme gizleniyor" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Genişletme gösteriliyor" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "Mobil aygıtlarda gizleme önerilmez" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Veri Tabanı Sıfırlansın Mı?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "Tüm notlar silinecek. Sıfırlama sürdürülsün mü?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Nextcloud Bağlantısını Kesilsin Mi?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "Tüm notlar kaldırılacak. Oturumu kapatmak istiyor musunuz?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Salt okunur notta kategori değiştirilemez" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "{} seçildi" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "EŞZAMANLAMA ÇAKIŞMASI" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Hata" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/uk.po000066400000000000000000001523701507102636600220070ustar00rootroot00000000000000# Ukrainian translation for Iotas. # Copyright (C) 2025 Iotas's COPYRIGHT HOLDER # This file is distributed under the same license as the Iotas package. # # Yuri Chornoivan , 2025. msgid "" msgstr "" "Project-Id-Version: Iotas main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-20 15:40+0000\n" "PO-Revision-Date: 2025-09-20 19:34+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" "%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Lokalize 23.04.3\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "Просте створення нотаток за допомогою Нотаток Nextcloud" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;docume" "nt;gnome;gtk;" msgstr "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;docume" "nt;gnome;gtk;нотатки;некстклауд;мінімальне;напруження;редактор;зосередження;т" "екст;записування;розмітка;документ;гноме;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "Створити нотатку" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "Просте створення нотаток" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "" "Iotas призначено для зосередженого створення нотаток з використанням " "сконцентрованого на мобільних пристроях дизайну." #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "Акценти" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "Додаткова швидка синхронізація із Нотатками Nextcloud" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "" "Автономне редагування нотаток, з наступною синхронізацією з інтернет-сховищем" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "Редагування і фільтрування за категоріями" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "Улюблене" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "Перевірка правопису" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "Пошук у збірці або окремих нотатках" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "" "Focus mode and optional hiding of the editor header and formatting bars" msgstr "" "Режим концентрації із можливим приховуванням заголовка редактора та панелей " "форматування" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "У попередньому перегляді: експортування до PDF, ODT та HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "" "Універсальний дизайн, погляд на Iotas як домашню на робочій станції як " "мобільному пристрої" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "Пошук з GNOME Shell" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "" "Резервне копіювання та відновлення нотаток (з інтерфейсу командного рядка " "для використання без синхронізації)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "Можливість змінити розмір шрифту та перемкнути моноширинний стиль" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "" "Підтримка написання нотаток мовою розмітки, але не обов'язкова, з " "можливостями" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "" "Форматування за допомогою панелі інструментів та клавіатурних скорочень" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "Підсвічування синтаксичних конструкцій з використанням тем" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "Форматований перегляд" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "Можливість викреслювання завдань зі списку у форматованому перегляді" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "Більше технічних подробиць для тих, хто знається на темі," #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "" "Синхронізація з Нотатками Nextcloud за допомогою програмного інтерфейсу " "REST, без WebDAV, що пришвидшує роботу" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "Передбачено базове виявлення конфліктів синхронізації" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "Неперервне збереження нотаток" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "" "Для пришвидшення запуску великі збірки нотаток завантажуються частково" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "Нотатки зберігаються у SQLite, що надає можливість швидкого пошуку (FTS) без " "винайдення колеса. Звичайні файли можна відновлювати з резервної копії " "(інтерфейс командного рядка)." #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "Покажчик" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Редактор з розміткою" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "Обробка розмітки" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "Покажчик у темному стилі" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "Мобільний" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "Юрій Чорноіван , 2025" #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "Скасувати зміни" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "Застосувати зміни" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "Застосувати" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "Очистити і застосувати" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "Знайти" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "Назад" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_dialog.ui:289 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "Попередній відповідник" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_dialog.ui:282 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "Наступний відповідник" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "Замінити" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "Режим фокусування" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "Знайти і замінити…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "Перейти до…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "Змінити заголовок…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "Змінити категорію…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "Вилучити" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "Експортувати…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "Повернутися до нотаток" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "Нотатку призначено лише для читання" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "Меню редактора" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "Увімкнути або вимкнути обробку розмітки" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "Змінити нотатку" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "Завантаження рушія обробки" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 #: iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "Скасувати" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "Експортувати як…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "Отримання…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "Експортування…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "Закрити" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "Показати" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "Не вдалося передати одне або декілька долучень." #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "Повторити спробу" #. Translators: Button #: data/ui/export_dialog.ui:297 #| msgid "Export As…" msgid "Export Anyway" msgstr "Експортувати попри це" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "Вітаємо у Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "Скористайтеся розміщеною вище панеллю заголовка для того, щоб…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "Додати нотатку" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "Синхронізуватися з Нотатками Nextcloud" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "Зменшити" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "Збільшити" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "Горизонтальна лінія" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "Цитата" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "Код" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "Таблиця" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "Рівень 1" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "Рівень 2" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "Рівень 3" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "Рівень 4" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "Вилучити" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "Заголовок" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "Напівжирний" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "Курсив" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "Закреслений" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "Невпорядкований список" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "Впорядкований список" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "Позначка" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "Посилання" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "Оновити" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "Налаштування" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "Клавіатурні скорочення" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "Про Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "Головне меню" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "Сьогодні" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "Вчора" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "Цього тижня" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "Цього місяця" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "Попереднього місяця" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "Показати попередні місяці" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "До попереднього місяця" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "Докладніше" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "Відкрити категорії" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 #: data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "Пошук" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "Позначити нотатки" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "Вимкнено з'єднання з сервером" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "" "Через зміни за лаштунками (новий ідентифікатор програми) Iotas потребує " "повторного проходження розпізнавання на вашому сервері Nextcloud" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "Пройти розпізнавання" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "" "Не вдалося отримати жетон розпізнавання для синхронізації з Нотатками " "Nextcloud" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "Відкинути" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "Список нотаток порожній" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "Вкажіть критерій пошуку" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "Нічого не знайдено" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "Створити нотатку" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "Показати бічну панель" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "Вилучити нотатку" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "Пересунути вище списком" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "Пересунути нижче списком" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "Почати позначення" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "Відкрити перший результат пошуку" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "Скинути фільтрування" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "Редактор" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "Змінити заголовок" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "Змінити категорію" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "Експортувати" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "Перейти до розділу" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "Створити нотатку з включенням позначеного" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "Скасувати введення" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "Повторити введення" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "Вставити емодзі" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "Фокусувати панель тексту" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "Фокусувати панель заголовка" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "Фокусувати панель форматування" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "Форматування" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "Позначити або зняти позначення з пункту" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "Пошук у редакторі" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "Вигляд редактора" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "Збільшити довжину рядка" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "Зменшити довжину рядка" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "Збільшити розмір шрифту" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "Зменшити розмір шрифту" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "Загальне" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "Перемикач повноекранного режиму" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "Показати налаштування" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "Показати клавіатурні скорочення" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "Відкрити попередню нотатку" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "Назад" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "Вийти" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "Адреса" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "Текст" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Налаштування Нотаток Nextcloud" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "" "Натисніть «Продовжити», щоб надати адресу сервера Nextcloud і увійти за " "допомогою браузера" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "Продовжити" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "Продовжити з введенням адреси" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "«Секретна служба» недоступна" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "Не вдалося отримати доступ до «Секретної служби» для збереження даних " "розпізнавання. Переконайтеся, що у вас є надавач даних, наприклад gnome-" "keyring. Слід налаштувати типове сховище ключів і це сховище розблоковано. " "Таке сховище надається у більшості робочих середовищ. Перезапустіть " "програму, щоб повторити спробу." #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "Адреса сервера" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "Початковий вхід" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "Самопідписаний сертифікат" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "Схоже, що ви використовуєте самопідписаний сертифікат SSL, через що на " "сервері профіль не проходить перевірки. Якщо так і має бути, будь ласка, " "дотримуйтесь інструкцій зі списку поширених питань щодо програми, щоб надати " "файл ланцюга центрів сертифікації." #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "Відкрити поширені питання" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "З'єднання встановлено" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "Виконано" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "Завершити налаштовування синхронізації" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "Схема" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "Фільтру не відповідає жоден заголовок" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "Не знайдено заголовків для ескіза" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "Інтерфейс" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "Використати моноширинний шрифт" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "Перевірка правопису" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "Змініть мову за допомогою контекстного меню редактора" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "Панель заголовка" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "Обмежити довжину рядка" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "" "В основному для робочих станцій. Скористайтеся Ctrl + ↑ і Ctrl + ↓ на " "клавіатурі для коригування." #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "Виявлення синтаксису" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "" "Потрібне для підсвічування синтаксичних конструкцій і форматування (панелі " "інструментів та клавіатурних скорочень). Вимкніть для певного збільшення " "швидкодії." #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "Тема" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "Панель форматування" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "Увімкнути форматований перегляд" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "Вимкніть для пришвидшення запуску програми" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "Відкрити у форматованому перегляді" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "Вмикання відкриває усі нотатки як оброблений код розмітки" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "Підтримка рівнянь" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "Дещо зменшує швидкодію оброблення" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "Обробляти за допомогою моноширинного шрифту" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "Коефіцієнт пропорційності до розміру моноширинного шрифту" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "Для обробленого перегляду. Скористайтеся 1 для вимикання коригування." #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "Тримати рушій у пам'яті" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "Пришвидшення перетворення, але більше використання пам'яті" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "Пришпилити бічну панель" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "Для робочих станцій, якщо є місце" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "Стиль міток категорій" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "Дані" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "Встановлення з'єднання з Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "Встановити синхронізацію з Нотатками Nextcloud" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "Увійти" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "Від'єднати Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "" "Скасувати вхід до Нотаток Nextcloud. Усі нотатки буде вилучено, а програма " "завершить роботу." #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "Від’єднатися" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "Скидання бази даних" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "" "Вилучити усі нотатки з локальної бази даних. Програма завершить роботу." #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "Скинути" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "Діагностика" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "Вилучити часову позначку синхронізації" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "Примусово отримати усі нотатки з сервера синхронізації" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "Очистити" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "Вилучити позначене" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "Включити або виключити позначене з улюбленого" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "Змінити категорію для позначеного" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "Закрити категорії" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "Категорії" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "Вставити таблицю" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "Створити" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "Використовувати стиль системи" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "Світлий стиль" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "Темний стиль" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "Створення примітки" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "Створити резервну копію" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "Відновлення з резервної копії" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "Показати шлях до резервної копії" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "" "Показати шлях до нетипового файла ланцюжка центрів сертифікації сервера SSL" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "" "Увімкнути або вимкнути показ розширених налаштувань в інтерфейсі користувача" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "Завершити роботу усіх запущених екземплярів" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "Увімкнути діагностичний журнал і функції" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "Відкрити нотатку за ідентифікатором" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "Шукати в нотатках" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "КОНФЛІКТ ВІДДАЛЕНОГО ІДЕНТИФІКАТОРА ПРИ ВІДНОВЛЕННІ" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "КОНФЛІКТ ЗАГОЛОВКІВ ПРИ ВІДНОВЛЕННІ" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "Усі нотатки" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "Поза категоріями" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "Тепер довжина рядка {0} пікселів" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "Обмеження довжини рядків вимкнено" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "Відкриття посилання у браузері" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} з {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "Експортовано до {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "Не вдалося експортувати до {}" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "Не вдалося передати" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "{} нотаток вилучено" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "Нотатку вилучено" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "Скасувати" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "Конфлікт синхронізації при редагуванні нотатки" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "Редаговану нотатку було віддалено вилучено" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "Не вдалося отримати доступ до «Секретної служби». Переконайтеся, що у вас є " "надавач даних, наприклад gnome-keyring, у якому розблоковано доступ до " "типового сховища ключів." #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "Синхронізація" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} зміна" msgstr[1] "{} зміни" msgstr[2] "{} змін" msgstr[3] "{} зміна" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "Помилка синхронізації. Чи встановлено Нотатки Nextcloud на сервері?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "Завантаження" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "Вставити посилання" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "Редагування посилання" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "Оновлення нотаток" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "Виконання початкового передавання даних" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "З'єднання" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "Очікуємо на вхід" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "Завершити розпізнавання у вашому браузері" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "Не вдалося увійти через можливу проблему із сертифікацією" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "Не вдалося увійти. Помилкова адреса?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "Чорно-білий" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "Приглушена розмітка" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "Напівжирна розмітка" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "Вимкнено" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "Приглушений" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "Синій" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "Помаранчевий" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "Червоний" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "Немає" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "Показувати завжди" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "Автоматично ховати" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "Автоматично ховати у повноекранному режимі" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "Зменшуємо за {0} натискань" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "Розширюємо за {0} натискань" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "Розширені приховано" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "Розширені показано" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "Не варто ховати на мобільному" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "Скинути базу даних?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "Усі нотатки буде вилучено. Продовжити скидання?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "Від'єднатися від Nextcloud?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "Усі нотатки буде вилучено. Справді хочете вийти?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "Не можна змінювати категорію для призначеної лише для читання нотатки" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "Позначено {}" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "КОНФЛІКТ СИНХРОНІЗАЦІЇ" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "Помилка" #~ msgid "Export As..." #~ msgstr "Експортувати як…" #~ msgid "Exporting..." #~ msgstr "Експортування…" #~ msgid "OK" #~ msgstr "Гаразд" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/po/zh_CN.po000066400000000000000000001323201507102636600223620ustar00rootroot00000000000000# Chinese translation for iotas package. # Copyright (C) 2024 The Iotas team # This file is distributed under the same license as the iotas package. # lumingzh , 2024-2025. # msgid "" msgstr "" "Project-Id-Version: iotas-main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/iotas/issues\n" "POT-Creation-Date: 2025-09-19 21:40+0000\n" "PO-Revision-Date: 2025-09-20 07:42+0800\n" "Last-Translator: lumingzh \n" "Language-Team: Chinese (China) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Gtranslator 49.0\n" #. Translators: Iotas is the app name, do not translate #: data/org.gnome.World.Iotas.desktop.in.in:3 #: data/org.gnome.World.Iotas.metainfo.xml.in.in:5 msgid "Iotas" msgstr "Iotas" #. Translators: App description/comment in .desktop file #: data/org.gnome.World.Iotas.desktop.in.in:5 msgid "Simple note taking with Nextcloud Notes" msgstr "带有 Nextcloud 笔记功能的简单笔记应用" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.gnome.World.Iotas.desktop.in.in:13 msgid "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" msgstr "" "notes;nextcloud;minimal;distraction;editor;focused;text;write;markdown;document;gnome;gtk;" "笔记;备注;便笺;编辑器;文本;编写;撰写;文档;" #. Translators: Button #: data/org.gnome.World.Iotas.desktop.in.in:22 data/ui/index.ui:42 msgid "New Note" msgstr "新建笔记" #. Translators: The application's summary / tagline #: data/org.gnome.World.Iotas.metainfo.xml.in.in:11 msgid "Simple note taking" msgstr "简单的笔记应用" #. Translators: Part of metainfo description. "Iotas" is the application name; do not translate. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:52 msgid "" "Iotas aims to provide distraction-free note taking via its mobile-first " "design." msgstr "Iotas 通过其移动应用优先的设计来提供无干扰的笔记编写体验。" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:54 msgid "Featuring" msgstr "特性" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:57 msgid "Optional speedy sync with Nextcloud Notes" msgstr "可选的与 Nextcloud 笔记快速同步" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:59 msgid "Offline note editing, syncing when back online" msgstr "离线笔记编辑,恢复在线时同步" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:61 msgid "Category editing and filtering" msgstr "编辑和筛选分类" #. Translators: Part of metainfo description #. Translators: Section title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:63 #: data/ui/index_note_list.ui:17 msgid "Favorites" msgstr "最爱" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:65 msgid "Spell checking" msgstr "拼写检查" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:67 msgid "Search within the collection or individual notes" msgstr "在集合或单独笔记中搜索" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:69 msgid "Focus mode and optional hiding of the editor header and formatting bars" msgstr "专注模式和可选隐藏编辑器标头栏及格式化栏" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:71 msgid "In preview: export to PDF, ODT and HTML" msgstr "预览中:导出为 PDF、ODT 和 HTML" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:73 msgid "A convergent design, seeing Iotas as at home on desktop as mobile" msgstr "趋同设计,在桌面应用中获得如同移动应用的家的体验" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:75 msgid "Search from GNOME Shell" msgstr "从 GNOME Shell 中搜索" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:77 msgid "Note backup and restoration (from CLI, for using without sync)" msgstr "笔记备份和恢复(来自命令行,用于不使用同步的情况)" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:79 msgid "The ability to change font size and toggle monospace style" msgstr "可以更改字体大小和切换等宽样式" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:82 msgid "Writing in markdown is supported but optional, providing" msgstr "提供了对 Markdown 编写的可选支持" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:85 msgid "Formatting via toolbar and shortcuts" msgstr "通过工具栏和快捷键格式化" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:87 msgid "Syntax highlighting with themes" msgstr "带主题的语法高亮" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:89 msgid "A formatted view" msgstr "格式化的视图" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:91 msgid "The ability to check off task lists from the formatted view" msgstr "可从格式化视图核对任务列表" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:94 msgid "Slightly more technical details, for those into that type of thing" msgstr "对专业人士有更多的技术细节" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:97 msgid "" "Nextcloud Notes sync is via the REST API, not WebDAV, which makes it snappy" msgstr "Nextcloud 笔记同步是通过 REST 接口实现的而不是 WebDAV,这使其更加简洁" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:99 msgid "There's basic sync conflict detection" msgstr "具有基本的同步冲突检测" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:101 msgid "Notes are constantly saved" msgstr "笔记会时常保存" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:103 msgid "Large note collections are partially loaded to quicken startup" msgstr "大型笔记集合会部分加载来加快启动速度" #. Translators: Part of metainfo description #: data/org.gnome.World.Iotas.metainfo.xml.in.in:105 msgid "" "Notes are stored in SQLite, providing for fast search (FTS) without " "reinventing the wheel. Plain files can be retrieved by making a backup (CLI)." msgstr "" "笔记存储在 SQLite 中,不需要重复造轮子即可提供快速搜索功能。纯文本文件可通过" "备份取回(命令行)。" #. Translators: A screenshot description. #. Translators: Title #: data/org.gnome.World.Iotas.metainfo.xml.in.in:112 #: data/ui/keyboard_shortcuts_dialog.ui:7 data/ui/preferences_dialog.ui:138 msgid "Index" msgstr "首页" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:117 msgid "Editor with markdown" msgstr "Markdown 编辑器" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:122 msgid "Rendered markdown" msgstr "渲染的 Markdown" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:127 msgid "Index in dark style" msgstr "暗色样式的首页" #. Translators: A screenshot description. #: data/org.gnome.World.Iotas.metainfo.xml.in.in:132 msgid "Mobile" msgstr "移动应用" #. Add your name to the translator credits list #: data/ui/about_dialog.ui.in:13 msgid "translator-credits" msgstr "lumingzh , 2024-2025." #. Translators: Button #: data/ui/category_header_bar.ui:15 data/ui/editor_rename_header_bar.ui:17 msgid "Revert Changes" msgstr "还原更改" #. Translators: Button tooltip #: data/ui/category_header_bar.ui:42 data/ui/editor_rename_header_bar.ui:40 msgid "Apply Changes" msgstr "应用更改" #. Translators: Button #: data/ui/category_header_bar.ui:44 data/ui/editor_rename_header_bar.ui:42 #: iotas/link_dialog.py:52 msgid "Apply" msgstr "应用" #. Translators: Button #: data/ui/category_header_bar.ui:58 msgid "Clear and Apply" msgstr "清除并应用" #. Translators: Placeholder text #: data/ui/editor_search_entry.ui:14 msgid "Find" msgstr "查找" #. Translators: Button #: data/ui/editor_search_header_bar.ui:16 data/ui/index_search_header_bar.ui:12 #: data/ui/render_search_header_bar.ui:15 data/ui/selection_header_bar.ui:17 msgid "Back" msgstr "返回" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:43 #: data/ui/keyboard_shortcuts_dialog.ui:289 #: data/ui/render_search_header_bar.ui:36 msgid "Previous Match" msgstr "上个匹配" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #. Translators: Button tooltip #: data/ui/editor_search_header_bar.ui:51 #: data/ui/keyboard_shortcuts_dialog.ui:282 #: data/ui/render_search_header_bar.ui:44 msgid "Next Match" msgstr "下个匹配" #. Translators: Placeholder text #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor_search_header_bar.ui:73 #: data/ui/editor_search_header_bar.ui:82 #: data/ui/keyboard_shortcuts_dialog.ui:275 msgid "Replace" msgstr "替换" #. Translators: Menu item #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:18 data/ui/keyboard_shortcuts_dialog.ui:302 msgid "Focus Mode" msgstr "专注模式" #. Translators: Menu item #: data/ui/editor.ui:25 msgid "Find and Replace…" msgstr "查找和替换…" #. Translators: Menu item #: data/ui/editor.ui:30 msgid "Jump To…" msgstr "跳转至…" #. Translators: Menu item #: data/ui/editor.ui:37 msgid "Edit Title…" msgstr "编辑标题…" #. Translators: Menu item #: data/ui/editor.ui:42 msgid "Change Category…" msgstr "更改分类…" #. Translators: Menu item #: data/ui/editor.ui:47 msgid "Delete" msgstr "删除" #. Translators: Menu item #: data/ui/editor.ui:54 msgid "Export…" msgstr "导出…" #. Translators: Button #: data/ui/editor.ui:88 msgid "Back to Notes" msgstr "返回笔记" #. Translators: Description, tooltip #: data/ui/editor.ui:124 msgid "Note is Read-Only" msgstr "笔记为只读模式" #. Translators: Button #: data/ui/editor.ui:134 msgid "Editor Menu" msgstr "编辑器菜单" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/editor.ui:142 data/ui/keyboard_shortcuts_dialog.ui:95 msgid "Toggle Markdown Render" msgstr "切换 Markdown 渲染" #. Translators: Button #: data/ui/editor.ui:150 msgid "Edit Note" msgstr "编辑笔记" #. Translators: Description, help #: data/ui/editor.ui:285 msgid "Render Engine Loading" msgstr "正在加载渲染引擎" #. Translators: Button #: data/ui/export_dialog.ui:22 iotas/preferences_dialog.py:346 #: iotas/preferences_dialog.py:371 msgid "Cancel" msgstr "取消" #. Translators: Title #: data/ui/export_dialog.ui:30 msgid "Export As…" msgstr "导出为…" #. Translators: Title #: data/ui/export_dialog.ui:51 msgid "Downloading…" msgstr "正在下载…" #. Translators: Title #: data/ui/export_dialog.ui:72 msgid "Exporting…" msgstr "正在导出…" #. Translators: Button #. Translators: Title #. Translators: Button #: data/ui/export_dialog.ui:92 data/ui/export_dialog.ui:117 #: data/ui/outline_dialog.ui:104 iotas/ui_utils.py:92 msgid "Close" msgstr "关闭" #. Translators: Button #: data/ui/export_dialog.ui:99 msgid "Show" msgstr "显示" #. Translators: Description #: data/ui/export_dialog.ui:276 msgid "One or more attachments failed to transfer." msgstr "一个或更多附件传输失败。" #. Translators: Button #: data/ui/export_dialog.ui:288 msgid "Retry" msgstr "重试" #. Translators: Button #: data/ui/export_dialog.ui:297 msgid "Export Anyway" msgstr "仍然导出" #. Translators: Title. Iotas is the application name and shouldn't be translated. #: data/ui/first_start_page.ui:10 msgid "Welcome to Iotas" msgstr "欢迎使用 Iotas" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:20 msgid "Use the header bar above to…" msgstr "使用上方的标头栏来…" #. Translators: Description, introduction help #: data/ui/first_start_page.ui:43 msgid "Add a Note" msgstr "添加笔记" #. Translators: Description, introduction help #. Translators: Menu item #: data/ui/first_start_page.ui:64 data/ui/index_menu_button.ui:13 msgid "Sync with Nextcloud Notes" msgstr "与 Nextcloud 笔记同步" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:15 data/ui/font_size_selector.ui:19 msgid "Zoom Out" msgstr "缩小" #. Translators: Button tooltip #. Translators: Button #: data/ui/font_size_selector.ui:35 data/ui/font_size_selector.ui:39 msgid "Zoom In" msgstr "放大" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:7 data/ui/formatting_header_bar.ui:158 #: data/ui/keyboard_shortcuts_dialog.ui:241 msgid "Horizontal Rule" msgstr "水平线" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:12 data/ui/formatting_header_bar.ui:167 #: data/ui/keyboard_shortcuts_dialog.ui:248 msgid "Quote" msgstr "引用" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:17 data/ui/formatting_header_bar.ui:176 #: data/ui/keyboard_shortcuts_dialog.ui:227 msgid "Code" msgstr "代码" #. Translators: Menu item #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:22 data/ui/formatting_header_bar.ui:185 #: data/ui/keyboard_shortcuts_dialog.ui:255 msgid "Table" msgstr "表格" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:31 msgid "Level 1" msgstr "1 级" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:36 msgid "Level 2" msgstr "2 级" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:41 msgid "Level 3" msgstr "3 级" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:46 msgid "Level 4" msgstr "4 级" #. Translators: Menu item #: data/ui/formatting_header_bar.ui:51 msgid "Remove" msgstr "移除" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:81 data/ui/keyboard_shortcuts_dialog.ui:185 msgid "Heading" msgstr "标题" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:90 data/ui/keyboard_shortcuts_dialog.ui:171 msgid "Bold" msgstr "粗体" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:99 data/ui/keyboard_shortcuts_dialog.ui:178 msgid "Italic" msgstr "斜体" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:108 #: data/ui/keyboard_shortcuts_dialog.ui:234 msgid "Strikethrough" msgstr "删除线" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:117 #: data/ui/keyboard_shortcuts_dialog.ui:192 msgid "Unordered List" msgstr "无序列表" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:126 #: data/ui/keyboard_shortcuts_dialog.ui:199 msgid "Ordered List" msgstr "有序列表" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:135 #: data/ui/keyboard_shortcuts_dialog.ui:206 msgid "Checkbox" msgstr "选择框" #. Translators: Button tooltip #. Translators: Description, keyboard shortcut #: data/ui/formatting_header_bar.ui:144 #: data/ui/keyboard_shortcuts_dialog.ui:220 msgid "Link" msgstr "链接" #. Translators: Menu item #: data/ui/index_menu_button.ui:19 msgid "Refresh" msgstr "刷新" #. Translators: Menu item #: data/ui/index_menu_button.ui:27 msgid "Preferences" msgstr "首选项" #. Translators: Menu item #: data/ui/index_menu_button.ui:32 msgid "Keyboard Shortcuts" msgstr "键盘快捷键" #. Translators: Menu item, Iotas is the application name and shouldn't be translated #: data/ui/index_menu_button.ui:37 msgid "About Iotas" msgstr "关于 Iotas" #. Translators: Button #: data/ui/index_menu_button.ui:44 msgid "Main Menu" msgstr "主菜单" #. Translators: Section title #: data/ui/index_note_list.ui:59 msgid "Today" msgstr "今天" #. Translators: Section title #: data/ui/index_note_list.ui:91 msgid "Yesterday" msgstr "昨天" #. Translators: Section title #: data/ui/index_note_list.ui:123 msgid "This Week" msgstr "本周" #. Translators: Section title #: data/ui/index_note_list.ui:155 msgid "This Month" msgstr "本月" #. Translators: Section title #: data/ui/index_note_list.ui:187 msgid "Last Month" msgstr "上月" #. Translators: Button #: data/ui/index_note_list.ui:218 msgid "Show Earlier Months" msgstr "显示更早月份" #. Translators: Section title #: data/ui/index_note_list.ui:236 msgid "Before Last Month" msgstr "上月之前" #. Translators: Button #: data/ui/index_note_list.ui:284 msgid "Show More" msgstr "显示更多" #. Translators: Button #: data/ui/index.ui:34 msgid "Open Categories" msgstr "打开分类" #. Translators: Button #. Translators: Description, keyboard shortcut #: data/ui/index.ui:61 data/ui/keyboard_shortcuts_dialog.ui:54 #: data/ui/keyboard_shortcuts_dialog.ui:268 msgid "Search" msgstr "搜索" #. Translators: Button #: data/ui/index.ui:69 msgid "Select Notes" msgstr "选择笔记" #. Translators: Description #: data/ui/index.ui:87 msgid "Server connection offline" msgstr "服务器连接离线" #. Translators: Description #: data/ui/index.ui:93 msgid "" "Due to behind-the-scenes changes (a new app id) Iotas needs to " "reauthenticate with your Nextcloud server" msgstr "由于幕后更改(新的应用标识)Iotas 需要与您的 Nextcloud 服务器重新认证" #. Translators: Button #: data/ui/index.ui:95 data/ui/index.ui:104 msgid "Authenticate" msgstr "认证" #. Translators: Description #: data/ui/index.ui:102 msgid "" "The authentication token for sync with Nextcloud Notes could not be retrieved" msgstr "用于 Nextcloud 笔记同步的认证口令无法取回" #. Translators: Button #: data/ui/index.ui:111 msgid "Dismiss" msgstr "拒绝" #. Translators: Description, help #: data/ui/index.ui:136 msgid "Note List Empty" msgstr "笔记列表为空" #. Translators: Description, help #: data/ui/index.ui:143 msgid "Enter Search Term" msgstr "输入搜索词" #. Translators: Description, help #: data/ui/index.ui:150 msgid "No Search Results" msgstr "无搜索结果" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:12 msgid "Create New Note" msgstr "创建新笔记" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:19 msgid "Show Sidebar" msgstr "显示侧边栏" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:26 msgid "Delete Note" msgstr "删除笔记" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:33 msgid "Move Up List" msgstr "上移列表" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:40 msgid "Move Down List" msgstr "下移列表" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:47 msgid "Start Selection" msgstr "开始选择" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:61 msgid "Open First Search Result" msgstr "打开首个搜索结果" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:68 msgid "Reset Filter" msgstr "重置筛选" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:76 data/ui/preferences_dialog.ui:14 msgid "Editor" msgstr "编辑器" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:81 msgid "Edit Title" msgstr "编辑标题" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:88 msgid "Change Category" msgstr "更改分类" #. Translators: Description, keyboard shortcut #. Translators: Button #: data/ui/keyboard_shortcuts_dialog.ui:102 iotas/export_dialog.py:159 msgid "Export" msgstr "导出" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:109 msgid "Jump to Section" msgstr "跳转到章节" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:116 msgid "Create New Note Including Selection" msgstr "创建包括选择的新笔记" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:123 msgid "Undo Typing" msgstr "撤消输入" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:130 msgid "Redo Typing" msgstr "重做输入" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:137 msgid "Insert Emoji" msgstr "插入表情" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:144 msgid "Focus Text View" msgstr "聚焦文本视图" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:151 msgid "Focus Header Bar" msgstr "聚焦标头栏" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:158 msgid "Focus Formatting Bar" msgstr "聚焦格式化栏" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:166 msgid "Formatting" msgstr "格式化" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:213 msgid "Toggle Checkbox" msgstr "切换选择框" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:263 msgid "Editor Search" msgstr "编辑器搜索" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:297 msgid "Editor Appearance" msgstr "编辑器外观" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:309 msgid "Increase Line Length" msgstr "增加行长度" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:316 msgid "Decrease Line Length" msgstr "减少行长度" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:323 msgid "Increase Font Size" msgstr "增大字号" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:330 msgid "Decrease Font Size" msgstr "减小字号" #. Translators: Title #: data/ui/keyboard_shortcuts_dialog.ui:338 msgid "General" msgstr "常规" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:343 msgid "Toggle Fullscreen" msgstr "切换全屏" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:350 msgid "Show Preferences" msgstr "显示首选项" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:357 msgid "Show Shortcuts" msgstr "显示快捷键" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:364 msgid "Open Previous Note" msgstr "打开上篇笔记" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:371 msgid "Go Back" msgstr "返回" #. Translators: Description, keyboard shortcut #: data/ui/keyboard_shortcuts_dialog.ui:378 msgid "Quit" msgstr "退出" #. Translators: Title #: data/ui/link_dialog.ui:19 msgid "URL" msgstr "URL" #. Translators: Title #: data/ui/link_dialog.ui:26 msgid "Text" msgstr "文本" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:16 msgid "Nextcloud Notes Setup" msgstr "Nextcloud 笔记部署" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:31 msgid "" "Press Continue to provide your Nextcloud server address and login via a web " "browser" msgstr "按继续来提供您的 Nextcloud 服务器地址并通过网络浏览器登录" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:36 data/ui/nextcloud_login_dialog.ui:93 msgid "Continue" msgstr "继续" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:38 msgid "Continue to URL Entry" msgstr "前进至 URL 输入" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:56 msgid "Secret Service Inaccessible" msgstr "无法访问保密服务" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:58 msgid "" "The Secret Service could not be accessed for storing authentication details. " "Ensure you have a provider such as gnome-keyring. A default keyring needs to " "be setup, and that keyring unlocked. Most desktop environments will provide " "this for you. Restart the app to try again." msgstr "" "无法访问保密服务来存储认证详情。请确保您拥有保密服务提供者如 gnome-keyring。" "需要部署一个默认密钥串,且该密钥串已解锁。大部分桌面环境都会提供这些。重启应" "用来重试。" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:80 msgid "Server URL" msgstr "服务器 URL" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:95 msgid "Start Login" msgstr "开始登录" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:117 msgid "Self-Signed Certificate" msgstr "自签名证书" #. Translators: Description #: data/ui/nextcloud_login_dialog.ui:119 msgid "" "You appear to be using a self-signed SSL certificate resulting in the server " "identity not being verified. If this is expected please follow the " "instructions in the FAQ to provide a CA chain file." msgstr "" "您看起来使用了自签名的 SSL 证书导致服务器标识不被验证。如果这是预期结果请遵循" "常见问题中的介绍来提供证书链文件。" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:123 msgid "Open the FAQ" msgstr "打开常见问题" #. Translators: Title #: data/ui/nextcloud_login_dialog.ui:154 msgid "Connection Established" msgstr "连接已建立" #. Translators: Button #: data/ui/nextcloud_login_dialog.ui:169 msgid "Done" msgstr "完成" #. Translators: Button tooltip #: data/ui/nextcloud_login_dialog.ui:171 msgid "Complete Sync Setup" msgstr "完成同步部署" #. Translators: Title #: data/ui/outline_dialog.ui:19 msgid "Outline" msgstr "大纲" #. Translators: Title #: data/ui/outline_dialog.ui:90 msgid "No headings matching filter" msgstr "无匹配筛选器的标题" #. Translators: Description #: data/ui/outline_dialog.ui:100 msgid "No headings found for outline" msgstr "未找到用于大纲的标题" #. Translators: Title #: data/ui/preferences_dialog.ui:10 msgid "Interface" msgstr "界面" #. Translators: Title #: data/ui/preferences_dialog.ui:18 msgid "Use Monospace Font" msgstr "使用等宽字体" #. Translators: Title #: data/ui/preferences_dialog.ui:25 msgid "Check Spelling" msgstr "检查拼写" #. Translators: Description, help #: data/ui/preferences_dialog.ui:28 msgid "Change language via the editor context menu" msgstr "通过编辑器上下文菜单更改语言" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:34 msgid "Header Bar" msgstr "标头栏" #. Translators: Title #: data/ui/preferences_dialog.ui:40 msgid "Limit Line Length" msgstr "限制行长度" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:43 msgid "" "Primarily for desktop. Use Ctrl + ↑ and Ctrl + ↓ on keyboard to fine tune." msgstr "主要用于桌面。使用 Ctrl + ↑ 和 Ctrl + ↓ 可做调整。" #. Translators: Title #: data/ui/preferences_dialog.ui:51 msgid "Markdown" msgstr "Markdown" #. Translators: Title #: data/ui/preferences_dialog.ui:55 msgid "Detect Syntax" msgstr "检测语法" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:57 msgid "" "Required for syntax highlighting and formatting (toolbar and keyboard " "shortcuts). Disable for slightly improved performance." msgstr "语法高亮和格式化(工具栏和键盘快捷键)需要该选项。禁用可略微提升性能。" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:64 msgid "Theme" msgstr "主题" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:70 msgid "Formatting Bar" msgstr "格式化栏" #. Translators: Title #: data/ui/preferences_dialog.ui:76 msgid "Enable Formatted View" msgstr "启用格式化视图" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:78 msgid "Disable to reduce startup time" msgstr "禁用可减少启动时间" #. Translators: Title #: data/ui/preferences_dialog.ui:85 msgid "Open In Formatted View" msgstr "以格式化视图打开" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:87 msgid "Enabling opens all notes as rendered markdown" msgstr "启用会将所有笔记作为已渲染的 Markdown 打开" #. Translators: Title #: data/ui/preferences_dialog.ui:94 msgid "Support Math Equations" msgstr "支持数学公式" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:96 msgid "Slightly decreases render performance" msgstr "略微降低渲染性能" #. Translators: Title #: data/ui/preferences_dialog.ui:103 msgid "Render Using Monospace Font" msgstr "使用等宽字体渲染" #. Translators: Title #: data/ui/preferences_dialog.ui:110 msgid "Proportional To Monospace Font Size Ratio" msgstr "与等宽字体大小比例相称" #: data/ui/preferences_dialog.ui:111 msgid "In render view. Use 1 for no adjustment." msgstr "在渲染视图中。使用 1 为无调整。" #. Translators: Title #: data/ui/preferences_dialog.ui:127 msgid "Hold Engine In Memory" msgstr "在内存中保留引擎" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:129 msgid "Faster subsequent conversions for higher memory usage" msgstr "用更高的内存占用获得更快的并发转换" #. Translators: Title #: data/ui/preferences_dialog.ui:142 msgid "Pin Sidebar" msgstr "固定侧边栏" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:144 msgid "On desktop, when there is space" msgstr "在桌面电脑上且有可用空间时" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:152 msgid "Category Label Style" msgstr "分类标签样式" #. Translators: Title #: data/ui/preferences_dialog.ui:163 msgid "Data" msgstr "数据" #. Translators: Title #: data/ui/preferences_dialog.ui:169 msgid "Connect Nextcloud" msgstr "连接 Nextcloud" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:171 msgid "Establish sync with Nextcloud Notes" msgstr "与 Nextcloud 笔记建立同步" #. Translators: Button #: data/ui/preferences_dialog.ui:178 msgid "Log In" msgstr "登录" #. Translators: Title #: data/ui/preferences_dialog.ui:187 msgid "Disconnect Nextcloud" msgstr "断开 Nextcloud 连接" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:189 msgid "" "Signs out from Nextcloud Notes. All notes will be removed and the app will " "quit." msgstr "从 Nextcloud 笔记登出。所有笔记将被移除且该应用将退出。" #. Translators: Button #: data/ui/preferences_dialog.ui:196 iotas/preferences_dialog.py:373 msgid "Disconnect" msgstr "断开连接" #. Translators: Title #: data/ui/preferences_dialog.ui:208 msgid "Reset Database" msgstr "重置数据库" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:210 msgid "Delete all notes from the local database. The app will quit." msgstr "从本地数据库删除所有笔记。该应用将退出。" #. Translators: Button #: data/ui/preferences_dialog.ui:217 iotas/preferences_dialog.py:348 msgid "Reset" msgstr "重置" #. Translators: Title #: data/ui/preferences_dialog.ui:235 msgid "Debug" msgstr "调试" #. Translators: Title #: data/ui/preferences_dialog.ui:241 msgid "Clear Sync Timestamp" msgstr "清除同步时间戳" #. Translators: Description, preference #: data/ui/preferences_dialog.ui:243 msgid "Forces a pull of all notes from the sync server" msgstr "强行从同步服务器拉取所有笔记" #. Translators: Button #: data/ui/preferences_dialog.ui:250 msgid "Clear" msgstr "清除" #. Translators: Button #: data/ui/selection_header_bar.ui:33 msgid "Delete Selected" msgstr "删除选中项" #. Translators: Button #: data/ui/selection_header_bar.ui:44 msgid "Toggle Favorite for Selected" msgstr "为选中项切换最爱" #. Translators: Button #: data/ui/selection_header_bar.ui:52 msgid "Change Category for Selected" msgstr "为选中项更改分类" #. Translators: Button #: data/ui/sidebar.ui:13 msgid "Close Categories" msgstr "关闭分类" #. Translators: Title #: data/ui/sidebar.ui:21 msgid "Categories" msgstr "分类" #. Translators: Title #: data/ui/table_dialog.ui:6 msgid "Insert Table" msgstr "插入表格" #. Translators: Title #. Translators: Button #: data/ui/table_dialog.ui:44 iotas/link_dialog.py:47 msgid "Create" msgstr "创建" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:25 data/ui/theme_selector.ui:28 msgid "Follow System Style" msgstr "跟随系统样式" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:44 data/ui/theme_selector.ui:47 msgid "Light Style" msgstr "亮色样式" #. Translators: Description, tooltip #. Translators: Description, accessibility #: data/ui/theme_selector.ui:63 data/ui/theme_selector.ui:66 msgid "Dark Style" msgstr "暗色样式" #. Translators: Description, CLI option #: iotas/application.py:285 msgid "Create a note" msgstr "创建笔记" #. Translators: Description, CLI option #: iotas/application.py:294 msgid "Create a backup" msgstr "创建备份" #. Translators: Description, CLI option #: iotas/application.py:303 msgid "Restore a backup" msgstr "恢复备份" #. Translators: Description, CLI option #: iotas/application.py:312 msgid "Display backup path" msgstr "显示备份路径" #. Translators: Description, CLI option #: iotas/application.py:321 msgid "Display path for custom server SSL CA chain file" msgstr "显示自定义服务器 SSL 证书链文件路径" #. Translators: Description, CLI option #: iotas/application.py:330 msgid "Toggle display of extended preferences in UI" msgstr "切换显示用户界面中的扩展首选项" #. Translators: Description, CLI option #: iotas/application.py:339 msgid "Quit any running instance" msgstr "退出所有运行中的实例" #. Translators: Description, CLI option #: iotas/application.py:348 msgid "Enable debug logging and functions" msgstr "启用调试日志和功能" #. Translators: Description, CLI option #: iotas/application.py:357 msgid "Open note by id" msgstr "通过标识打开笔记" #. Translators: Description, CLI option #: iotas/application.py:366 msgid "Search in notes" msgstr "在笔记中搜索" #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:205 msgid "RESTORATION REMOTE ID CLASH" msgstr "恢复远程标识冲突" #. Duplicate note #. Translators: Description, prefixes note title on backup restoration clash #: iotas/backup_manager.py:223 msgid "RESTORATION TITLE CLASH" msgstr "恢复标题冲突" #. Translators: Title #: iotas/category.py:19 msgid "All Notes" msgstr "所有笔记" #. Translators: Title #: iotas/category.py:21 msgid "Uncategorised" msgstr "未分类" #. Translators: Description, notification, {0} is a number #: iotas/editor.py:993 #, python-brace-format msgid "Line length now {0}px" msgstr "行长度现在为 {0} 像素" #. Translators: Description, notification #: iotas/editor.py:999 msgid "Line length limit disabled" msgstr "行长度限制已禁用" #: iotas/editor.py:1579 msgid "Opening link in browser" msgstr "在浏览器中打开链接" #. Translators: Description, {0} the current position in {1} a number of search results #: iotas/editor_search_entry.py:66 #, python-brace-format msgid "{0} of {1}" msgstr "{0} 共 {1}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:128 msgid "Exported to {}" msgstr "已导出为 {}" #. Translators: Description, {} is a format eg. PDF #: iotas/export_dialog.py:141 msgid "Failed to export to {}" msgstr "导出为 {} 失败" #. Translators: Title #: iotas/export_dialog.py:209 msgid "Transfer Failed" msgstr "传输失败" #. Translators: Description, notification, {} is a positive number #: iotas/index.py:205 msgid "{} notes deleted" msgstr "已删除 {} 条笔记" #. Translators: Description, notification #: iotas/index.py:208 msgid "Note deleted" msgstr "笔记已删除" #. Translators: Button #: iotas/index.py:213 msgid "Undo" msgstr "撤消" #. Translators: Description, notification #: iotas/index.py:251 msgid "Sync conflict with note being edited" msgstr "同步与编辑中的笔记冲突" #. Translators: Description, notification #: iotas/index.py:258 msgid "The note being edited was remotely deleted" msgstr "该正被编辑的笔记已被远程删除" #. Translators: Description, notification. "Secret Service" and "gnome-keyring" should #. likely not be translated. #: iotas/index.py:266 msgid "" "Failure accessing Secret Service. Ensure you have a provider like gnome-" "keyring which has a default keyring setup that is unlocked." msgstr "" "访问保密服务失败。请确保您拥有部署了默认密钥串且已解锁的保密服务提供者如 " "gnome-keyring。" #. Another toast misuse replacing a revealer notification. Debug only at least. #. TODO in future look at replacing this with a (debug only) spinner. #. Translators: Description, notification #: iotas/index.py:500 msgid "Syncing" msgstr "正在同步" #. Translators: Description, notification, {} is a number #: iotas/index.py:519 msgid "{} change" msgid_plural "{} changes" msgstr[0] "{} 条更改" #. Translators: Description, notification #: iotas/index.py:535 msgid "Sync failure. Is the Nextcloud Notes app installed on the server?" msgstr "同步失败。确定服务器上安装了 Nextcloud 笔记应用吗?" #. Somewhat clunky misuse of toast to replace previous revealer notification #. Translators: Description, notification #: iotas/index.py:632 msgid "Loading" msgstr "正在加载" #. Translators: Title #: iotas/link_dialog.py:45 msgid "Insert Link" msgstr "插入链接" #. Translators: Title #: iotas/link_dialog.py:50 msgid "Edit Link" msgstr "编辑链接" #. Translators: Title #: iotas/nextcloud_login_dialog.py:110 msgid "Updating Notes" msgstr "正在更新笔记" #. Translators: Title #: iotas/nextcloud_login_dialog.py:114 msgid "Performing Initial Transfer" msgstr "正在执行初始传输" #. Translators: Title #: iotas/nextcloud_login_dialog.py:170 msgid "Connecting" msgstr "正在连接" #. Translators: Title #: iotas/nextcloud_login_dialog.py:192 msgid "Waiting for Login" msgstr "正在等待登录" #. Translators: Description #: iotas/nextcloud_login_dialog.py:194 msgid "Complete the authentication in your browser" msgstr "在您的浏览器中完成认证" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:210 msgid "Failed to start login with possible certificate issue" msgstr "由于可能存在证书问题而登录失败" #. Translators: Description, notification #: iotas/nextcloud_login_dialog.py:213 msgid "Failed to start login. Wrong address?" msgstr "登录失败。地址错误吗?" #. Translators: Description, a style name #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:71 iotas/preferences_dialog.py:103 msgid "Monochrome" msgstr "单色" #. Translators: Description, a style name #: iotas/preferences_dialog.py:73 msgid "Muted Markup" msgstr "减弱标记" #. Translators: Description, a style name #: iotas/preferences_dialog.py:75 msgid "Bold Markup" msgstr "粗体标记" #. Translators: Description, a style name #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:77 iotas/preferences_dialog.py:130 msgid "Disabled" msgstr "已禁用" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:105 msgid "Muted" msgstr "柔和" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:107 msgid "Blue" msgstr "蓝色" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:109 msgid "Orange" msgstr "橙色" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:111 msgid "Red" msgstr "红色" #. Translators: Description, a visual style (for category labels in index) #: iotas/preferences_dialog.py:113 msgid "None" msgstr "无" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:124 iotas/preferences_dialog.py:144 msgid "Always Visible" msgstr "总是可见" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:126 iotas/preferences_dialog.py:146 msgid "Automatically Hide" msgstr "自动隐藏" #. Translators: Description, for preference option - a description of visibility #: iotas/preferences_dialog.py:128 iotas/preferences_dialog.py:148 msgid "Auto Hide When Fullscreen" msgstr "全屏时自动隐藏" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:281 #, python-brace-format msgid "Reducing in {0} presses" msgstr "按 {0} 次减少" #. Translators: Description, notification, {0} is a number #: iotas/preferences_dialog.py:284 #, python-brace-format msgid "Extending in {0} presses" msgstr "按 {0} 次扩展" #. Translators: Description, notification #: iotas/preferences_dialog.py:289 msgid "Extended hidden" msgstr "扩展已隐藏" #. Translators: Description, notification #: iotas/preferences_dialog.py:292 msgid "Extended shown" msgstr "扩展已显示" #. Translators: Description, notification. Needs to be short for toast. #: iotas/preferences_dialog.py:321 msgid "Hiding discouraged on mobile" msgstr "已阻止在移动设备上隐藏" #. Translators: Title #: iotas/preferences_dialog.py:341 msgid "Reset Database?" msgstr "重置数据库吗?" #. Translators: Description #: iotas/preferences_dialog.py:343 msgid "All notes will be deleted. Continue with the reset?" msgstr "将删除所有笔记。继续重置吗?" #. Translators: Title #: iotas/preferences_dialog.py:366 msgid "Disconnect Nextcloud?" msgstr "断开 Nextcloud 连接吗?" #. Translators: Description #: iotas/preferences_dialog.py:368 msgid "All notes will be removed. Do you want to sign out?" msgstr "将移除所有笔记。您确定要登出吗?" #. Translators: Description, alert #: iotas/selection_header_bar.py:87 iotas/selection_header_bar.py:168 msgid "Unable to change category on read-only note" msgstr "无法更改只读笔记的分类" #. Translators: Description, {} is a number #: iotas/selection_header_bar.py:151 msgid "{} Selected" msgstr "已选 {} 项" #. Translators: Description, used as a prefix to the previous title for notes updated both #. locally and remotely. " - " is placed between this prefix and the title. #: iotas/sync_manager.py:585 msgid "SYNC CONFLICT" msgstr "同步冲突" #. Translators: Title #: iotas/ui_utils.py:90 msgid "Error" msgstr "错误" #~ msgid "Export As..." #~ msgstr "导出为…" #~ msgid "Exporting..." #~ msgstr "正在导出…" #~ msgid "OK" #~ msgstr "确定" #~ msgid "Disable" #~ msgstr "禁用" #~ msgid "Return to Index" #~ msgstr "返回首页" #~ msgid "Line length limit already disabled" #~ msgstr "行长度限制已经被禁用" #, python-brace-format #~ msgid "Font size now {0}pt" #~ msgstr "字体大小现在为 {0} 磅" #~ msgid "Read-Only Note" #~ msgstr "只读笔记" #~ msgid "Waiting for completion of login in browser" #~ msgstr "正在等待浏览器登录完成" #~ msgid "Syntax Theme" #~ msgstr "语法主题" #~ msgid "Finish" #~ msgstr "完成" #~ msgid "Auto Hide" #~ msgstr "自动隐藏" #~ msgid "" #~ "Why \"Iotas\"? An iota is a little bit and this app is designed for " #~ "jotting down little things on little devices. Iota stems from the same " #~ "Greek word as jot and is commonly used in negative statements eg. \"not " #~ "one iota of …\", but we think the word has more to give. Maybe somebody " #~ "will take note?" #~ msgstr "" #~ "为什么取名“Iotas”?Iota(希腊字母)的意思是微量且该应用设计为在小型设备上" #~ "对微小事务草记一二。Iota 来源于意思是少量的相同希腊词语且普遍用在否定句式" #~ "如“没有一点……”中,但我们认为这个词语可以给予更多。也许有人会注意到(记笔" #~ "记)?" #~ msgid "Let's get started" #~ msgstr "让我们开始吧" #~ msgid "Add new feeds via URL" #~ msgstr "通过网址添加新的订阅" #~ msgid "Import an OPML file" #~ msgstr "导入 OPML 文件" #~ msgid "Go back" #~ msgstr "返回" #~ msgid "Highlight Syntax" #~ msgstr "高亮语法" #~ msgid "Disable for slightly improved performance." #~ msgstr "禁用可略微提升性能。" #~ msgid "Editor with plain text" #~ msgstr "纯文本编辑器" #~ msgid "1 change" #~ msgstr "1 条更改" iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/pyproject.toml000066400000000000000000000020071507102636600233150ustar00rootroot00000000000000[project] requires-python = ">=3.11" [tool.black] line-length = 100 [tool.codespell] skip = '*.po,.git,_build,./third-party/katex/*,./build/*' check-filenames = true exclude-file = '.codespell_ignore_lines' [tool.ruff] line-length = 100 [tool.ruff.lint] extend-select = ["E501"] [tool.ruff.lint.per-file-ignores] "iotas/application.py" = ["E402"] "iotas/category_list_model.py" = ["E402"] "iotas/editor.py" = ["E402"] "iotas/editor_text_view.py" = ["E402"] "iotas/focus_mode_helper.py" = ["E402"] "iotas/markdown_render_view.py" = ["E402"] "iotas/nextcloud_sync_worker.py" = ["E402"] "iotas/preferences_dialog.py" = ["E402"] "iotas/text_utils.py" = ["E402"] "tests/test_exporter.py" = ["E402"] [tool.mypy] ignore_missing_imports = true follow_imports = "silent" python_version = "3.11" packages = "iotas,search-provider,tests" [tool.pytest.ini_options] filterwarnings = [ 'ignore:.*was imported without specifying a version first.*:Warning', ] testpaths = [ "tests", ] pythonpath = [ ".", "./third-party", ] iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/requirements.txt000066400000000000000000000001311507102636600236610ustar00rootroot00000000000000pygtkspellcheck requests markdown-it-py linkify-it-py mdit-py-plugins pypandoc packaging iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/search-provider/000077500000000000000000000000001507102636600234775ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/search-provider/.flake8000066400000000000000000000001631507102636600246520ustar00rootroot00000000000000[flake8] max-line-length = 100 extend-ignore = # See https://github.com/PyCQA/pycodestyle/issues/373 E203, iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/search-provider/iotas-search-provider.py.in000077500000000000000000000206601507102636600306770ustar00rootroot00000000000000#!@PYTHON@ import gi gi.require_version("Gdk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gdk, Gio, GLib import logging import iotas.const as const from iotas.database import Database, DbCursor from iotas.note_database import NoteDatabase class Server: def __init__(self, conn: Gio.DBusConnection, node_info:str, path: str): logging.basicConfig( format="%(asctime)s | %(module)s | %(levelname)s | %(message)s", datefmt="%H:%M:%S", level=logging.INFO, ) out_args = {} in_args = {} for interface in Gio.DBusNodeInfo.new_for_xml(node_info).interfaces: for method in interface.methods: out_args[method.name] = ( "(" + "".join([arg.signature for arg in method.out_args]) + ")" ) in_args[method.name] = tuple(arg.signature for arg in method.in_args) conn.register_object( object_path=path, interface_info=interface, method_call_closure=self.__on_method_call, ) self.__method_in_args = in_args self.__method_out_args = out_args def __on_method_call( self, _conn: Gio.DBusConnection, _sender: str, _object_path: str, _interface_name: str, method_name: str, parameters: GLib.Variant, invocation: Gio.DBusMethodInvocation, ): args = list(parameters.unpack()) for i, sig in enumerate(self.__method_in_args[method_name]): if sig == "h": msg = invocation.get_message() fd_list = msg.get_unix_fd_list() args[i] = fd_list.get(args[i]) try: result = getattr(self, method_name)(*args) # out_args is at least (signature1). # We therefore always wrap the result as a tuple. # Refer to https://bugzilla.gnome.org/show_bug.cgi?id=765603 result = (result,) out_args = self.__method_out_args[method_name] if out_args != "()": variant = GLib.Variant(out_args, result) invocation.return_value(variant) else: invocation.return_value(None) except Exception as e: logging.warning(f"__on_method_call: {e}") class SearchIotasService(Server, Gio.Application): DBUS_NODE_INFO = """ """ SEARCH_BUS = "org.gnome.Shell.SearchProvider2" PATH_BUS = "/org/gnome/World/IotasSearchProvider" MAX_SUBSEARCH_LIST_LENGTH = 999 def __init__(self): Gio.Application.__init__( self, application_id="org.gnome.World.Iotas.SearchProvider", flags=Gio.ApplicationFlags.IS_SERVICE, inactivity_timeout=10000, ) self.cursors: dict[str, DbCursor] = {} self.__db_base = Database() self.__db = NoteDatabase(self.__db_base) self.__bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) Gio.bus_own_name_on_connection( self.__bus, self.SEARCH_BUS, Gio.BusNameOwnerFlags.NONE, None, None ) Server.__init__(self, self.__bus, self.DBUS_NODE_INFO, self.PATH_BUS) def ActivateResult(self, search_id: str, _terms: list[str], timestamp: int) -> None: """Activate individual search result. :param str search_id: The note id :param list[str] _terms: The search terms :param int timestamp: Search timestamp """ self.hold() launch_context = Gdk.Display.get_app_launch_context(Gdk.Display.get_default()) launch_context.set_timestamp(timestamp) app = Gio.AppInfo.create_from_commandline( f"iotas --open-note {search_id}", const.APP_ID, Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION, ) if not app: logging.error("Failed to create AppInfo") elif not app.launch(None, launch_context): logging.error("Failed to launch") self.release() def GetInitialResultSet(self, terms: list[str]) -> list[str]: """Search for initial results. :param list[str] terms: The search terms :return: A list of note ids :rtype: list[str] """ self.hold() results = [] try: results = self.__search(terms) except Exception as e: logging.warning(f"GetInitialResultSet: {e}") self.release() return results def GetResultMetas(self, ids: list[str]) -> list[dict]: """Fetch metadata for provided note ids. :param list[str] ids: Note ids :return: List of metadata for provided notes :rtype: list[dict] """ self.hold() results = [] gicon = Gio.ThemedIcon.new("text-x-generic").to_string() try: notes = self.__db.get_notes_by_ids([int(x) for x in ids]) for note in notes: name = note.title description = note.excerpt d = { "id": GLib.Variant("s", str(note.id)), "description": GLib.Variant("s", GLib.markup_escape_text(description)), "name": GLib.Variant("s", name), "gicon": GLib.Variant("s", gicon), } results.append(d) except Exception as e: logging.warning(f"GetResultMetas: {e}") self.release() return results def GetSubsearchResultSet(self, previous_results: list[str], new_terms: list[str]) -> list[str]: """Search refining results :param list[str] previous_results: Note ids from parent set :param list[str] new_terms: The search terms :return: A list of note ids :rtype: list[str] """ self.hold() results = [] try: if len(previous_results) < self.MAX_SUBSEARCH_LIST_LENGTH: ids = [int(x) for x in previous_results] else: ids = [] results = self.__search(new_terms, ids) except Exception as e: logging.warning(f"GetSubsearchResultSet: {e}") self.release() return results def LaunchSearch(self, terms: list[str], timestamp: int) -> None: """Search in app for the provided terms. :param list[str] terms: The search terms :param int timestamp: Search timestamp """ self.hold() launch_context = Gdk.Display.get_app_launch_context(Gdk.Display.get_default()) launch_context.set_timestamp(timestamp) search_text = " ".join(terms) app = Gio.AppInfo.create_from_commandline( f'iotas --search "{search_text}"', const.APP_ID, Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION, ) if not app: logging.error("Failed to create AppInfo") elif not app.launch(None, launch_context): logging.error("Failed to launch") self.release() def __search(self, terms: list[str], previous_results: list[int] = []) -> list[str]: search_text = " ".join(terms) return [str(x) for x in self.__db.search_notes(search_text, previous_results, True)] def main(): service = SearchIotasService() service.run() if __name__ == "__main__": main() iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/search-provider/meson.build000066400000000000000000000014241507102636600256420ustar00rootroot00000000000000service_dir = join_paths(get_option('datadir'), 'dbus-1', 'services') search_provider_dir = join_paths(get_option('datadir'), 'gnome-shell', 'search-providers') conf = configuration_data() conf.set('LIBEXEC_DIR', LIBEXEC_DIR) conf.set('PYTHON', python_bin.full_path()) conf.set('APPID', application_id) configure_file( input: 'iotas-search-provider.py.in', output: 'iotas-search-provider', configuration: conf, install_dir: LIBEXEC_DIR ) configure_file( input: project_id + '.SearchProvider.service.in', output: project_id + '.SearchProvider.service', configuration: conf, install_dir: service_dir ) configure_file( input: project_id + '.SearchProvider.ini.in', output: project_id + '.SearchProvider.ini', configuration: conf, install_dir: search_provider_dir ) org.gnome.World.Iotas.SearchProvider.ini.in000066400000000000000000000002311507102636600335000ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/search-provider[Shell Search Provider] DesktopId=@APPID@.desktop BusName=org.gnome.World.Iotas.SearchProvider ObjectPath=/org/gnome/World/IotasSearchProvider Version=2 org.gnome.World.Iotas.SearchProvider.service.in000066400000000000000000000001431507102636600343630ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/search-provider[D-BUS Service] Name=org.gnome.World.Iotas.SearchProvider Exec=@LIBEXEC_DIR@/iotas-search-provider iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/tests/000077500000000000000000000000001507102636600215445ustar00rootroot00000000000000iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/tests/meson.build000066400000000000000000000004241507102636600237060ustar00rootroot00000000000000envdata = environment() python_paths = [join_paths(meson.project_source_root(), 'third-party')] envdata.append('PYTHONPATH', python_paths) test('iotas-test-suite', python_bin, args: ['-m', 'pytest'], workdir: meson.project_source_root(), env: envdata, timeout: 90) iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/tests/test_attachment.py000066400000000000000000000016231507102636600253070ustar00rootroot00000000000000import unittest import warnings from iotas.attachment import Attachment warnings.filterwarnings("ignore", "version") class Test(unittest.TestCase): def test_duplicate(self) -> None: attachment = Attachment() attachment.note_id = 1 attachment.note_remote_id = 2 attachment.path = "image.png" dupe = attachment.duplicate() self.assertIsNotNone(dupe) self.assertEqual(dupe.note_id, 1) self.assertEqual(dupe.note_remote_id, 2) self.assertEqual(dupe.path, "image.png") def test_filename(self) -> None: attachment = Attachment() attachment.path = "dir/subdir/image.png" self.assertEqual(attachment.filename, "image.png") def test_path_quoted(self) -> None: attachment = Attachment() attachment.path = "image (1).png" self.assertEqual(attachment.path_quoted, "image%20%281%29.png") iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/tests/test_attachment_helpers.py000066400000000000000000000240771507102636600270410ustar00rootroot00000000000000import os import shutil import unittest import warnings from iotas.attachment import Attachment from iotas.attachment_helpers import ( copy_note_attachments, write_attachment_to_disk, get_attachments_on_disk_for_note, delete_attachments_for_note, get_attachment_disk_states, get_attachment_filesystem_uri, get_attachment_filesystem_path, attachment_exists_locally, get_attachment_file_object, flush_all_attachments_on_disk, set_attachment_filesystem_uris_on_tokens, trim_orphaned_images, AttachmentsCopyOutcome, ) from iotas.markdown_helpers import ( filter_image_tokens, parse_to_tokens, ) from iotas.note import Note import iotas.attachment_helpers def get_attachments_dir() -> str: file_dir = os.path.dirname(__file__) return os.path.join(file_dir, os.pardir, "testing-tmp", "user-attachments") iotas.attachment_helpers.get_attachments_dir = get_attachments_dir warnings.filterwarnings("ignore", "version") class Test(unittest.TestCase): def test_copy_note_attachments(self) -> None: self.__prepare_output_dir() note = Note() note.id = 1 note.content = "![](image.png)\n\n![](image2.png)\n\n![](image2.png)" path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "1.image2.png") self.assertTrue(self.__create_empty_file(path)) out_dir = os.path.join(get_attachments_dir(), "copy-test") def refresh_out_dir(): if os.path.exists(out_dir): shutil.rmtree(out_dir) os.makedirs(out_dir) refresh_out_dir() results = copy_note_attachments(note, out_dir, prefix_note_id=True) self.assertEqual(results.outcome, AttachmentsCopyOutcome.SUCCESS) self.assertEqual(len(os.listdir(out_dir)), 2) refresh_out_dir() note.content = "![](image.png)\n\n![](image2.png)\n\n![](image3.png)" results = copy_note_attachments(note, out_dir, prefix_note_id=True) self.assertEqual(results.outcome, AttachmentsCopyOutcome.HAD_MISSING) self.assertEqual(len(os.listdir(out_dir)), 2) refresh_out_dir() note.content = "[](image.png)" results = copy_note_attachments(note, out_dir, prefix_note_id=True) self.assertEqual(results.outcome, AttachmentsCopyOutcome.NONE) self.assertEqual(len(os.listdir(out_dir)), 0) self.__clean_output_dir() def test_write_attachment_to_disk(self) -> None: self.__prepare_output_dir() attachment = Attachment() attachment.note_id = 1 attachment.path = "image.png" success = write_attachment_to_disk(attachment, b"bytes") self.assertTrue(success) path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(os.path.exists(path)) with open(path, "rb") as f: out = f.read() self.assertEqual(out, b"bytes") self.__clean_output_dir() def test_get_attachments_on_disk_for_note(self) -> None: self.__prepare_output_dir() note = Note() note.id = 1 self.assertEqual(len(get_attachments_on_disk_for_note(note)), 0) path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "1.image2.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "2.image.png") self.assertTrue(self.__create_empty_file(path)) out = get_attachments_on_disk_for_note(note) self.assertEqual(len(out), 2) out_paths = {a.path for a in out} self.assertEqual(out_paths, {"image.png", "image2.png"}) self.__clean_output_dir() def test_delete_attachments_for_note(self) -> None: self.__prepare_output_dir() note = Note() note.id = 1 self.assertEqual(len(get_attachments_on_disk_for_note(note)), 0) path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "1.image2.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "2.image.png") self.assertTrue(self.__create_empty_file(path)) delete_attachments_for_note(note) remaining = os.listdir(get_attachments_dir()) self.assertEqual(len(remaining), 1) self.assertEqual(remaining[0], "2.image.png") self.__clean_output_dir() def test_get_attachment_disk_states(self) -> None: self.__prepare_output_dir() note = Note() note.id = 1 note.content = "![](image.png)\n\n![](image2.png)\n\n![](image2.png)\n\n![](image3.png)" path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "1.image2.png") self.assertTrue(self.__create_empty_file(path)) _parser, tokens = parse_to_tokens(note, exporting=False, tex_support=False) states = get_attachment_disk_states(note, tokens) self.assertEqual(len(states.exists), 2) self.assertTrue("image.png" in states.exists) self.assertTrue("image2.png" in states.exists) self.assertEqual(len(states.missing), 1) self.assertTrue("image3.png" in states.missing) self.__clean_output_dir() def test_get_attachment_filesystem_uri(self) -> None: attachment = Attachment() attachment.note_id = 1 attachment.path = "image.png" uri = get_attachment_filesystem_uri(attachment) expected = os.path.join(get_attachments_dir(), "1.image.png") self.assertEqual(uri, f"file://{expected}") def test_get_attachment_filesystem_path(self) -> None: attachment = Attachment() attachment.note_id = 1 attachment.path = "image.png" uri = get_attachment_filesystem_path(attachment) expected = os.path.join(get_attachments_dir(), "1.image.png") self.assertEqual(uri, expected) def test_attachment_exists_locally(self) -> None: attachment = Attachment() attachment.note_id = 1 attachment.path = "image.png" self.assertFalse(attachment_exists_locally(attachment)) self.__prepare_output_dir() path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(self.__create_empty_file(path)) self.assertTrue(attachment_exists_locally(attachment)) self.__clean_output_dir() def test_get_attachment_file_object(self) -> None: attachment = Attachment() attachment.note_id = 1 attachment.path = "image.png" self.__prepare_output_dir() path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(self.__create_empty_file(path)) obj = get_attachment_file_object(attachment) self.assertIsNotNone(obj) if obj is not None: # mypy self.assertEqual(obj.read(), b"") self.__clean_output_dir() def test_flush_all_attachments_on_disk(self) -> None: self.__prepare_output_dir() path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "1.image2.png") self.assertTrue(self.__create_empty_file(path)) flush_all_attachments_on_disk() self.assertEqual(len(os.listdir(get_attachments_dir())), 0) self.__clean_output_dir() def test_set_attachment_filesystem_uris_to_tokens(self) -> None: note = Note() note.id = 1 note.content = "![](image.png)\n\n![](image2.png)\n\n![](image2.png)" _parser, tokens = parse_to_tokens(note, exporting=False, tex_support=False) attachment1 = Attachment() attachment1.note_id = 1 attachment1.path = "image.png" attachment2 = Attachment() attachment2.note_id = 1 attachment2.path = "image2.png" new_paths = { "image.png": attachment1, "image2.png": attachment2, } set_attachment_filesystem_uris_on_tokens(tokens, new_paths) image_tokens = filter_image_tokens(tokens) self.assertEqual(len(image_tokens), 3) dirpath = f"file://{os.path.join(get_attachments_dir())}/" path = dirpath + "1.image.png" self.assertEqual(image_tokens[0].attrs["src"], path) path = dirpath + "1.image2.png" self.assertEqual(image_tokens[1].attrs["src"], path) self.assertEqual(image_tokens[2].attrs["src"], path) def test_trim_orphaned_images(self) -> None: self.__prepare_output_dir() path = os.path.join(get_attachments_dir(), "1.image.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "1.orphan1.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "1.orphan2.png") self.assertTrue(self.__create_empty_file(path)) path = os.path.join(get_attachments_dir(), "2.image.png") self.assertTrue(self.__create_empty_file(path)) self.assertEqual(len(os.listdir(get_attachments_dir())), 4) note = Note() note.id = 1 note.content = "![description](image.png)" trim_orphaned_images(note, on_thread=False) self.assertEqual(len(os.listdir(get_attachments_dir())), 2) def __prepare_output_dir(self) -> str: out_path = get_attachments_dir() if os.path.exists(out_path): shutil.rmtree(out_path) os.makedirs(out_path) return out_path def __clean_output_dir(self) -> None: out_path = get_attachments_dir() if os.path.exists(out_path): shutil.rmtree(out_path) def __create_empty_file(self, path: str) -> bool: try: with open(path, "w") as f: f.write("") except OSError: return False else: return True iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/tests/test_backup_manager.py000066400000000000000000000233231507102636600261170ustar00rootroot00000000000000import json import os import shutil import time from typing import Optional import unittest import warnings from iotas.backup_manager import BackupManager from iotas.backup_storage import BackupStorage from iotas.note import Note, DirtyFields warnings.filterwarnings("ignore", "version") class _MockStorage(BackupStorage): notes: list[Note] = [] def add_note(self, note: Note) -> None: """Add a new note to the database. :param Note note: Note to add """ self.notes.append(note) def get_all_notes_count(self, include_locally_deleted: bool = True) -> int: """Fetch the number of notes in the database. :param bool include_locally_deleted: Whether to include locally deleted notes in the count :return: The count :rtype: int """ return len(self.notes) def get_all_notes(self, load_content: bool = False) -> list[Note]: """Fetch all notes from the database. :param bool load_content: Whether to load the content for each note :return: List of notes :rtype: list[Note] """ return self.notes[:] def get_note_by_remote_id(self, remote_id: int) -> Optional[Note]: """Fetch note from the database by remote id. :param int remote_id: Remote id of the note :return: The note, or None :rtype: Optional[Note] """ result = None for note in self.notes: if note.remote_id == remote_id: result = note break return result def get_note_by_title(self, title: str) -> Optional[Note]: """Fetch note from the database by title. :param str title: Search title :return: The note, or None :rtype: Optional[Note] """ result = None for note in self.notes: if note.title == title: result = note break return result def persist_note_selective(self, note: Note, updated_fields: DirtyFields) -> None: """Persist local note based on remote changes. :param Note note: The note to update :param DirtyFields updated_fields: Which fields to update """ # Not implementing for unit test due to backup merging being disabled raise NotImplementedError() def create_duplicate_note(self, note: Note, reason: str) -> Note: """Create a duplicate note with a prefixed title. :param Note note: The note to duplicate :param str reason: The reason for the duplication, which is prefixed on the title """ # Not implementing for unit test due to backup merging being disabled raise NotImplementedError() def flush(self) -> None: self.notes = [] class Test(unittest.TestCase): BACKUPS_SUBPATH = "backup" mock_storage = _MockStorage() def test_create_backup(self) -> None: self.__reset() backups_dir = os.path.join(self.__get_output_dir(), self.BACKUPS_SUBPATH) note1 = Note(new_note=True) note1.content = "content" note1.title = "Test Note Title" self.mock_storage.add_note(note1) note2 = Note(new_note=True) note2.content = "second content" note2.title = "Second Note Title" self.mock_storage.add_note(note2) result = self.manager.create_backup(sync_configured=False, file_extension="md") self.assertTrue(result) files = os.listdir(backups_dir) self.assertEqual(len(files), 4) self.assertTrue(f"{note1.title}.md" in files) self.assertTrue(f"{note1.title}.md.iota" in files) self.assertTrue(f"{note2.title}.md" in files) self.assertTrue(f"{note2.title}.md.iota" in files) with open(os.path.join(backups_dir, f"{note1.title}.md"), "r") as f: self.assertEqual(note1.content, f.read()) with open(os.path.join(backups_dir, f"{note1.title}.md.iota"), "r") as f: meta_dict = json.loads(f.read()) self.assertEqual(meta_dict["SchemaVersion"], "1.0") self.assertEqual(meta_dict["IotasVersion"], "0.0") self.assertEqual(meta_dict["Title"], note1.title) self.assertEqual(meta_dict["Category"], note1.category) self.assertEqual(meta_dict["LastModified"], note1.last_modified) self.assertEqual(meta_dict["Favourite"], note1.favourite) self.assertEqual(meta_dict["Dirty"], note1.dirty) self.assertEqual(meta_dict["LocallyDeleted"], note1.locally_deleted) self.assertEqual(meta_dict["RemoteId"], note1.remote_id) self.assertEqual(meta_dict["ETag"], note1.etag) self.__reset() note = Note(new_note=True) note.content = "content" note.title = "Test Note Title" note.category = "category" note.last_modified = int(time.time()) note.favourite = True note.dirty = True note.locally_deleted = True note.remote_id = 13 note.etag = "etag" self.mock_storage.add_note(note) result = self.manager.create_backup(sync_configured=False, file_extension="md") self.assertTrue(result) file_path = os.path.join(backups_dir, f"{note.title}.md.iota") self.assertTrue(os.path.exists(file_path)) with open(file_path, "r") as f: meta_dict = json.loads(f.read()) self.assertEqual(meta_dict["SchemaVersion"], "1.0") self.assertEqual(meta_dict["IotasVersion"], "0.0") self.assertEqual(meta_dict["Title"], note.title) self.assertEqual(meta_dict["Category"], note.category) self.assertEqual(meta_dict["LastModified"], note.last_modified) self.assertEqual(meta_dict["Favourite"], note.favourite) self.assertEqual(meta_dict["Dirty"], note.dirty) self.assertEqual(meta_dict["LocallyDeleted"], note.locally_deleted) self.assertEqual(meta_dict["RemoteId"], note.remote_id) self.assertEqual(meta_dict["ETag"], note.etag) self.__clean_output_dir() def test_restore_backup(self) -> None: self.__reset() backups_dir = os.path.join(self.__get_output_dir(), self.BACKUPS_SUBPATH) os.makedirs(backups_dir) with open(os.path.join(backups_dir, "Title.md"), "w") as f: f.write("content") with open(os.path.join(backups_dir, "Title.md.iota"), "w") as f: f.write( """{ "SchemaVersion": "1.0", "IotasVersion": "0.0", "Title": "Title", "Category": "", "LastModified": 0, "Favourite": false, "Dirty": false, "LocallyDeleted": false, "RemoteId": -1, "ETag": "" }""" ) with open(os.path.join(backups_dir, "Second Title.md"), "w") as f: f.write("second content") with open(os.path.join(backups_dir, "Second Title.md.iota"), "w") as f: f.write( """{ "SchemaVersion": "1.0", "IotasVersion": "0.0", "Title": "Second Title", "Category": "category", "LastModified": 1745975049, "Favourite": true, "Dirty": true, "LocallyDeleted": true, "RemoteId": 13, "ETag": "etag" }""" ) result = self.manager.restore_backup(sync_configured=False) self.assertTrue(result) self.assertEqual(self.mock_storage.get_all_notes_count(True), 2) note = self.mock_storage.get_note_by_title("Title") self.assertIsNotNone(note) assert note # mypy self.assertEqual(note.title, "Title") self.assertEqual(note.content, "content") self.assertEqual(note.category, "") self.assertEqual(note.last_modified, 0) self.assertEqual(note.favourite, False) self.assertEqual(note.dirty, False) self.assertEqual(note.locally_deleted, False) self.assertEqual(note.remote_id, -1) self.assertEqual(note.etag, "") note = self.mock_storage.get_note_by_title("Second Title") self.assertIsNotNone(note) assert note # mypy self.assertEqual(note.title, "Second Title") self.assertEqual(note.content, "second content") self.assertEqual(note.category, "category") self.assertEqual(note.last_modified, 1745975049) self.assertEqual(note.favourite, True) self.assertEqual(note.dirty, True) self.assertEqual(note.locally_deleted, True) # Not populated during restore self.assertEqual(note.remote_id, -1) self.assertEqual(note.etag, "") result = self.manager.restore_backup(sync_configured=False) self.assertFalse(result) self.__clean_output_dir() def __reset(self) -> BackupManager: self.mock_storage.flush() self.__prepare_output_dir() file_dir = os.path.dirname(__file__) storage_dir = os.path.join(file_dir, os.pardir, "testing-tmp") self.manager = BackupManager( self.mock_storage, iotas_version="0.0", storage_dir=storage_dir, ) return self.manager def __prepare_output_dir(self) -> str: out_path = self.__get_output_dir() if os.path.exists(out_path): shutil.rmtree(out_path) os.makedirs(out_path) return out_path def __clean_output_dir(self) -> None: out_path = self.__get_output_dir() if os.path.exists(out_path): shutil.rmtree(out_path) def __get_output_dir(self) -> str: file_dir = os.path.dirname(__file__) return os.path.join(file_dir, os.pardir, "testing-tmp") iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/tests/test_exporter.py000066400000000000000000000232631507102636600250330ustar00rootroot00000000000000from datetime import datetime import os import shutil from typing import Callable, Optional import unittest import warnings from markdown_it.token import Token from markdown_it.utils import EnvType, OptionsDict import pypandoc from iotas.attachment import Attachment from iotas.attachment_helpers import ( write_attachment_to_disk, ) from iotas.exporter import Exporter from iotas.html_generator import HtmlGenerator from iotas.note import Note from iotas.pdf_exporter import PdfExporter def get_output_dir() -> str: file_dir = os.path.dirname(__file__) return os.path.join(file_dir, os.pardir, "testing-tmp") def get_attachments_dir() -> str: return os.path.join(get_output_dir(), "user-attachments") import iotas.attachment_helpers iotas.attachment_helpers.get_attachments_dir = get_attachments_dir warnings.filterwarnings("ignore", "version") class _MockPdfExporter(PdfExporter): note: Note location: str def set_callbacks(self, finished_callback: Callable, error_callback: Callable) -> None: """Set functions to be called upon export result. :param Callable finished_callback: Finished callback :param Callable error_callback: Error callback """ pass def export(self, note: Note, location: str) -> None: """Export PDF of note. :param Note note: Note to export :param str location: Destination location """ self.note = note self.location = location class MockHtmlGenerator(HtmlGenerator): """HTML generator mocked.""" def generate( self, note: Note, tokens: list[Token], render_func: Callable[[list[Token], OptionsDict, EnvType], str], parser_options: OptionsDict, searching: bool, export_format: Optional[str], scroll_position: Optional[float] = None, ) -> str: """Generator HTML for note. :param Note note: Note to render :param list[Token] tokens: Parser tokens :param Callable[[list[Token], OptionsDict, EnvType], str] render_fun: Render function :param OptionsDict parser_options: Parser options :param bool searching: Whether search CSS should be included :param Optional[str] export_format: Export format, if using :param Optional[float] scroll_position: Position to scroll to :return: Generated HTML :rtype: str """ return self.get_output(note) def generate_user_stylesheet(self, searching: bool) -> str: """Generate part of stylesheet based on state (configuration etc). :param bool searching: Whether searching :return: stylesheet :rtype: str """ return "" def update_font_family(self, family: str) -> None: """Update the font family. :param str family: New font family """ pass def get_output(self, note: Note) -> str: """Get the mocked output. :param Note note: The note :return: Generated content: :rtype: str """ return f"{note.title}|{note.content}" class Test(unittest.TestCase): exporter: Exporter pdf_exporter: _MockPdfExporter def test_export_md_attachments(self) -> None: exporter = self.__reset() note = Note(new_note=True) note.id = 1 note.content = "![](image.png)" note.title = "Test Note Title" out_path = self.__prepare_output_dir() self.__create_attachment(note, "image.png") dir_path = os.path.join(out_path, "Test Note Title") file_path = os.path.join(dir_path, "Test Note Title.md") exporter.export( note, out_format="md", file_extension="md", supporting_tex=False, allow_missing_images=False, user_location=dir_path, ) self.assertTrue(os.path.exists(file_path)) with open(file_path, "r") as f: contents = f.read() self.assertEqual(contents, "![](attachments/image.png)") attachment_path = os.path.join(dir_path, "attachments", "image.png") self.assertTrue(os.path.exists(attachment_path)) self.__clean_output_dir() def test_export_md_no_attachments(self) -> None: exporter = self.__reset() note = Note(new_note=True) note.id = 1 note.content = "content" note.title = "Test Note Title" out_path = self.__prepare_output_dir() file_path = os.path.join(out_path, "Test Note Title.md") exporter.export( note, out_format="md", file_extension="md", supporting_tex=False, allow_missing_images=False, user_location=file_path, ) self.assertTrue(os.path.exists(file_path)) with open(file_path, "r") as f: contents = f.read() self.assertEqual(contents, note.content) self.__clean_output_dir() def test_export_mock_html(self) -> None: exporter = self.__reset() note = Note(new_note=True) note.id = 1 note.content = "content\n\n![](image.png)" note.title = "Test Note Title" out_path = self.__prepare_output_dir() self.__create_attachment(note, "image.png") dir_path = os.path.join(out_path, "Test Note Title") exporter.export( note, out_format="html", file_extension="html", supporting_tex=False, allow_missing_images=False, user_location=dir_path, ) index_path = os.path.join(dir_path, "index.html") self.assertTrue(os.path.exists(index_path)) with open(index_path, "r") as f: contents = f.read() self.assertTrue(f"{note.content}" in contents) self.assertTrue(f"{note.title}" in contents) attachment_path = os.path.join(dir_path, "attachments", "image.png") self.assertTrue(os.path.exists(attachment_path)) self.__clean_output_dir() def test_mock_export_pdf(self) -> None: exporter = self.__reset() note = Note(new_note=True) note.content = "content" note.title = "Test Note Title" out_path = self.__prepare_output_dir() file_path = os.path.join(out_path, "Test Note Title.pdf") exporter.export( note, out_format="pdf", file_extension="pdf", supporting_tex=False, allow_missing_images=False, user_location=file_path, ) self.assertEqual(self.pdf_exporter.note, note) self.assertEqual(self.pdf_exporter.location, file_path) self.__clean_output_dir() def test_export_odt(self) -> None: exporter = self.__reset() note = Note(new_note=True) note.content = "content" note.title = "Test Note Title" out_path = self.__prepare_output_dir() file_path = os.path.join(out_path, "Test Note Title.odt") exporter.export( note, out_format="odt", file_extension="odt", supporting_tex=False, user_location=file_path, ) self.assertTrue(os.path.exists(file_path)) with open(file_path, "rb") as f: contents = f.read() md = pypandoc.convert_text(contents, to="md", format="odt") self.assertTrue(note.content == md.strip()) self.__clean_output_dir() def test_build_default_filename(self) -> None: exporter = self.__reset() note = Note(new_note=True) note.content = "content" note.title = "Test Note Title" filename = exporter.build_default_filename( note, out_format="md", file_extension="md", add_timestamp=False ) self.assertEqual(filename, "Test Note Title.md") filename = exporter.build_default_filename( note, out_format="odt", file_extension="odt", add_timestamp=False ) self.assertEqual(filename, "Test Note Title.odt") filename = exporter.build_default_filename( note, out_format="pdf", file_extension="pdf", add_timestamp=False ) self.assertEqual(filename, "Test Note Title.pdf") filename = exporter.build_default_filename( note, out_format="html", file_extension="html", add_timestamp=False ) self.assertEqual(filename, "Test Note Title") filename = exporter.build_default_filename( note, out_format="md", file_extension="md", add_timestamp=True ) parts = filename.split(" ") self.assertEqual(len(parts), 4) timestamp = None try: timestamp = datetime.strptime(parts[0], "%Y-%m-%dT%H:%M:%S") except ValueError: pass self.assertIsNotNone(timestamp) self.assertEqual(" ".join(parts[1:]), "Test Note Title.md") def __reset(self) -> Exporter: self.pdf_exporter = _MockPdfExporter() html_generator = MockHtmlGenerator() data_path = "/mock/data/path" self.exporter = Exporter(self.pdf_exporter, html_generator, data_path) return self.exporter def __prepare_output_dir(self) -> str: out_path = get_output_dir() if os.path.exists(out_path): shutil.rmtree(out_path) os.makedirs(out_path) return out_path def __clean_output_dir(self) -> None: out_path = get_output_dir() if os.path.exists(out_path): shutil.rmtree(out_path) def __create_attachment(self, note: Note, path: str) -> bool: os.makedirs(get_attachments_dir()) attachment = Attachment() attachment.note_id = note.id attachment.path = path return write_attachment_to_disk(attachment, b"bytes") iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/tests/test_formatter.py000066400000000000000000000675351507102636600252000ustar00rootroot00000000000000import os from typing import Callable import unittest import warnings from gi.repository import GLib, Gtk, GtkSource from iotas.formatter import Formatter, LinkStateInfo warnings.filterwarnings("ignore", "version") class Test(unittest.TestCase): formatter: Formatter buffer: GtkSource.Buffer awaiting_signal = False def test_bold(self) -> None: # Markup around cursor formatter, buffer = self.__reset() self.__call_and_wait(formatter.bold) self.assertEqual(self.__get_text(), "****") centre = buffer.get_iter_at_offset(2) buffer.place_cursor(centre) formatter.bold() self.assertEqual(self.__get_text(), "") # Markup around selection formatter, buffer = self.__reset() start_iter = buffer.get_start_iter() buffer.insert(start_iter, "text") buffer.select_range(buffer.get_start_iter(), start_iter) self.__call_and_wait(formatter.bold) self.assertEqual(self.__get_text(), "**text**") self.__call_and_wait(formatter.bold) self.assertEqual(self.__get_text(), "text") Gtk.TextBuffer.select_range # Removing markup when cursor within bold buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.bold) self.assertEqual(self.__get_text(), "**text**") buffer.place_cursor(buffer.get_iter_at_offset(4)) self.__call_and_wait(formatter.bold) self.assertEqual(self.__get_text(), "text") # Multi-line selection ignored (uses selection start as cursor instead) formatter, buffer = self.__reset() start_iter = buffer.get_start_iter() buffer.insert(start_iter, "line\nline\nline\nline") buffer.select_range(buffer.get_start_iter(), buffer.get_iter_at_offset(15)) self.__call_and_wait(formatter.bold) self.assertEqual(self.__get_text(), "****line\nline\nline\nline") def test_italic(self) -> None: # Markup around cursor formatter, buffer = self.__reset() self.__call_and_wait(formatter.italic) self.assertEqual(self.__get_text(), "__") centre = buffer.get_iter_at_offset(1) buffer.place_cursor(centre) formatter.italic() self.assertEqual(self.__get_text(), "") # Markup around selection formatter, buffer = self.__reset() start_iter = buffer.get_start_iter() buffer.insert(start_iter, "text") buffer.select_range(buffer.get_start_iter(), start_iter) self.__call_and_wait(formatter.italic) self.assertEqual(self.__get_text(), "_text_") self.__call_and_wait(formatter.italic) self.assertEqual(self.__get_text(), "text") Gtk.TextBuffer.select_range # Removing markup when cursor within italic buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.italic) self.assertEqual(self.__get_text(), "_text_") buffer.place_cursor(buffer.get_iter_at_offset(3)) self.__call_and_wait(formatter.italic) self.assertEqual(self.__get_text(), "text") # Multi-line selection ignored (uses selection start as cursor instead) formatter, buffer = self.__reset() start_iter = buffer.get_start_iter() buffer.insert(start_iter, "line\nline\nline\nline") buffer.select_range(buffer.get_start_iter(), buffer.get_iter_at_offset(15)) self.__call_and_wait(formatter.italic) self.assertEqual(self.__get_text(), "__line\nline\nline\nline") def test_strikethrough(self) -> None: # Markup around cursor formatter, buffer = self.__reset() self.__call_and_wait(formatter.strikethrough) self.assertEqual(self.__get_text(), "~~~~") centre = buffer.get_iter_at_offset(2) buffer.place_cursor(centre) formatter.strikethrough() self.assertEqual(self.__get_text(), "") # Markup around selection formatter, buffer = self.__reset() start_iter = buffer.get_start_iter() buffer.insert(start_iter, "text") buffer.select_range(buffer.get_start_iter(), start_iter) self.__call_and_wait(formatter.strikethrough) self.assertEqual(self.__get_text(), "~~text~~") self.__call_and_wait(formatter.strikethrough) self.assertEqual(self.__get_text(), "text") Gtk.TextBuffer.select_range # Removing markup when cursor within strikethrough buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.strikethrough) self.assertEqual(self.__get_text(), "~~text~~") buffer.place_cursor(buffer.get_iter_at_offset(4)) self.__call_and_wait(formatter.strikethrough) self.assertEqual(self.__get_text(), "text") # Multi-line selection ignored (uses selection start as cursor instead) formatter, buffer = self.__reset() start_iter = buffer.get_start_iter() buffer.insert(start_iter, "line\nline\nline\nline") buffer.select_range(buffer.get_start_iter(), buffer.get_iter_at_offset(15)) self.__call_and_wait(formatter.strikethrough) self.assertEqual(self.__get_text(), "~~~~line\nline\nline\nline") def test_quote(self) -> None: formatter, buffer = self.__reset() self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "> ") formatter.quote() self.assertEqual(self.__get_text(), "") # Cursor location and selection not making a difference buffer.insert(buffer.get_start_iter(), "text") buffer.place_cursor(self.buffer.get_end_iter()) self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "> text") self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "text") buffer.place_cursor(self.buffer.get_start_iter()) self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "> text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "text") buffer.select_range(buffer.get_iter_at_offset(2), buffer.get_iter_at_offset(3)) self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "> text") # Basic multi-line formatter, buffer = self.__reset() start_iter = buffer.get_start_iter() buffer.insert(start_iter, "line\nline\nline\nline") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "> line\n> line\n> line\n> line") self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "line\nline\nline\nline") # Mixed quote indentation multi-line formatter, buffer = self.__reset() start_iter = buffer.get_start_iter() buffer.insert(start_iter, "line\n> line\nline\nline") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "> line\n> > line\n> line\n> line") self.__call_and_wait(formatter.quote) self.assertEqual(self.__get_text(), "line\n> line\nline\nline") def test_heading(self) -> None: # Empty formatter, buffer = self.__reset() self.__call_and_wait(formatter.heading, 1) self.assertEqual(self.__get_text(), "# ") formatter.heading(0) self.assertEqual(self.__get_text(), "") # Basic text buffer.insert(buffer.get_start_iter(), "text") self.__call_and_wait(formatter.heading, 1) self.assertEqual(self.__get_text(), "# text") self.__call_and_wait(formatter.heading, 3) self.assertEqual(self.__get_text(), "### text") formatter.heading(0) self.assertEqual(self.__get_text(), "text") # Cursor location and selection not making a difference formatter, buffer = self.__reset() buffer.insert(buffer.get_start_iter(), "text") buffer.place_cursor(self.buffer.get_end_iter()) self.__call_and_wait(formatter.heading, 1) self.assertEqual(self.__get_text(), "# text") formatter.heading(0) self.assertEqual(self.__get_text(), "text") buffer.place_cursor(self.buffer.get_start_iter()) self.__call_and_wait(formatter.heading, 1) self.assertEqual(self.__get_text(), "# text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) formatter.heading(0) self.assertEqual(self.__get_text(), "text") buffer.select_range(buffer.get_iter_at_offset(2), buffer.get_iter_at_offset(3)) self.__call_and_wait(formatter.heading, 1) self.assertEqual(self.__get_text(), "# text") def test_get_link_state(self) -> None: # Empty formatter, buffer = self.__reset() state = formatter.get_link_state() self.assertTrue(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "") self.assertEqual(state.text, "") # Typical inline link formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "[text]()") buffer.place_cursor(buffer.get_start_iter()) state = formatter.get_link_state() self.assertFalse(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "https://linky.com") self.assertEqual(state.text, "text") self.assertEqual(state.source_text, "[text]()") self.assertEqual(state.start_offset, 0) self.assertEqual(state.end_offset, 27) # Creating inline from automatic formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "") buffer.place_cursor(buffer.get_start_iter()) state = formatter.get_link_state() self.assertTrue(state.creating) self.assertTrue(state.automatic_link) self.assertEqual(state.link, "https://linky.com") self.assertEqual(state.text, "") # URL in plain text formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "https://linky.com") buffer.place_cursor(buffer.get_start_iter()) state = formatter.get_link_state() self.assertTrue(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "https://linky.com") self.assertEqual(state.text, "") # New from URL selection formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "https://linky.com") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) state = formatter.get_link_state() self.assertTrue(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "https://linky.com") self.assertEqual(state.text, "") # Edit selected inline formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "[text]()") buffer.select_range(buffer.get_iter_at_offset(3), buffer.get_iter_at_offset(10)) state = formatter.get_link_state() self.assertFalse(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "https://linky.com") self.assertEqual(state.text, "text") self.assertEqual(state.source_text, "[text]()") self.assertEqual(state.start_offset, 0) self.assertEqual(state.end_offset, 27) # Creating inline from selected automatic formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) state = formatter.get_link_state() self.assertTrue(state.creating) self.assertTrue(state.automatic_link) self.assertEqual(state.link, "https://linky.com") self.assertEqual(state.text, "") # Selection text for title in creation formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "plain text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) state = formatter.get_link_state() self.assertTrue(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "") self.assertEqual(state.text, "plain text") # Avoiding creating link from selection which has markup formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "- item") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) state = formatter.get_link_state() self.assertTrue(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "") self.assertEqual(state.text, "") # Create when seeing only part of URI formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "plain text https://") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) state = formatter.get_link_state() self.assertTrue(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "") self.assertEqual(state.text, "") # Ignore selection when multi-line, create new formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "[text]()\ntext") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) state = formatter.get_link_state() self.assertTrue(state.creating) self.assertFalse(state.automatic_link) self.assertEqual(state.link, "") self.assertEqual(state.text, "") def test_link(self) -> None: # No replacement formatter, buffer = self.__reset() info = LinkStateInfo() info.text = "text" info.link = "https://linky.com" formatter.link(info) self.assertEqual(self.__get_text(), "[text](https://linky.com)") # Replace text used for title formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "plain text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) info = formatter.get_link_state() self.assertTrue(info.creating) self.assertFalse(info.automatic_link) self.assertEqual(info.link, "") self.assertEqual(info.text, "plain text") info.link = "https://linky.com" formatter.link(info) self.assertEqual(self.__get_text(), "[plain text](https://linky.com)") # Edit inline formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "[text](https://linky.com)") buffer.place_cursor(buffer.get_start_iter()) info = formatter.get_link_state() self.assertFalse(info.creating) self.assertFalse(info.automatic_link) self.assertEqual(info.link, "https://linky.com") self.assertEqual(info.text, "text") self.assertEqual(info.source_text, "[text](https://linky.com)") self.assertEqual(info.start_offset, 0) self.assertEqual(info.end_offset, 25) info.link = "https://newlink.com" info.text = "new text" formatter.link(info) self.assertEqual(self.__get_text(), "[new text](https://newlink.com)") # Insert instead of edit if buffer is updated remotely while in edit link dialog formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "[text](https://linky.com)") buffer.place_cursor(buffer.get_start_iter()) info = formatter.get_link_state() info.link = "https://newlink.com" info.text = "new text" self.__insert_and_wait(buffer.get_start_iter(), "modified") formatter.link(info) self.assertEqual( self.__get_text(), "modified[new text](https://newlink.com)[text](https://linky.com)" ) def test_code(self) -> None: # Markup around cursor formatter, buffer = self.__reset() self.__call_and_wait(formatter.code) self.assertEqual(self.__get_text(), "``") formatter.code() self.assertEqual(self.__get_text(), "") # Code block formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "line\nline\nline") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.code) self.assertEqual(self.__get_text(), "```\nline\nline\nline\n```\n") formatter.code() self.assertEqual(self.__get_text(), "line\nline\nline\n\n") # Basic span formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "code") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.code) self.assertEqual(self.__get_text(), "`code`") formatter.code() self.assertEqual(self.__get_text(), "code") # Double backtick span formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "``code``") buffer.place_cursor(buffer.get_iter_at_offset(3)) formatter.code() self.assertEqual(self.__get_text(), "code") def test_unordered_list(self) -> None: # Empty formatter, buffer = self.__reset() self.__call_and_wait(formatter.unordered_list) self.assertEqual(self.__get_text(), "- ") formatter.unordered_list() self.assertEqual(self.__get_text(), "") # Basic formatter, buffer = self.__reset() buffer.insert(buffer.get_start_iter(), "text") self.__call_and_wait(formatter.unordered_list) self.assertEqual(self.__get_text(), "- text") # Multi-line formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "text\ntext\n- text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.unordered_list) self.assertEqual(self.__get_text(), "- text\n- text\ntext") self.__call_and_wait(formatter.unordered_list) self.assertEqual(self.__get_text(), "text\ntext\n- text") # Other list items formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "- [ ] text") self.__call_and_wait(formatter.unordered_list) self.assertEqual(self.__get_text(), "- text") formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "1. text") self.__call_and_wait(formatter.unordered_list) self.assertEqual(self.__get_text(), "- text") def test_ordered_list(self) -> None: # Empty formatter, buffer = self.__reset() self.__call_and_wait(formatter.ordered_list) self.assertEqual(self.__get_text(), "1. ") formatter.ordered_list() self.assertEqual(self.__get_text(), "") # Basic formatter, buffer = self.__reset() buffer.insert(buffer.get_start_iter(), "text") self.__call_and_wait(formatter.ordered_list) self.assertEqual(self.__get_text(), "1. text") # Multi-line formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "text\ntext\ntext") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.ordered_list) self.assertEqual(self.__get_text(), "1. text\n2. text\n3. text") self.__call_and_wait(formatter.ordered_list) self.assertEqual(self.__get_text(), "text\ntext\ntext") # Continuation of existing formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "1. text\n2. text\n3. text\ntext\ntext") success, line_iter = buffer.get_iter_at_line(3) self.assertTrue(success) buffer.select_range(line_iter, buffer.get_end_iter()) self.__call_and_wait(formatter.ordered_list) self.assertEqual(self.__get_text(), "1. text\n2. text\n3. text\n4. text\n5. text") # Other list items formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "- [ ] text\n* text\n+ text\n- text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.ordered_list) self.assertEqual(self.__get_text(), "1. text\n2. text\n3. text\n4. text") formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "- [ ] text") self.__call_and_wait(formatter.ordered_list) self.assertEqual(self.__get_text(), "1. text") def test_checkbox(self) -> None: # Empty formatter, buffer = self.__reset() self.__call_and_wait(formatter.checkbox) self.assertEqual(self.__get_text(), "- [ ] ") formatter.checkbox() self.assertEqual(self.__get_text(), "") # Basic formatter, buffer = self.__reset() buffer.insert(buffer.get_start_iter(), "text") self.__call_and_wait(formatter.checkbox) self.assertEqual(self.__get_text(), "- [ ] text") # Multi-line formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "text\ntext\n- [ ] text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.checkbox) self.assertEqual(self.__get_text(), "- [ ] text\n- [ ] text\ntext") self.__call_and_wait(formatter.checkbox) self.assertEqual(self.__get_text(), "text\ntext\n- [ ] text") # Other list items formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "- text\n* text\n+ text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.checkbox) self.assertEqual(self.__get_text(), "- [ ] text\n- [ ] text\n- [ ] text") formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "1. text") self.__call_and_wait(formatter.checkbox) self.assertEqual(self.__get_text(), "- [ ] text") def test_toggle_checkbox(self) -> None: # Empty formatter, buffer = self.__reset() formatter.toggle_checkbox() self.assertEqual(self.__get_text(), "") # Plain text formatter, buffer = self.__reset() buffer.insert(buffer.get_start_iter(), "text") formatter.toggle_checkbox() self.assertEqual(self.__get_text(), "text") # Basic formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "- [ ] text") self.__call_and_wait(formatter.toggle_checkbox) self.assertEqual(self.__get_text(), "- [x] text") formatter.toggle_checkbox() self.assertEqual(self.__get_text(), "- [ ] text") # Indented formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), " - [ ] text") self.__call_and_wait(formatter.toggle_checkbox) self.assertEqual(self.__get_text(), " - [x] text") formatter.toggle_checkbox() self.assertEqual(self.__get_text(), " - [ ] text") # Multi line formatter, buffer = self.__reset() self.__insert_and_wait(buffer.get_start_iter(), "- [ ] text\n- [ ] text\n- [x] text") buffer.select_range(buffer.get_start_iter(), buffer.get_end_iter()) self.__call_and_wait(formatter.toggle_checkbox) self.assertEqual(self.__get_text(), "- [x] text\n- [x] text\n- [ ] text") formatter.toggle_checkbox() self.assertEqual(self.__get_text(), "- [ ] text\n- [ ] text\n- [x] text") # Other list items formatter, buffer = self.__reset() buffer.insert(buffer.get_start_iter(), "- text") formatter.toggle_checkbox() self.assertEqual(self.__get_text(), "- text") formatter, buffer = self.__reset() buffer.insert(buffer.get_start_iter(), "1. text") formatter.toggle_checkbox() self.assertEqual(self.__get_text(), "1. text") def test_horizontal_rule(self) -> None: formatter, buffer = self.__reset() self.__call_and_wait(formatter.horizontal_rule) self.assertEqual(self.__get_text(), "\n- - -\n") self.__call_and_wait(formatter.horizontal_rule) self.assertEqual(self.__get_text(), "\n\n") formatter, buffer = self.__reset() buffer.insert(buffer.get_start_iter(), "text") buffer.place_cursor(buffer.get_start_iter()) self.__call_and_wait(formatter.horizontal_rule) self.assertEqual(self.__get_text(), "\n- - -\n\ntext") formatter, buffer = self.__reset() buffer.insert(buffer.get_end_iter(), "text") buffer.place_cursor(buffer.get_start_iter()) self.__call_and_wait(formatter.horizontal_rule) self.assertEqual(self.__get_text(), "\n- - -\n\ntext") def test_table(self) -> None: def add_table(columns, rows, view_width, character_width) -> None: self.__call_and_wait(formatter.table, columns, rows, view_width, character_width) def check_table(columns: int, rows: int, min_column_width: int) -> bool: text = self.__get_text() lines = text.strip().split("\n") if len(lines) != rows + 2: return False if lines[0].replace(" ", "") != "|" * (columns + 1): return False return True formatter, buffer = self.__reset() add_table(columns=3, rows=3, view_width=600, character_width=5) self.assertTrue(check_table(3, 3, 20)) # Check GFM min column width formatter, buffer = self.__reset() add_table(columns=300, rows=3, view_width=600, character_width=5) self.assertTrue(check_table(300, 3, 3)) def __get_language(self) -> tuple[GtkSource.LanguageManager, GtkSource.Language]: manager = GtkSource.LanguageManager() file_dir = os.path.dirname(__file__) language_path = os.path.join( file_dir, os.pardir, "data", "gtksourceview-5", "language-specs" ) manager.prepend_search_path(language_path) language = manager.get_language("iotas-markdown") return (manager, language) def __reset(self) -> tuple[Formatter, GtkSource.Buffer]: self.formatter = Formatter() self.__manager, language = self.__get_language() self.buffer = GtkSource.Buffer.new_with_language(language) self.formatter.buffer = self.buffer return (self.formatter, self.buffer) def __get_text(self) -> str: if self.buffer is None: return "" else: start = self.buffer.get_start_iter() end = self.buffer.get_end_iter() return self.buffer.get_text(start, end, False) def __call_and_wait(self, call: Callable, *args) -> None: context = GLib.MainContext.default() self.buffer.connect("highlight-updated", self.__flag_not_waiting) self.awaiting_signal = True call(*args) while self.awaiting_signal: context.iteration(False) def __insert_and_wait(self, location: Gtk.TextIter, text: str) -> None: context = GLib.MainContext.default() self.buffer.connect("highlight-updated", self.__flag_not_waiting) self.awaiting_signal = True self.buffer.insert(location, text) while self.awaiting_signal: context.iteration(False) def __flag_not_waiting(self, *_args) -> None: self.awaiting_signal = False iotas-0.12.1-fdd88d6f077a2da6e33c81b56dbe3967224917f4/tests/test_html_generator.py000066400000000000000000000162341507102636600261750ustar00rootroot00000000000000import os import unittest import warnings from iotas.html_generator_configuration import HtmlGeneratorConfiguration from iotas.markdown_helpers import parse_to_tokens from iotas.note import Note from iotas.template_html_generator import TemplateHtmlGenerator, TemplateDetails warnings.filterwarnings("ignore", "version") class _TestHtmlGeneratorConfig(HtmlGeneratorConfiguration): tex_support = False @property def markdown_tex_support(self) -> bool: """Get whether markdown TeX rendering is supported. :return: Markdown TeX supported :rtype: bool """ return self.tex_support @property def line_length(self) -> int: """Get line length. :return: Size in pixels :rtype: int """ return 800 @property def markdown_use_monospace_font(self) -> bool: """Get whether to use a monospace font for the markdown render. :return: Using monospace font :rtype: bool """ return False @property def use_monospace_font(self) -> bool: """Get whether to use a monospace font. :return: Using monospace font :rtype: bool """ return True @property def font_size(self) -> int: """Get font size. :return: Size :rtype: int """ return 14 @property def high_contrast(self) -> bool: """Get whether high contrast output should be used for screen rendering. :return: Whether visible :rtype: bool """ return False @property def markdown_render_monospace_font_ratio(self) -> float: """Get the adjustment in size from proportional to fixed width font. :return: Ratio :rtype: float """ return 1.0 @property def editor_header_bar_visible_for_window_state(self) -> bool: """Get whether the header bar is configured visible for the window maximised state." :return: Whether visible :rtype: bool """ return False class Test(unittest.TestCase): def test_generate(self) -> None: note = Note(new_note=True) note.content = "content" note.id = 1 note.title = "Test Note Title" generator = self.__reset() parser, tokens = parse_to_tokens(note, exporting=False, tex_support=False) html = generator.generate( note, tokens, parser.renderer.render, parser.options, searching=False, export_format=None, ) self.assertTrue(note.content in html) self.assertTrue(note.title in html) self.assertFalse("katex" in html) self.assertFalse("