mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
automatically format/check ftl files
This commit is contained in:
parent
0b848eae56
commit
52617511b0
19 changed files with 162 additions and 76 deletions
|
@ -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"],
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
card-template-rendering-missing-cloze =
|
||||
No cloze { $number } found on card.
|
||||
Please either add a cloze deletion, or use the Empty Cards tool.
|
||||
|
|
|
@ -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 ->
|
||||
decks-it-has-card =
|
||||
{ $count ->
|
||||
[one] It has { $count } card.
|
||||
*[other] It has { $count } cards.
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
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 ->
|
||||
empty-cards-deleted-count =
|
||||
Deleted { $cards ->
|
||||
[one] { $cards } card.
|
||||
*[other] { $cards } cards.
|
||||
}
|
||||
|
|
|
@ -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 ->
|
||||
exporting-card-exported =
|
||||
{ $count ->
|
||||
[one] { $count } card exported.
|
||||
*[other] { $count } cards exported.
|
||||
}
|
||||
exporting-exported-media-file = { $count ->
|
||||
exporting-exported-media-file =
|
||||
{ $count ->
|
||||
[one] Exported { $count } media file
|
||||
*[other] Exported { $count } media files
|
||||
}
|
||||
exporting-note-exported = { $count ->
|
||||
exporting-note-exported =
|
||||
{ $count ->
|
||||
[one] { $count } note exported.
|
||||
*[other] { $count } notes exported.
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
findreplace-notes-updated = { $total ->
|
||||
findreplace-notes-updated =
|
||||
{ $total ->
|
||||
[one] { $changed } of { $total } note updated
|
||||
*[other] { $changed } of { $total } notes updated
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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 ->
|
||||
scheduling-deck-updated =
|
||||
{ $count ->
|
||||
[one] { $count } deck updated.
|
||||
*[other] { $count } decks updated.
|
||||
}
|
||||
|
|
|
@ -6,3 +6,4 @@ search-note-modified = Note Modified
|
|||
search-card-modified = Card Modified
|
||||
|
||||
##
|
||||
|
||||
|
|
|
@ -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 ->
|
||||
studying-card-studied-in =
|
||||
{ $count ->
|
||||
[one] { $count } card studied in
|
||||
*[other] { $count } cards studied in
|
||||
}
|
||||
studying-minute = { $count ->
|
||||
studying-minute =
|
||||
{ $count ->
|
||||
[one] { $count } minute.
|
||||
*[other] { $count } minutes.
|
||||
}
|
||||
studying-note-and-its-card-deleted = { $count ->
|
||||
studying-note-and-its-card-deleted =
|
||||
{ $count ->
|
||||
[one] Note and its { $count } card deleted.
|
||||
*[other] Note and its { $count } cards deleted.
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
### Messages shown when synchronizing with AnkiWeb.
|
||||
|
||||
|
||||
## Media synchronization
|
||||
|
||||
sync-media-added-count = Added: { $up }↑ { $down }↓
|
||||
|
|
62
ftl/format.py
Normal file
62
ftl/format.py
Normal file
|
@ -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)
|
10
ftl/format_check.py
Normal file
10
ftl/format_check.py
Normal file
|
@ -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)
|
|
@ -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.
|
||||
|
|
|
@ -4,6 +4,5 @@ profiles-folder-readme =
|
|||
please see:
|
||||
|
||||
{ $link }
|
||||
|
||||
# will appear as 'Downgrade & Quit'
|
||||
profiles-downgrade-and-quit = Downgrade && Quit
|
||||
|
|
|
@ -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 ->
|
||||
qt-misc-second =
|
||||
{ $count ->
|
||||
[one] { $count } second
|
||||
*[other] { $count } seconds
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue