automatically format/check ftl files

This commit is contained in:
Damien Elmes 2020-11-22 15:30:59 +10:00
parent 0b848eae56
commit 52617511b0
19 changed files with 162 additions and 76 deletions

View file

@ -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"],

View file

@ -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

View file

@ -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.

View file

@ -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.
}

View file

@ -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.
}

View file

@ -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.
}

View file

@ -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
}

View file

@ -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"

View file

@ -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 }

View file

@ -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...

View file

@ -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.
}

View file

@ -6,3 +6,4 @@ search-note-modified = Note Modified
search-card-modified = Card Modified
##

View file

@ -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.
}

View file

@ -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
View 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
View 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)

View file

@ -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.

View file

@ -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

View file

@ -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
}