From 0fc84d19b245e8391c047b9a2dc8c25bc88499ec Mon Sep 17 00:00:00 2001 From: RumovZ Date: Fri, 20 Nov 2020 09:23:25 +0100 Subject: [PATCH 1/8] Replace text.rs/text_to_re with text.rs/to_re --- rslib/src/tags.rs | 4 ++-- rslib/src/text.rs | 32 -------------------------------- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/rslib/src/tags.rs b/rslib/src/tags.rs index 7b6c424ff..e0443c7b0 100644 --- a/rslib/src/tags.rs +++ b/rslib/src/tags.rs @@ -5,7 +5,7 @@ use crate::{ collection::Collection, err::{AnkiError, Result}, notes::{NoteID, TransformNoteOutput}, - text::text_to_re, + text::to_re, {text::normalize_to_nfc, types::Usn}, }; use regex::{NoExpand, Regex, Replacer}; @@ -134,7 +134,7 @@ impl Collection { // generate regexps let tags = split_tags(tags) .map(|tag| { - let tag = if regex { tag.into() } else { text_to_re(tag) }; + let tag = if regex { tag.into() } else { to_re(tag) }; Regex::new(&format!("(?i)^{}$", tag)) .map_err(|_| AnkiError::invalid_input("invalid regex")) }) diff --git a/rslib/src/text.rs b/rslib/src/text.rs index 934fa64c0..5a063eafc 100644 --- a/rslib/src/text.rs +++ b/rslib/src/text.rs @@ -258,38 +258,6 @@ pub(crate) fn without_combining(s: &str) -> Cow { .into() } -/// Escape text, converting glob characters to regex syntax, then return. -pub(crate) fn text_to_re(glob: &str) -> String { - lazy_static! { - static ref ESCAPED: Regex = Regex::new(r"(\\\\)?\\\*").unwrap(); - static ref GLOB: Regex = Regex::new(r"(\\\\)?[_%]").unwrap(); - } - - let escaped = regex::escape(glob); - - let text = ESCAPED.replace_all(&escaped, |caps: &Captures| { - if caps.get(0).unwrap().as_str().len() == 2 { - ".*" - } else { - r"\*" - } - }); - - let text2 = GLOB.replace_all(&text, |caps: &Captures| { - match caps.get(0).unwrap().as_str() { - "_" => ".", - "%" => ".*", - other => { - // strip off the escaping char - &other[2..] - } - } - .to_string() - }); - - text2.into() -} - /// Check if string contains an unescaped wildcard. pub(crate) fn is_glob(txt: &str) -> bool { // even number of \s followed by a wildcard From 347c547e10d9925bfb8a3e3018d9d1dbb3d4f7a6 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Fri, 20 Nov 2020 09:45:53 +0100 Subject: [PATCH 2/8] Add tests for conversion functions in text.rs --- rslib/src/text.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/rslib/src/text.rs b/rslib/src/text.rs index 5a063eafc..0cfa814c7 100644 --- a/rslib/src/text.rs +++ b/rslib/src/text.rs @@ -343,10 +343,7 @@ pub(crate) fn matches_glob(text: &str, search: &str) -> bool { #[cfg(test)] mod test { - use crate::text::without_combining; - use crate::text::{ - extract_av_tags, strip_av_tags, strip_html, strip_html_preserving_media_filenames, AVTag, - }; + use super::*; use std::borrow::Cow; #[test] @@ -395,4 +392,16 @@ mod test { assert!(matches!(without_combining("test"), Cow::Borrowed(_))); assert!(matches!(without_combining("Über"), Cow::Owned(_))); } + + #[test] + fn conversion() { + assert_eq!(&to_re(r"[te\*st]"), r"\[te\*st\]"); + assert_eq!(&to_custom_re("f_o*", r"\d"), r"f\do\d*"); + assert_eq!(&to_sql("%f_o*"), r"\%f_o%"); + assert_eq!(&to_text(r"\*\_*_"), "*_*_"); + assert_eq!(&escape_sql(r"1\2%3_"), r"1\\2\%3\_"); + assert!(is_glob(r"\\\\_")); + assert!(!is_glob(r"\\\_")); + assert!(matches_glob("foo*bar123", r"foo\*bar*")); + } } From a4d70c88e31259d13b215e44e8b79836f6549141 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 20 Nov 2020 19:33:40 +1000 Subject: [PATCH 3/8] remove make dependency in packaged Linux build --- qt/linux/Makefile.dist | 40 ---------------------------------------- qt/linux/README.dist | 7 ++----- qt/linux/install.sh | 29 +++++++++++++++++++++++++++++ qt/linux/uninstall.sh | 18 ++++++++++++++++++ 4 files changed, 49 insertions(+), 45 deletions(-) delete mode 100644 qt/linux/Makefile.dist create mode 100755 qt/linux/install.sh create mode 100755 qt/linux/uninstall.sh diff --git a/qt/linux/Makefile.dist b/qt/linux/Makefile.dist deleted file mode 100644 index 2c5823f27..000000000 --- a/qt/linux/Makefile.dist +++ /dev/null @@ -1,40 +0,0 @@ -PREFIX=/usr/local - -all: - @echo "You can run Anki with ./bin/Anki" - @echo "If you wish to install it system wide, type 'sudo make install'," - @echo "then run with 'anki'." - @echo "Uninstall with 'sudo make uninstall'" - -install: - rm -rf ${PREFIX}/share/anki - mkdir -p ${PREFIX}/share/anki - cp -av * ${PREFIX}/share/anki/ - mkdir -p ${PREFIX}/bin - ln -sf ${PREFIX}/share/anki/bin/Anki ${PREFIX}/bin/anki - # fix a previous packaging issue where we created this as a file - (test -f ${PREFIX}/share/applications && rm ${PREFIX}/share/applications)||true - mkdir -p ${PREFIX}/share/pixmaps - mkdir -p ${PREFIX}/share/applications - mkdir -p ${PREFIX}/share/man/man1 - cd ${PREFIX}/share/anki && (\ - mv anki.xpm anki.png ${PREFIX}/share/pixmaps/;\ - mv anki.desktop ${PREFIX}/share/applications/;\ - mv anki.1 ${PREFIX}/share/man/man1/) - xdg-mime install anki.xml --novendor - xdg-mime default anki.desktop application/x-colpkg - xdg-mime default anki.desktop application/x-apkg - xdg-mime default anki.desktop application/x-ankiaddon - @echo - @echo "Install complete. Type 'anki' to run." - -uninstall: - -xdg-mime uninstall ${PREFIX}/share/anki/anki.xml - rm -rf ${PREFIX}/share/anki - rm -rf ${PREFIX}/bin/anki - rm -rf ${PREFIX}/share/pixmaps/anki.xpm - rm -rf ${PREFIX}/share/pixmaps/anki.png - rm -rf ${PREFIX}/share/applications/anki.desktop - rm -rf ${PREFIX}/share/man/man1/anki.1 - @echo - @echo "Uninstall complete." diff --git a/qt/linux/README.dist b/qt/linux/README.dist index 5ba3f62c9..7cecbdb5b 100644 --- a/qt/linux/README.dist +++ b/qt/linux/README.dist @@ -2,11 +2,8 @@ To run, change to this folder in a terminal and run the following command: ./bin/Anki -- To install system wide, ensure you have make installed -(eg in Ubuntu, run 'sudo apt install make' in a terminal) -- Run 'sudo make install' -- Start Anki with 'anki' -- To remove in the future, run 'sudo make uninstall' from the same folder. +- To install system wide, run 'sudo ./install.sh' +- To remove in the future, run 'sudo ./uninstall.sh' from the same folder. To play and record audio, mpv and lame must be installed. If mpv is not installed or too old, Anki will try to fall back on using mplayer. diff --git a/qt/linux/install.sh b/qt/linux/install.sh new file mode 100755 index 000000000..49e6c1a1f --- /dev/null +++ b/qt/linux/install.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -e + +if [ "$PREFIX" = "" ]; then + PREFIX=/usr/local +fi + +rm -rf ${PREFIX}/share/anki +mkdir -p ${PREFIX}/share/anki +cp -av * ${PREFIX}/share/anki/ +mkdir -p ${PREFIX}/bin +ln -sf ${PREFIX}/share/anki/bin/Anki ${PREFIX}/bin/anki +# fix a previous packaging issue where we created this as a file +(test -f ${PREFIX}/share/applications && rm ${PREFIX}/share/applications)||true +mkdir -p ${PREFIX}/share/pixmaps +mkdir -p ${PREFIX}/share/applications +mkdir -p ${PREFIX}/share/man/man1 +cd ${PREFIX}/share/anki && (\ +mv anki.xpm anki.png ${PREFIX}/share/pixmaps/;\ +mv anki.desktop ${PREFIX}/share/applications/;\ +mv anki.1 ${PREFIX}/share/man/man1/) + +xdg-mime install anki.xml --novendor +xdg-mime default anki.desktop application/x-colpkg +xdg-mime default anki.desktop application/x-apkg +xdg-mime default anki.desktop application/x-ankiaddon + +echo "Install complete. Type 'anki' to run." diff --git a/qt/linux/uninstall.sh b/qt/linux/uninstall.sh new file mode 100755 index 000000000..77b71db78 --- /dev/null +++ b/qt/linux/uninstall.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +if [ "$PREFIX" = "" ]; then + PREFIX=/usr/local +fi + +xdg-mime uninstall ${PREFIX}/share/anki/anki.xml || true + +rm -rf ${PREFIX}/share/anki +rm -rf ${PREFIX}/bin/anki +rm -rf ${PREFIX}/share/pixmaps/anki.xpm +rm -rf ${PREFIX}/share/pixmaps/anki.png +rm -rf ${PREFIX}/share/applications/anki.desktop +rm -rf ${PREFIX}/share/man/man1/anki.1 + +echo "Uninstall complete." From 751e8183c4476d7bc4da31e22bd97e0166962c1d Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 22 Nov 2020 14:36:44 +1000 Subject: [PATCH 4/8] update translations update translations --- repos.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/repos.bzl b/repos.bzl index d1a066db4..c5025a082 100644 --- a/repos.bzl +++ b/repos.bzl @@ -120,11 +120,11 @@ def register_repos(): # translations ################ - core_i18n_commit = "1599ff1c4cb60b98fe0e80e1b45da47e9de9eeb1" - core_i18n_shallow_since = "1605671186 +1000" + core_i18n_commit = "1a107ce14da4da13df27216704b5cc1709037aca" + core_i18n_shallow_since = "1606019752 +0000" - qtftl_i18n_commit = "9909cfa4386288e686b2336b3b1048b7ee1bb194" - qtftl_i18n_shallow_since = "1605664969 +1000" + qtftl_i18n_commit = "33d11d992f2a868249ac958c782fe977339968a4" + qtftl_i18n_shallow_since = "1605822423 +0000" i18n_build_content = """ filegroup( From 0b848eae5681d5fe4b88b478ccf9f0cc982ecb46 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 22 Nov 2020 14:57:53 +1000 Subject: [PATCH 5/8] update remaining python format strings to Fluent --- ftl/core/browsing.ftl | 32 ++++++++------- ftl/core/card-templates.ftl | 26 ++++++------ ftl/core/importing.ftl | 47 ++++++++++++---------- ftl/qt/about.ftl | 2 +- ftl/qt/addons.ftl | 25 ++++++------ pylib/anki/importing/csvfile.py | 10 ++--- qt/aqt/about.py | 6 +-- qt/aqt/addons.py | 46 ++++++++++----------- qt/aqt/browser.py | 8 ++-- qt/aqt/clayout.py | 6 ++- scripts/BUILD.bazel | 6 +++ scripts/transform-string.py | 71 +++++++++++++++++++++++++++++++++ 12 files changed, 187 insertions(+), 98 deletions(-) create mode 100644 scripts/transform-string.py diff --git a/ftl/core/browsing.ftl b/ftl/core/browsing.ftl index 82a089255..b359e2012 100644 --- a/ftl/core/browsing.ftl +++ b/ftl/core/browsing.ftl @@ -43,7 +43,7 @@ browsing-first-card = First Card browsing-flag = Flag browsing-font = Font: browsing-font-size = Font Size: -browsing-found-as-across-bs = Found %(a)s across %(b)s. +browsing-found-as-across-bs = Found { $part } across { $whole }. browsing-home = Home browsing-ignore-case = Ignore case browsing-in = In: @@ -54,7 +54,7 @@ browsing-line-size = Line Size: browsing-manage-note-types = Manage Note Types... browsing-move-cards = Move Cards browsing-move-cards-to-deck = Move cards to deck: -browsing-nd-names = %(n)d: %(name)s +browsing-nd-names = { $num }: { $name } browsing-new = (new) browsing-new-note-type = New note type: browsing-no-flag = No Flag @@ -102,17 +102,19 @@ browsing-treat-input-as-regular-expression = Treat input as regular expression browsing-type-here-to-search = browsing-whole-collection = Whole Collection browsing-you-must-have-at-least-one = You must have at least one column. -browsing-group = { $count -> - [one] { $count } group - *[other] { $count } groups - } -browsing-note-count = { $count -> - [one] { $count } note - *[other] { $count } notes - } -browsing-note-deleted = { $count -> - [one] { $count } note deleted. - *[other] { $count } notes deleted. - } +browsing-group = + { $count -> + [one] { $count } group + *[other] { $count } groups + } +browsing-note-count = + { $count -> + [one] { $count } note + *[other] { $count } notes + } +browsing-note-deleted = + { $count -> + [one] { $count } note deleted. + *[other] { $count } notes deleted. + } browsing-window-title = Browse ({ $selected } of { $total } cards selected) - diff --git a/ftl/core/card-templates.ftl b/ftl/core/card-templates.ftl index 8b66fc00e..74d235791 100644 --- a/ftl/core/card-templates.ftl +++ b/ftl/core/card-templates.ftl @@ -11,7 +11,7 @@ card-templates-front-preview = Front Preview card-templates-back-preview = Back Preview card-templates-preview-box = Preview card-templates-template-box = Template -card-templates-sample-cloze = This is a {"{{c1::"}sample{"}}"} cloze deletion. +card-templates-sample-cloze = This is a { "{{c1::" }sample{ "}}" } cloze deletion. card-templates-fill-empty = Fill Empty Fields card-templates-night-mode = Night Mode # Add "mobile" class to card preview, so the card appears like it would @@ -30,21 +30,23 @@ card-templates-card-types = Card Types card-templates-card-types-for = Card Types for { $val } card-templates-cloze = Cloze { $val } card-templates-deck-override = Deck Override... -card-templates-delete-the-as-card-type-and = Delete the '%(a)s' card type, and its %(b)s? +card-templates-delete-the-as-card-type-and = Delete the '{ $template }' card type, and its { $cards }? card-templates-enter-deck-to-place-new = Enter deck to place new { $val } cards in, or leave blank: card-templates-enter-new-card-position-1 = Enter new card position (1...{ $val }): card-templates-flip = Flip card-templates-form = Form -card-templates-off = (off) -card-templates-on = (on) +card-templates-off = (off) +card-templates-on = (on) card-templates-remove-card-type = Remove Card Type... card-templates-rename-card-type = Rename Card Type... card-templates-reposition-card-type = Reposition Card Type... -card-templates-card-count = { $count -> - [one] { $count } card - *[other] { $count } cards - } -card-templates-this-will-create-card-proceed = { $count -> - [one] This will create { $count } card. Proceed? - *[other] This will create { $count } cards. Proceed? - } +card-templates-card-count = + { $count -> + [one] { $count } card + *[other] { $count } cards + } +card-templates-this-will-create-card-proceed = + { $count -> + [one] This will create { $count } card. Proceed? + *[other] This will create { $count } cards. Proceed? + } diff --git a/ftl/core/importing.ftl b/ftl/core/importing.ftl index 08c7413da..60ba0a14e 100644 --- a/ftl/core/importing.ftl +++ b/ftl/core/importing.ftl @@ -36,7 +36,7 @@ importing-notes-that-could-not-be-imported = Notes that could not be imported as importing-notes-updated-as-file-had-newer = Notes updated, as file had newer version: { $val } importing-packaged-anki-deckcollection-apkg-colpkg-zip = Packaged Anki Deck/Collection (*.apkg *.colpkg *.zip) importing-pauker-18-lesson-paugz = Pauker 1.8 Lesson (*.pau.gz) -importing-rows-had-num1d-fields-expected-num2d = '%(row)s' had %(num1)d fields, expected %(num2)d +importing-rows-had-num1d-fields-expected-num2d = '{ $row }' had { $found } fields, expected { $expected } importing-selected-file-was-not-in-utf8 = Selected file was not in UTF-8 format. Please see the importing section of the manual. importing-semicolon = Semicolon importing-skipped = Skipped @@ -52,23 +52,28 @@ importing-unable-to-import-from-a-readonly = Unable to import from a read-only f importing-unknown-file-format = Unknown file format. importing-update-existing-notes-when-first-field = Update existing notes when first field matches importing-updated = Updated -importing-note-added = { $count -> - [one] { $count } note added - *[other] { $count } notes added - } -importing-note-imported = { $count -> - [one] { $count } note imported. - *[other] { $count } notes imported. - } -importing-note-unchanged = { $count -> - [one] { $count } note unchanged - *[other] { $count } notes unchanged - } -importing-note-updated = { $count -> - [one] { $count } note updated - *[other] { $count } notes updated - } -importing-processed-media-file = { $count -> - [one] Processed { $count } media file - *[other] Processed { $count } media files - } +importing-note-added = + { $count -> + [one] { $count } note added + *[other] { $count } notes added + } +importing-note-imported = + { $count -> + [one] { $count } note imported. + *[other] { $count } notes imported. + } +importing-note-unchanged = + { $count -> + [one] { $count } note unchanged + *[other] { $count } notes unchanged + } +importing-note-updated = + { $count -> + [one] { $count } note updated + *[other] { $count } notes updated + } +importing-processed-media-file = + { $count -> + [one] Processed { $count } media file + *[other] Processed { $count } media files + } diff --git a/ftl/qt/about.ftl b/ftl/qt/about.ftl index eb048cb64..6fd190638 100644 --- a/ftl/qt/about.ftl +++ b/ftl/qt/about.ftl @@ -7,4 +7,4 @@ about-copy-debug-info = Copy Debug Info about-if-you-have-contributed-and-are = If you have contributed and are not on this list, please get in touch. about-version = Version { $val } about-visit-website = Visit website -about-written-by-damien-elmes-with-patches = Written by Damien Elmes, with patches, translation, testing and design from:

%(cont)s +about-written-by-damien-elmes-with-patches = Written by Damien Elmes, with patches, translation, testing and design from:

{ $cont } diff --git a/ftl/qt/addons.ftl b/ftl/qt/addons.ftl index 89c8588f6..43894125d 100644 --- a/ftl/qt/addons.ftl +++ b/ftl/qt/addons.ftl @@ -19,13 +19,13 @@ addons-code = Code: addons-config = Config addons-configuration = Configuration addons-corrupt-addon-file = Corrupt add-on file. -addons-disabled = (disabled) +addons-disabled = (disabled) addons-disabled2 = (disabled) addons-download-complete-please-restart-anki-to = Download complete. Please restart Anki to apply changes. -addons-downloaded-fnames = Downloaded %(fname)s -addons-downloading-adbd-kb02fkb = Downloading %(a)d/%(b)d (%(kb)0.2fKB)... -addons-error-downloading-ids-errors = Error downloading %(id)s: %(error)s -addons-error-installing-bases-errors = Error installing %(base)s: %(error)s +addons-downloaded-fnames = Downloaded { $fname } +addons-downloading-adbd-kb02fkb = Downloading { $part }/{ $total } ({ $kilobytes }KB)... +addons-error-downloading-ids-errors = Error downloading { $id }: { $error } +addons-error-installing-bases-errors = Error installing { $base }: { $error } addons-get-addons = Get Add-ons... addons-important-as-addons-are-programs-downloaded = Important: As add-ons are programs downloaded from the internet, they are potentially malicious.You should only install add-ons you trust.

Are you sure you want to proceed with the installation of the following Anki add-on(s)?

%(names)s addons-install-addon = Install Add-on @@ -33,12 +33,12 @@ addons-install-addons = Install Add-on(s) addons-install-anki-addon = Install Anki add-on addons-install-from-file = Install from file... addons-installation-complete = Installation complete -addons-installed-names = Installed %(name)s +addons-installed-names = Installed { $name } addons-installed-successfully = Installed successfully. addons-invalid-addon-manifest = Invalid add-on manifest. addons-invalid-code = Invalid code. addons-invalid-code-or-addon-not-available = Invalid code, or add-on not available for your version of Anki. -addons-invalid-configuration = Invalid configuration: +addons-invalid-configuration = Invalid configuration: addons-invalid-configuration-top-level-object-must = Invalid configuration: top level object must be a map addons-no-updates-available = No updates available. addons-one-or-more-errors-occurred = One or more errors occurred: @@ -49,7 +49,7 @@ addons-please-restart-anki-to-complete-the = Please restart Anki to complete addons-please-select-a-single-addon-first = Please select a single add-on first. addons-requires = (requires { $val }) addons-restored-defaults = Restored defaults -addons-the-following-addons-are-incompatible-with = The following add-ons are incompatible with %(name)s and have been disabled: %(found)s +addons-the-following-addons-are-incompatible-with = The following add-ons are incompatible with { $name } and have been disabled: { $found } addons-the-following-addons-have-updates-available = The following add-ons have updates available. Install them now? addons-the-following-conflicting-addons-were-disabled = The following conflicting add-ons were disabled: addons-this-addon-is-not-compatible-with = This add-on is not compatible with your version of Anki. @@ -59,7 +59,8 @@ addons-unable-to-update-or-delete-addon = Unable to update or delete add-on. Ple addons-unknown-error = Unknown error: { $val } addons-view-addon-page = View Add-on Page addons-view-files = View Files -addons-delete-the-numd-selected-addon = { $count -> - [one] Delete the { $count } selected add-on? - *[other] Delete the { $count } selected add-ons? - } +addons-delete-the-numd-selected-addon = + { $count -> + [one] Delete the { $count } selected add-on? + *[other] Delete the { $count } selected add-ons? + } diff --git a/pylib/anki/importing/csvfile.py b/pylib/anki/importing/csvfile.py index c76a15295..eeee98d46 100644 --- a/pylib/anki/importing/csvfile.py +++ b/pylib/anki/importing/csvfile.py @@ -42,13 +42,11 @@ class TextImporter(NoteImporter): if row: log.append( self.col.tr( - TR.IMPORTING_ROWS_HAD_NUM1D_FIELDS_EXPECTED_NUM2D + TR.IMPORTING_ROWS_HAD_NUM1D_FIELDS_EXPECTED_NUM2D, + row=" ".join(row), + found=len(row), + expected=self.numFields, ) - % { - "row": " ".join(row), - "num1": len(row), - "num2": self.numFields, - } ) ignored += 1 continue diff --git a/qt/aqt/about.py b/qt/aqt/about.py index 73205ad85..71eb1591b 100644 --- a/qt/aqt/about.py +++ b/qt/aqt/about.py @@ -202,9 +202,9 @@ def show(mw): ) ) - abouttext += "

" + tr(TR.ABOUT_WRITTEN_BY_DAMIEN_ELMES_WITH_PATCHES) % { - "cont": ", ".join(allusers) - } + abouttext += "

" + tr( + TR.ABOUT_WRITTEN_BY_DAMIEN_ELMES_WITH_PATCHES, cont=", ".join(allusers) + ) abouttext += "

" + tr(TR.ABOUT_IF_YOU_HAVE_CONTRIBUTED_AND_ARE) abouttext += "

" + tr(TR.ABOUT_A_BIG_THANKS_TO_ALL_THE) abt.label.setMinimumWidth(800) diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py index ef8d18912..ab65e5903 100644 --- a/qt/aqt/addons.py +++ b/qt/aqt/addons.py @@ -275,8 +275,11 @@ class AddonManager: if conflicting: addons = ", ".join(self.addonName(f) for f in conflicting) showInfo( - tr(TR.ADDONS_THE_FOLLOWING_ADDONS_ARE_INCOMPATIBLE_WITH) - % dict(name=addon.human_name(), found=addons), + tr( + TR.ADDONS_THE_FOLLOWING_ADDONS_ARE_INCOMPATIBLE_WITH, + name=addon.human_name(), + found=addons, + ), textFormat="plain", ) @@ -306,7 +309,7 @@ class AddonManager: meta = self.addon_meta(dir) name = meta.human_name() if not meta.enabled: - name += tr(TR.ADDONS_DISABLED) + name += " " + tr(TR.ADDONS_DISABLED) return name # Conflict resolution @@ -469,26 +472,24 @@ class AddonManager: result.errmsg, tr(TR.ADDONS_UNKNOWN_ERROR, val=result.errmsg) ) - if mode == "download": # preserve old format strings for i18n - template = tr(TR.ADDONS_ERROR_DOWNLOADING_IDS_ERRORS) + if mode == "download": + template = tr(TR.ADDONS_ERROR_DOWNLOADING_IDS_ERRORS, id=base, error=msg) else: - template = tr(TR.ADDONS_ERROR_INSTALLING_BASES_ERRORS) + template = tr(TR.ADDONS_ERROR_INSTALLING_BASES_ERRORS, base=base, error=msg) - name = base - - return [template % dict(base=name, id=name, error=msg)] + return [template] def _installationSuccessReport( self, result: InstallOk, base: str, mode: str = "download" ) -> List[str]: - if mode == "download": # preserve old format strings for i18n - template = tr(TR.ADDONS_DOWNLOADED_FNAMES) - else: - template = tr(TR.ADDONS_INSTALLED_NAMES) - name = result.name or base - strings = [template % dict(name=name, fname=name)] + if mode == "download": + template = tr(TR.ADDONS_DOWNLOADED_FNAMES, fname=name) + else: + template = tr(TR.ADDONS_INSTALLED_NAMES, name=name) + + strings = [template] if result.conflicts: strings.append( @@ -1074,13 +1075,12 @@ class DownloaderInstaller(QObject): def _progress_callback(self, up: int, down: int) -> None: self.dl_bytes += down self.mgr.mw.progress.update( - # T: "%(a)d" is the index of the element currently - # downloaded. "%(b)d" is the number of element to download, - # and "%(kb)0.2f" is the number of downloaded - # kilobytes. This lead for example to "Downloading 3/5 - # (27KB)" - label=tr(TR.ADDONS_DOWNLOADING_ADBD_KB02FKB) - % dict(a=len(self.log) + 1, b=len(self.ids), kb=self.dl_bytes / 1024) + label=tr( + TR.ADDONS_DOWNLOADING_ADBD_KB02FKB, + part=len(self.log) + 1, + total=len(self.ids), + kilobytes=self.dl_bytes / 1024, + ) ) def _download_all(self) -> None: @@ -1361,7 +1361,7 @@ class ConfigEditor(QDialog): showInfo(msg) return except Exception as e: - showInfo(tr(TR.ADDONS_INVALID_CONFIGURATION) + repr(e)) + showInfo(tr(TR.ADDONS_INVALID_CONFIGURATION) + " " + repr(e)) return if not isinstance(new_conf, dict): diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 967af003c..b43d5b1a2 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -1352,8 +1352,10 @@ QTableView {{ gridline-color: {grid} }} for c, tmpl in enumerate(nt["tmpls"]): # T: name is a card type name. n it's order in the list of card type. # T: this is shown in browser's filter, when seeing the list of card type of a note type. - name = tr(TR.BROWSING_ND_NAMES) % dict( - n=c + 1, name=self._escapeMenuItem(tmpl["name"]) + name = tr( + TR.BROWSING_ND_NAMES, + num=c + 1, + name=self._escapeMenuItem(tmpl["name"]), ) subm.addItem( name, self._filterFunc("note", nt["name"], "card", str(c + 1)) @@ -1995,7 +1997,7 @@ where id in %s""" notes = sum(len(r[1]) for r in res) part1 = tr(TR.BROWSING_GROUP, count=groups) part2 = tr(TR.BROWSING_NOTE_COUNT, count=notes) - t += tr(TR.BROWSING_FOUND_AS_ACROSS_BS) % dict(a=part1, b=part2) + t += tr(TR.BROWSING_FOUND_AS_ACROSS_BS, part=part1, whole=part2) t += "

    " for val, nids in res: t += ( diff --git a/qt/aqt/clayout.py b/qt/aqt/clayout.py index 47c2211ca..6181dc79d 100644 --- a/qt/aqt/clayout.py +++ b/qt/aqt/clayout.py @@ -564,8 +564,10 @@ class CardLayout(QDialog): template = self.current_template() cards = tr(TR.CARD_TEMPLATES_CARD_COUNT, count=card_cnt) - msg = tr(TR.CARD_TEMPLATES_DELETE_THE_AS_CARD_TYPE_AND) % dict( - a=template["name"], b=cards + msg = tr( + TR.CARD_TEMPLATES_DELETE_THE_AS_CARD_TYPE_AND, + template=template["name"], + cards=cards, ) if not askUser(msg): return diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 442618eb8..67de5adab 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -13,3 +13,9 @@ py_binary( srcs = ["extract-strings.py"], deps = [requirement("fluent-syntax")], ) + +py_binary( + name = "transform-string", + srcs = ["transform-string.py"], + deps = [requirement("fluent-syntax")], +) diff --git a/scripts/transform-string.py b/scripts/transform-string.py new file mode 100644 index 000000000..cc559eb7b --- /dev/null +++ b/scripts/transform-string.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +""" +Tool to apply transform to an ftl string and its translations. +""" + +import os +import json +import glob +from fluent.syntax import parse, serialize +from fluent.syntax.ast import Junk + +template_root = os.environ["BUILD_WORKSPACE_DIRECTORY"] +template_files = glob.glob( + os.path.join(template_root, "ftl", "*", "*.ftl"), recursive=True +) +translation_root = os.path.join(template_root, "..", "anki-i18n") +translation_files = glob.glob( + os.path.join(translation_root, "*", "*", "*", "*.ftl"), recursive=True +) + +target_repls = [ + ["addons-downloaded-fnames", "%(fname)s", "{ $fname }"], + ["addons-downloading-adbd-kb02fkb", "%(a)d", "{ $part }"], + ["addons-downloading-adbd-kb02fkb", "%(b)d", "{ $total }"], + ["addons-downloading-adbd-kb02fkb", "%(kb)0.2f", "{ $kilobytes }"], + ["addons-error-downloading-ids-errors", "%(id)s", "{ $id }"], + ["addons-error-downloading-ids-errors", "%(error)s", "{ $error }"], + ["addons-error-installing-bases-errors", "%(base)s", "{ $base }"], + ["addons-error-installing-bases-errors", "%(error)s", "{ $error }"], + ["addons-important-as-addons-are-programs-downloaded", "%(name)s", "{ $name }"], + ["addons-installed-names", "%(name)s", "{ $name }"], + ["addons-the-following-addons-are-incompatible-with", "%(name)s", "{ $name }"], + ["addons-the-following-addons-are-incompatible-with", "%(found)s", "{ $found }"], + ["about-written-by-damien-elmes-with-patches", "%(cont)s", "{ $cont }"], + ["importing-rows-had-num1d-fields-expected-num2d", "%(row)s", "{ $row }"], + ["importing-rows-had-num1d-fields-expected-num2d", "%(num1)d", "{ $found }"], + ["importing-rows-had-num1d-fields-expected-num2d", "%(num2)d", "{ $expected }"], + ["card-templates-delete-the-as-card-type-and", "%(a)s", "{ $template }"], + ["card-templates-delete-the-as-card-type-and", "%(b)s", "{ $cards }"], + ["browsing-found-as-across-bs", "%(a)s", "{ $part }"], + ["browsing-found-as-across-bs", "%(b)s", "{ $whole }"], + ["browsing-nd-names", "%(n)d", "{ $num }"], + ["browsing-nd-names", "%(name)s", "{ $name }"], +] + + +def transform_string_in_file(path): + obj = parse(open(path).read(), with_spans=False) + changed = False + for ent in obj.body: + if isinstance(ent, Junk): + raise Exception(f"file had junk! {path} {ent}") + if getattr(ent, "id", None): + key = ent.id.name + for (target_key, src, dst) in target_repls: + if key == target_key: + for elem in ent.value.elements: + newval = elem.value.replace(src, dst) + if newval != elem.value: + elem.value = newval + changed = True + + if changed: + open(path, "w", encoding="utf8").write(serialize(obj)) + print("updated", path) + + +for path in template_files + translation_files: + transform_string_in_file(path) From 52617511b0ec2ee3c3615c1da6901ab5e2860b22 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 22 Nov 2020 15:30:59 +1000 Subject: [PATCH 6/8] automatically format/check ftl files --- ftl/BUILD.bazel | 20 +++++++++ ftl/core/card-stats.ftl | 1 - ftl/core/card-template-rendering.ftl | 28 ++++--------- ftl/core/decks.ftl | 9 ++-- ftl/core/empty-cards.ftl | 12 +++--- ftl/core/exporting.ftl | 27 ++++++------ ftl/core/findreplace.ftl | 9 ++-- ftl/core/media-check.ftl | 1 - ftl/core/network.ftl | 3 +- ftl/core/notetypes.ftl | 1 - ftl/core/scheduling.ftl | 9 ++-- ftl/core/search.ftl | 1 + ftl/core/studying.ftl | 27 ++++++------ ftl/core/sync.ftl | 1 + ftl/format.py | 62 ++++++++++++++++++++++++++++ ftl/format_check.py | 10 +++++ ftl/qt/preferences.ftl | 5 +-- ftl/qt/profiles.ftl | 3 +- ftl/qt/qt-misc.ftl | 9 ++-- 19 files changed, 162 insertions(+), 76 deletions(-) create mode 100644 ftl/format.py create mode 100644 ftl/format_check.py diff --git a/ftl/BUILD.bazel b/ftl/BUILD.bazel index 5356aa65d..e9d227a19 100644 --- a/ftl/BUILD.bazel +++ b/ftl/BUILD.bazel @@ -1,3 +1,5 @@ +load("@py_deps//:requirements.bzl", "requirement") + filegroup( name = "ftl", srcs = [ @@ -7,6 +9,24 @@ filegroup( visibility = ["//rslib:__subpackages__"], ) +py_binary( + name = "format", + srcs = ["format.py"], + deps = [requirement("fluent-syntax")], +) + +py_test( + name = "format_check", + srcs = [ + "format.py", + "format_check.py", + ], + # so we can locate data files + args = ["$(location BUILD.bazel)"], + data = glob(["**/*.ftl"]) + ["BUILD.bazel"], + deps = [requirement("fluent-syntax")], +) + # export this file as a way of locating the top level folder in $(location ...) exports_files( ["BUILD.bazel"], diff --git a/ftl/core/card-stats.ftl b/ftl/core/card-stats.ftl index ddaf797d9..af08defcd 100644 --- a/ftl/core/card-stats.ftl +++ b/ftl/core/card-stats.ftl @@ -22,4 +22,3 @@ card-stats-review-log-type-review = Review card-stats-review-log-type-relearn = Relearn card-stats-review-log-type-filtered = Filtered card-stats-review-log-type-manual = Manual - diff --git a/ftl/core/card-template-rendering.ftl b/ftl/core/card-template-rendering.ftl index 42e1b66b1..bff3327a0 100644 --- a/ftl/core/card-template-rendering.ftl +++ b/ftl/core/card-template-rendering.ftl @@ -4,39 +4,27 @@ # Label of link users can click on card-template-rendering-more-info = More information - card-template-rendering-front-side-problem = Front template has a problem: card-template-rendering-back-side-problem = Back template has a problem: - # when the user forgot to close a field reference, # eg, Missing '}}' in '{{Field' -card-template-rendering-no-closing-brackets = - Missing '{$missing}' in '{$tag}' - +card-template-rendering-no-closing-brackets = Missing '{ $missing }' in '{ $tag }' # when the user opened a conditional, but forgot to close it # eg, Missing '{{/Conditional}}' -card-template-rendering-conditional-not-closed = - Missing '{$missing}' - +card-template-rendering-conditional-not-closed = Missing '{ $missing }' # when the user closed the wrong conditional # eg, Found '{{/Something}}', but expected '{{/SomethingElse}}' -card-template-rendering-wrong-conditional-closed = - Found '{$found}', but expected '{$expected}' - +card-template-rendering-wrong-conditional-closed = Found '{ $found }', but expected '{ $expected }' # when the user closed a conditional that wasn't open # eg, Found '{{/Something}}', but missing '{{#Something}}' or '{{^Something}}' -card-template-rendering-conditional-not-open = - Found '{$found}', but missing '{$missing1}' or '{$missing2}' - +card-template-rendering-conditional-not-open = Found '{ $found }', but missing '{ $missing1 }' or '{ $missing2 }' # when the user referenced a field that doesn't exist # eg, Found '{{Field}}', but there is not field called 'Field' -card-template-rendering-no-such-field = - Found '{$found}', but there is no field called '{$field}' - +card-template-rendering-no-such-field = Found '{ $found }', but there is no field called '{ $field }' # This message is shown when the front side of the card is blank, # either due to a badly-designed template, or because required fields # are missing. card-template-rendering-empty-front = The front of this card is blank. - -card-template-rendering-missing-cloze = No cloze { $number } found on card. - Please either add a cloze deletion, or use the Empty Cards tool. +card-template-rendering-missing-cloze = + No cloze { $number } found on card. + Please either add a cloze deletion, or use the Empty Cards tool. diff --git a/ftl/core/decks.ftl b/ftl/core/decks.ftl index 4eecee62a..222a993c2 100644 --- a/ftl/core/decks.ftl +++ b/ftl/core/decks.ftl @@ -31,7 +31,8 @@ decks-reschedule-cards-based-on-my-answers = Reschedule cards based on my answer decks-study = Study decks-study-deck = Study Deck decks-the-provided-search-did-not-match = The provided search did not match any cards. Would you like to revise it? -decks-it-has-card = { $count -> - [one] It has { $count } card. - *[other] It has { $count } cards. - } +decks-it-has-card = + { $count -> + [one] It has { $count } card. + *[other] It has { $count } cards. + } diff --git a/ftl/core/empty-cards.ftl b/ftl/core/empty-cards.ftl index e03144fcb..cbc9f91a9 100644 --- a/ftl/core/empty-cards.ftl +++ b/ftl/core/empty-cards.ftl @@ -1,14 +1,14 @@ empty-cards-for-note-type = Empty cards for { $notetype }: -empty-cards-count-line = - { $empty_count } of { $existing_count } cards empty ({ $template_names }). +empty-cards-count-line = { $empty_count } of { $existing_count } cards empty ({ $template_names }). empty-cards-window-title = Empty Cards empty-cards-preserve-notes-checkbox = Keep notes with no valid cards empty-cards-delete-button = Delete empty-cards-not-found = No empty cards. -empty-cards-deleted-count = Deleted { $cards -> - [one] { $cards } card. - *[other] { $cards } cards. - } +empty-cards-deleted-count = + Deleted { $cards -> + [one] { $cards } card. + *[other] { $cards } cards. + } empty-cards-delete-empty-cards = Delete Empty Cards empty-cards-delete-empty-notes = Delete Empty Notes empty-cards-deleting = Deleting... diff --git a/ftl/core/exporting.ftl b/ftl/core/exporting.ftl index 7d66820c5..c373b63ed 100644 --- a/ftl/core/exporting.ftl +++ b/ftl/core/exporting.ftl @@ -15,15 +15,18 @@ exporting-include-scheduling-information = Include scheduling information exporting-include-tags = Include tags exporting-notes-in-plain-text = Notes in Plain Text exporting-selected-notes = Selected Notes -exporting-card-exported = { $count -> - [one] { $count } card exported. - *[other] { $count } cards exported. - } -exporting-exported-media-file = { $count -> - [one] Exported { $count } media file - *[other] Exported { $count } media files - } -exporting-note-exported = { $count -> - [one] { $count } note exported. - *[other] { $count } notes exported. - } +exporting-card-exported = + { $count -> + [one] { $count } card exported. + *[other] { $count } cards exported. + } +exporting-exported-media-file = + { $count -> + [one] Exported { $count } media file + *[other] Exported { $count } media files + } +exporting-note-exported = + { $count -> + [one] { $count } note exported. + *[other] { $count } notes exported. + } diff --git a/ftl/core/findreplace.ftl b/ftl/core/findreplace.ftl index ad08c7a2b..85e7ed905 100644 --- a/ftl/core/findreplace.ftl +++ b/ftl/core/findreplace.ftl @@ -1,4 +1,5 @@ -findreplace-notes-updated = { $total -> - [one] {$changed} of {$total} note updated - *[other] {$changed} of {$total} notes updated - } +findreplace-notes-updated = + { $total -> + [one] { $changed } of { $total } note updated + *[other] { $changed } of { $total } notes updated + } diff --git a/ftl/core/media-check.ftl b/ftl/core/media-check.ftl index 02b52e23b..af6f9458d 100644 --- a/ftl/core/media-check.ftl +++ b/ftl/core/media-check.ftl @@ -1,7 +1,6 @@ ## Shown at the top of the media check screen media-check-window-title = Check Media - # the number of files, and the total space used by files # that have been moved to the trash folder. eg, # "Trash folder: 3 files, 3.47MB" diff --git a/ftl/core/network.ftl b/ftl/core/network.ftl index 9fff6a92b..660e410fd 100644 --- a/ftl/core/network.ftl +++ b/ftl/core/network.ftl @@ -2,5 +2,4 @@ network-offline = Please check your internet connection. network-timeout = Connection timed out. Please try again. If you see frequent timeouts, please try a different network connection. network-proxy-auth = Your proxy requires authentication. network-other = A network error occurred. - -network-details = Error details: {$details} +network-details = Error details: { $details } diff --git a/ftl/core/notetypes.ftl b/ftl/core/notetypes.ftl index d20d7fff9..5e993c0c2 100644 --- a/ftl/core/notetypes.ftl +++ b/ftl/core/notetypes.ftl @@ -18,7 +18,6 @@ notetypes-cloze-name = Cloze notetypes-card-1-name = Card 1 notetypes-card-2-name = Card 2 - notetypes-add = Add: { $val } notetypes-add-note-type = Add Note Type notetypes-cards = Cards... diff --git a/ftl/core/scheduling.ftl b/ftl/core/scheduling.ftl index be774a8d0..861c365e8 100644 --- a/ftl/core/scheduling.ftl +++ b/ftl/core/scheduling.ftl @@ -138,7 +138,8 @@ scheduling-steps-must-be-numbers = Steps must be numbers. scheduling-tag-only = Tag Only scheduling-the-default-configuration-cant-be-removed = The default configuration can't be removed. scheduling-your-changes-will-affect-multiple-decks = Your changes will affect multiple decks. If you wish to change only the current deck, please add a new options group first. -scheduling-deck-updated = { $count -> - [one] { $count } deck updated. - *[other] { $count } decks updated. - } +scheduling-deck-updated = + { $count -> + [one] { $count } deck updated. + *[other] { $count } decks updated. + } diff --git a/ftl/core/search.ftl b/ftl/core/search.ftl index 4f4de7f60..8bb63dbe7 100644 --- a/ftl/core/search.ftl +++ b/ftl/core/search.ftl @@ -6,3 +6,4 @@ search-note-modified = Note Modified search-card-modified = Card Modified ## + diff --git a/ftl/core/studying.ftl b/ftl/core/studying.ftl index 8f8b6180e..3cc23ffef 100644 --- a/ftl/core/studying.ftl +++ b/ftl/core/studying.ftl @@ -42,15 +42,18 @@ studying-type-answer-unknown-field = Type answer: unknown field { $val } studying-unbury = Unbury studying-what-would-you-like-to-unbury = What would you like to unbury? studying-you-havent-recorded-your-voice-yet = You haven't recorded your voice yet. -studying-card-studied-in = { $count -> - [one] { $count } card studied in - *[other] { $count } cards studied in - } -studying-minute = { $count -> - [one] { $count } minute. - *[other] { $count } minutes. - } -studying-note-and-its-card-deleted = { $count -> - [one] Note and its { $count } card deleted. - *[other] Note and its { $count } cards deleted. - } +studying-card-studied-in = + { $count -> + [one] { $count } card studied in + *[other] { $count } cards studied in + } +studying-minute = + { $count -> + [one] { $count } minute. + *[other] { $count } minutes. + } +studying-note-and-its-card-deleted = + { $count -> + [one] Note and its { $count } card deleted. + *[other] Note and its { $count } cards deleted. + } diff --git a/ftl/core/sync.ftl b/ftl/core/sync.ftl index 73ace090c..0b2f99d4b 100644 --- a/ftl/core/sync.ftl +++ b/ftl/core/sync.ftl @@ -1,5 +1,6 @@ ### Messages shown when synchronizing with AnkiWeb. + ## Media synchronization sync-media-added-count = Added: { $up }↑ { $down }↓ diff --git a/ftl/format.py b/ftl/format.py new file mode 100644 index 000000000..402ed92f1 --- /dev/null +++ b/ftl/format.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +""" +Parse and re-serialize ftl files to get them in a consistent form. +""" + +import os +import json +import glob +import sys +from typing import List +from fluent.syntax import parse, serialize +from fluent.syntax.ast import Junk + + +def check_file(path: str, fix: bool) -> bool: + "True if file is ok." + orig_text = open(path).read() + obj = parse(orig_text, with_spans=False) + # make sure there's no junk + for ent in obj.body: + if isinstance(ent, Junk): + raise Exception(f"file had junk! {path} {ent}") + # serialize + new_text = serialize(obj) + # make sure serializing did not introduce new junk + obj = parse(new_text, with_spans=False) + for ent in obj.body: + if isinstance(ent, Junk): + raise Exception(f"file introduced junk! {path} {ent}") + + if new_text == orig_text: + return True + + if fix: + print(f"Fixing {path}") + open(path, "w", newline="\n", encoding="utf8").write(new_text) + return True + else: + print(f"Bad formatting in {path}") + return False + + +def check_files(files: List[str], fix: bool) -> bool: + "True if files ok." + + found_bad = False + for path in files: + ok = check_file(path, fix) + if not ok: + found_bad = True + return True + + +if __name__ == "__main__": + template_root = os.environ["BUILD_WORKSPACE_DIRECTORY"] + template_files = glob.glob( + os.path.join(template_root, "ftl", "*", "*.ftl"), recursive=True + ) + + check_files(template_files, fix=True) diff --git a/ftl/format_check.py b/ftl/format_check.py new file mode 100644 index 000000000..9df5ed058 --- /dev/null +++ b/ftl/format_check.py @@ -0,0 +1,10 @@ +import os +import format +import sys +import glob + +template_root = os.path.dirname(sys.argv[1]) +template_files = glob.glob(os.path.join(template_root, "*", "*.ftl"), recursive=True) + +if not format.check_files(template_files, fix=False): + sys.exit(1) diff --git a/ftl/qt/preferences.ftl b/ftl/qt/preferences.ftl index 7e4249e16..7d64939a0 100644 --- a/ftl/qt/preferences.ftl +++ b/ftl/qt/preferences.ftl @@ -1,7 +1,6 @@ # shown instead of the 'night mode' option when night mode is forced on because # macOS is in dark mode preferences-dark-mode-active = macOS is in dark mode - preferences-dark-mode-disable = - To show Anki in light mode while macOS is in dark mode, please - see the Night Mode section of the manual. + To show Anki in light mode while macOS is in dark mode, please + see the Night Mode section of the manual. diff --git a/ftl/qt/profiles.ftl b/ftl/qt/profiles.ftl index 261b10397..924f126fc 100644 --- a/ftl/qt/profiles.ftl +++ b/ftl/qt/profiles.ftl @@ -3,7 +3,6 @@ profiles-folder-readme = to make backups easy. To tell Anki to use a different location, please see: - {$link} - + { $link } # will appear as 'Downgrade & Quit' profiles-downgrade-and-quit = Downgrade && Quit diff --git a/ftl/qt/qt-misc.ftl b/ftl/qt/qt-misc.ftl index bac7bc46c..f7bf66c60 100644 --- a/ftl/qt/qt-misc.ftl +++ b/ftl/qt/qt-misc.ftl @@ -61,7 +61,8 @@ qt-misc-would-you-like-to-download-it = Would you like to download it now? qt-misc-your-collection-file-appears-to-be = Your collection file appears to be corrupt. This can happen when the file is copied or moved while Anki is open, or when the collection is stored on a network or cloud drive. If problems persist after restarting your computer, please open an automatic backup from the profile screen. qt-misc-your-computers-storage-may-be-full = Your computer's storage may be full. Please delete some unneeded files, then try again. qt-misc-your-firewall-or-antivirus-program-is = Your firewall or antivirus program is preventing Anki from creating a connection to itself. Please add an exception for Anki. -qt-misc-second = { $count -> - [one] { $count } second - *[other] { $count } seconds - } +qt-misc-second = + { $count -> + [one] { $count } second + *[other] { $count } seconds + } From 1e8e4ee603f5b1f90b93b7a815c5b90c146bad10 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 22 Nov 2020 15:37:18 +1000 Subject: [PATCH 7/8] move other i18n scripts to ftl/ --- ftl/BUILD.bazel | 20 ++++++++++++++++++++ ftl/README.md | 3 +++ {scripts => ftl}/duplicate-string.py | 0 {scripts => ftl}/extract-strings.py | 0 scripts/synci18n.py => ftl/sync.py | 14 ++++++-------- {scripts => ftl}/transform-string.py | 0 scripts/BUILD.bazel | 12 ------------ 7 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 ftl/README.md rename {scripts => ftl}/duplicate-string.py (100%) rename {scripts => ftl}/extract-strings.py (100%) rename scripts/synci18n.py => ftl/sync.py (91%) rename {scripts => ftl}/transform-string.py (100%) diff --git a/ftl/BUILD.bazel b/ftl/BUILD.bazel index e9d227a19..d1448bca0 100644 --- a/ftl/BUILD.bazel +++ b/ftl/BUILD.bazel @@ -27,6 +27,26 @@ py_test( deps = [requirement("fluent-syntax")], ) +py_binary( + name = "sync", + srcs = ["sync.py"], + tags = ["manual"], +) + +py_binary( + name = "extract-strings", + srcs = ["extract-strings.py"], + tags = ["manual"], + deps = [requirement("fluent-syntax")], +) + +py_binary( + name = "transform-string", + srcs = ["transform-string.py"], + tags = ["manual"], + deps = [requirement("fluent-syntax")], +) + # export this file as a way of locating the top level folder in $(location ...) exports_files( ["BUILD.bazel"], diff --git a/ftl/README.md b/ftl/README.md new file mode 100644 index 000000000..589c1de40 --- /dev/null +++ b/ftl/README.md @@ -0,0 +1,3 @@ +Files related to Anki's translations. + +Please see https://translating.ankiweb.net/#/anki/developers diff --git a/scripts/duplicate-string.py b/ftl/duplicate-string.py similarity index 100% rename from scripts/duplicate-string.py rename to ftl/duplicate-string.py diff --git a/scripts/extract-strings.py b/ftl/extract-strings.py similarity index 100% rename from scripts/extract-strings.py rename to ftl/extract-strings.py diff --git a/scripts/synci18n.py b/ftl/sync.py similarity index 91% rename from scripts/synci18n.py rename to ftl/sync.py index b7378d6fb..f929ce935 100644 --- a/scripts/synci18n.py +++ b/ftl/sync.py @@ -10,11 +10,9 @@ import os import sys from typing import Optional, Tuple -repos_bzl = "repos.bzl" -working_folder = "../anki-i18n" - -if not os.path.exists(repos_bzl): - raise Exception("run from workspace root") +root = os.environ["BUILD_WORKSPACE_DIRECTORY"] +repos_bzl = os.path.join(root, "repos.bzl") +working_folder = os.path.join(root, "..", "anki-i18n") if not os.path.exists(working_folder): os.mkdir(working_folder) @@ -35,12 +33,12 @@ modules = [ Module( name="core", repo="git@github.com:ankitects/anki-core-i18n", - ftl=("ftl/core", "core/templates"), + ftl=(os.path.join(root, "ftl", "core"), "core/templates"), ), Module( name="qtftl", repo="git@github.com:ankitects/anki-desktop-ftl", - ftl=("ftl/qt", "desktop/templates"), + ftl=(os.path.join(root, "ftl", "qt"), "desktop/templates"), ), ] @@ -103,7 +101,7 @@ def update_repos_bzl(): out.append(line) open(path, "w").writelines(out) - commit_if_changed(".") + commit_if_changed(root) def commit_if_changed(folder: str): diff --git a/scripts/transform-string.py b/ftl/transform-string.py similarity index 100% rename from scripts/transform-string.py rename to ftl/transform-string.py diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 67de5adab..bfd938208 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -7,15 +7,3 @@ py_binary( stamp = 1, visibility = ["//visibility:public"], ) - -py_binary( - name = "extract-strings", - srcs = ["extract-strings.py"], - deps = [requirement("fluent-syntax")], -) - -py_binary( - name = "transform-string", - srcs = ["transform-string.py"], - deps = [requirement("fluent-syntax")], -) From 5e16c7655d2f73fc5621ae02373c769b46dcfa7f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 22 Nov 2020 16:00:25 +1000 Subject: [PATCH 8/8] update translations --- repos.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/repos.bzl b/repos.bzl index c5025a082..b5c273a9f 100644 --- a/repos.bzl +++ b/repos.bzl @@ -120,11 +120,11 @@ def register_repos(): # translations ################ - core_i18n_commit = "1a107ce14da4da13df27216704b5cc1709037aca" - core_i18n_shallow_since = "1606019752 +0000" + core_i18n_commit = "82530e22eb374bb745af9d7ae9af879441f5d909" + core_i18n_shallow_since = "1606023535 +1000" - qtftl_i18n_commit = "33d11d992f2a868249ac958c782fe977339968a4" - qtftl_i18n_shallow_since = "1605822423 +0000" + qtftl_i18n_commit = "72e91ac6c5e00855728fefacfe1366189055fb47" + qtftl_i18n_shallow_since = "1606023535 +1000" i18n_build_content = """ filegroup(