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( filegroup(
name = "ftl", name = "ftl",
srcs = [ srcs = [
@ -7,6 +9,24 @@ filegroup(
visibility = ["//rslib:__subpackages__"], 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 ...) # export this file as a way of locating the top level folder in $(location ...)
exports_files( exports_files(
["BUILD.bazel"], ["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-relearn = Relearn
card-stats-review-log-type-filtered = Filtered card-stats-review-log-type-filtered = Filtered
card-stats-review-log-type-manual = Manual card-stats-review-log-type-manual = Manual

View file

@ -4,39 +4,27 @@
# Label of link users can click on # Label of link users can click on
card-template-rendering-more-info = More information card-template-rendering-more-info = More information
card-template-rendering-front-side-problem = Front template has a problem: card-template-rendering-front-side-problem = Front template has a problem:
card-template-rendering-back-side-problem = Back template has a problem: card-template-rendering-back-side-problem = Back template has a problem:
# when the user forgot to close a field reference, # when the user forgot to close a field reference,
# eg, Missing '}}' in '{{Field' # eg, Missing '}}' in '{{Field'
card-template-rendering-no-closing-brackets = card-template-rendering-no-closing-brackets = Missing '{ $missing }' in '{ $tag }'
Missing '{$missing}' in '{$tag}'
# when the user opened a conditional, but forgot to close it # when the user opened a conditional, but forgot to close it
# eg, Missing '{{/Conditional}}' # eg, Missing '{{/Conditional}}'
card-template-rendering-conditional-not-closed = card-template-rendering-conditional-not-closed = Missing '{ $missing }'
Missing '{$missing}'
# when the user closed the wrong conditional # when the user closed the wrong conditional
# eg, Found '{{/Something}}', but expected '{{/SomethingElse}}' # eg, Found '{{/Something}}', but expected '{{/SomethingElse}}'
card-template-rendering-wrong-conditional-closed = card-template-rendering-wrong-conditional-closed = Found '{ $found }', but expected '{ $expected }'
Found '{$found}', but expected '{$expected}'
# when the user closed a conditional that wasn't open # when the user closed a conditional that wasn't open
# eg, Found '{{/Something}}', but missing '{{#Something}}' or '{{^Something}}' # eg, Found '{{/Something}}', but missing '{{#Something}}' or '{{^Something}}'
card-template-rendering-conditional-not-open = card-template-rendering-conditional-not-open = Found '{ $found }', but missing '{ $missing1 }' or '{ $missing2 }'
Found '{$found}', but missing '{$missing1}' or '{$missing2}'
# when the user referenced a field that doesn't exist # when the user referenced a field that doesn't exist
# eg, Found '{{Field}}', but there is not field called 'Field' # eg, Found '{{Field}}', but there is not field called 'Field'
card-template-rendering-no-such-field = card-template-rendering-no-such-field = Found '{ $found }', but there is no field called '{ $field }'
Found '{$found}', but there is no field called '{$field}'
# This message is shown when the front side of the card is blank, # This message is shown when the front side of the card is blank,
# either due to a badly-designed template, or because required fields # either due to a badly-designed template, or because required fields
# are missing. # are missing.
card-template-rendering-empty-front = The front of this card is blank. card-template-rendering-empty-front = The front of this card is blank.
card-template-rendering-missing-cloze =
card-template-rendering-missing-cloze = No cloze { $number } found on card. No cloze { $number } found on card.
Please either add a cloze deletion, or use the Empty Cards tool. 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 = Study
decks-study-deck = Study Deck 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-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. [one] It has { $count } card.
*[other] It has { $count } cards. *[other] It has { $count } cards.
} }

View file

@ -1,11 +1,11 @@
empty-cards-for-note-type = Empty cards for { $notetype }: empty-cards-for-note-type = Empty cards for { $notetype }:
empty-cards-count-line = empty-cards-count-line = { $empty_count } of { $existing_count } cards empty ({ $template_names }).
{ $empty_count } of { $existing_count } cards empty ({ $template_names }).
empty-cards-window-title = Empty Cards empty-cards-window-title = Empty Cards
empty-cards-preserve-notes-checkbox = Keep notes with no valid cards empty-cards-preserve-notes-checkbox = Keep notes with no valid cards
empty-cards-delete-button = Delete empty-cards-delete-button = Delete
empty-cards-not-found = No empty cards. empty-cards-not-found = No empty cards.
empty-cards-deleted-count = Deleted { $cards -> empty-cards-deleted-count =
Deleted { $cards ->
[one] { $cards } card. [one] { $cards } card.
*[other] { $cards } cards. *[other] { $cards } cards.
} }

View file

@ -15,15 +15,18 @@ exporting-include-scheduling-information = Include scheduling information
exporting-include-tags = Include tags exporting-include-tags = Include tags
exporting-notes-in-plain-text = Notes in Plain Text exporting-notes-in-plain-text = Notes in Plain Text
exporting-selected-notes = Selected Notes exporting-selected-notes = Selected Notes
exporting-card-exported = { $count -> exporting-card-exported =
{ $count ->
[one] { $count } card exported. [one] { $count } card exported.
*[other] { $count } cards exported. *[other] { $count } cards exported.
} }
exporting-exported-media-file = { $count -> exporting-exported-media-file =
{ $count ->
[one] Exported { $count } media file [one] Exported { $count } media file
*[other] Exported { $count } media files *[other] Exported { $count } media files
} }
exporting-note-exported = { $count -> exporting-note-exported =
{ $count ->
[one] { $count } note exported. [one] { $count } note exported.
*[other] { $count } notes exported. *[other] { $count } notes exported.
} }

View file

@ -1,4 +1,5 @@
findreplace-notes-updated = { $total -> findreplace-notes-updated =
{ $total ->
[one] { $changed } of { $total } note updated [one] { $changed } of { $total } note updated
*[other] { $changed } of { $total } notes updated *[other] { $changed } of { $total } notes updated
} }

View file

@ -1,7 +1,6 @@
## Shown at the top of the media check screen ## Shown at the top of the media check screen
media-check-window-title = Check Media media-check-window-title = Check Media
# the number of files, and the total space used by files # the number of files, and the total space used by files
# that have been moved to the trash folder. eg, # that have been moved to the trash folder. eg,
# "Trash folder: 3 files, 3.47MB" # "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-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-proxy-auth = Your proxy requires authentication.
network-other = A network error occurred. 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-1-name = Card 1
notetypes-card-2-name = Card 2 notetypes-card-2-name = Card 2
notetypes-add = Add: { $val } notetypes-add = Add: { $val }
notetypes-add-note-type = Add Note Type notetypes-add-note-type = Add Note Type
notetypes-cards = Cards... notetypes-cards = Cards...

View file

@ -138,7 +138,8 @@ scheduling-steps-must-be-numbers = Steps must be numbers.
scheduling-tag-only = Tag Only scheduling-tag-only = Tag Only
scheduling-the-default-configuration-cant-be-removed = The default configuration can't be removed. 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-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. [one] { $count } deck updated.
*[other] { $count } decks updated. *[other] { $count } decks updated.
} }

View file

@ -6,3 +6,4 @@ search-note-modified = Note Modified
search-card-modified = Card 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-unbury = Unbury
studying-what-would-you-like-to-unbury = What would you like to 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-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 [one] { $count } card studied in
*[other] { $count } cards studied in *[other] { $count } cards studied in
} }
studying-minute = { $count -> studying-minute =
{ $count ->
[one] { $count } minute. [one] { $count } minute.
*[other] { $count } minutes. *[other] { $count } minutes.
} }
studying-note-and-its-card-deleted = { $count -> studying-note-and-its-card-deleted =
{ $count ->
[one] Note and its { $count } card deleted. [one] Note and its { $count } card deleted.
*[other] Note and its { $count } cards deleted. *[other] Note and its { $count } cards deleted.
} }

View file

@ -1,5 +1,6 @@
### Messages shown when synchronizing with AnkiWeb. ### Messages shown when synchronizing with AnkiWeb.
## Media synchronization ## Media synchronization
sync-media-added-count = Added: { $up }↑ { $down }↓ 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 # shown instead of the 'night mode' option when night mode is forced on because
# macOS is in dark mode # macOS is in dark mode
preferences-dark-mode-active = macOS is in dark mode preferences-dark-mode-active = macOS is in dark mode
preferences-dark-mode-disable = preferences-dark-mode-disable =
To show Anki in light mode while macOS is in dark mode, please To show Anki in light mode while macOS is in dark mode, please
see the Night Mode section of the manual. see the Night Mode section of the manual.

View file

@ -4,6 +4,5 @@ profiles-folder-readme =
please see: please see:
{ $link } { $link }
# will appear as 'Downgrade & Quit' # will appear as 'Downgrade & Quit'
profiles-downgrade-and-quit = 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-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-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-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 [one] { $count } second
*[other] { $count } seconds *[other] { $count } seconds
} }