комментарии и сообщения переведены на английский

- комментарии, тексты ошибок, вывод CLI и сообщения тестов теперь на английском
- по-русски остались только литералы словаря ru и содержимое фикстур: это
  данные под проверкой, а не текст инструмента
- согласование числительных в итоге упростилось до английского plural
This commit is contained in:
av
2026-07-27 10:04:27 +03:00
parent 0b8cc125b3
commit b2d07ae55d
17 changed files with 548 additions and 524 deletions
+23 -23
View File
@@ -9,11 +9,11 @@ import (
"git.vakhrushev.me/av/convy/internal/suite"
)
// refRe ловит идентификатор правила: четыре заглавные латинские буквы, дефис,
// номер и необязательный номер строки таблицы.
// refRe catches a rule identifier: four uppercase Latin letters, a hyphen, a
// number and an optional table row number.
var refRe = regexp.MustCompile(`\b([A-Z]{4})-(\d+)(?:\.(\d+))?`)
// Ref — ссылка на правило, найденная в тексте.
// Ref is a reference to a rule found in the text.
type Ref struct {
Prefix string
Num int
@@ -22,13 +22,13 @@ type Ref struct {
Text string
}
// refsIn собирает ссылки в диапазоне строк документа. Инлайн-код вырезан: в
// бэктиках идентификатор стоит образцом записи, а не ссылкой на утверждение, —
// иначе строка «на конкретное правило ссылаются идентификатором (`SLOG-27`)»
// требовала бы, чтобы правило SLOG-27 существовало.
// refsIn collects the references in a range of lines. Inline code is cut out:
// inside backticks an identifier stands as a sample of the notation rather than
// as a reference to an assertion — otherwise the line "a rule is referred to by
// its identifier (`SLOG-27`)" would demand that rule SLOG-27 exist.
//
// Заголовки правил пропускаются: заголовок правило объявляет, а не ссылается
// на него, и разрешать его по манифесту не к чему.
// Rule headings are skipped: a heading declares a rule instead of referring to
// one, and there is nothing to resolve against the manifest.
func refsIn(d *doc.Document, from, to int) []Ref {
heading := make(map[int]bool, len(d.Rules))
for _, r := range d.Rules {
@@ -60,48 +60,48 @@ func refsInLine(n int, text string) []Ref {
return out
}
// checkLinks проверяет, что каждая ссылка разрешается. Неразрешённый
// идентификатор всегда ошибка: с заглушками на месте снятых правил третьего
// исхода нет — ссылка ведёт либо к правилу, либо к объяснению, почему его
// сняли (META-31, META-32).
// checkLinks verifies that every reference resolves. An unresolved identifier
// is always an error: with stubs standing in for retired rules there is no
// third outcome — a reference leads either to a rule or to the explanation of
// why it was retired (META-31, META-32).
func checkLinks(s *suite.Suite, d *doc.Document, rep *Report) {
for _, ref := range refsIn(d, d.Body, d.Len()) {
if strings.HasPrefix(ref.Prefix, "X") {
// Префикс потребителя: локальные правила чужого репозитория
// набору не видны и разрешению не подлежат.
// A consumer's prefix: the local rules of a foreign repository
// are invisible to the suite and are not to be resolved.
continue
}
if s.Manifest.PrefixRetired(ref.Prefix) {
rep.Errorf(Links, d.Path, ref.Line,
"ссылка %s ведёт на выбывший префикс %s", ref.Text, ref.Prefix)
"reference %s points at retired prefix %s", ref.Text, ref.Prefix)
continue
}
target, ok := s.ByPrefix[ref.Prefix]
if !ok {
if _, declared := s.Manifest.PathOf(ref.Prefix); declared {
// Файл объявлен, но не прочитан — о нём уже сказано
// проверкой манифеста, второй раз не повторяем.
// The file is declared but was not read — the manifest check
// has already said so, and saying it twice helps no one.
continue
}
rep.Errorf(Links, d.Path, ref.Line,
"ссылка %s ведёт на префикс %s, которого в манифесте набора нет", ref.Text, ref.Prefix)
"reference %s points at prefix %s, which the suite manifest does not declare", ref.Text, ref.Prefix)
continue
}
rule, ok := ruleByNum(target, ref.Num)
if !ok {
rep.Errorf(Links, d.Path, ref.Line,
"ссылка %s не разрешается: в %s правила с номером %d нет", ref.Text, target.Path, ref.Num)
"reference %s does not resolve: %s holds no rule numbered %d", ref.Text, target.Path, ref.Num)
continue
}
if ref.Sub > 0 && !mentions(target, rule, ref.Text) {
rep.Errorf(Links, d.Path, ref.Line,
"ссылка %s не разрешается: в области %s такой строки нет", ref.Text, rule.ID())
"reference %s does not resolve: the area of %s holds no such row", ref.Text, rule.ID())
}
}
}
// mentions отвечает, встречается ли текст ссылки в области правила. Так
// проверяется номер строки таблицы: сама строка его и несёт.
// mentions reports whether the text of a reference occurs inside the area of a
// rule. That is how a table row number is checked: the row itself carries it.
func mentions(d *doc.Document, rule doc.Rule, text string) bool {
for n := rule.Line; n <= rule.End; n++ {
if strings.Contains(d.Line(n), text) {