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

- комментарии, тексты ошибок, вывод 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
+42 -36
View File
@@ -10,9 +10,9 @@ import (
"git.vakhrushev.me/av/convy/internal/suite"
)
// checkSpread проверяет то, что относится к отъезду документа к потребителю.
// Применяется только к файлам конвенций: документ, которым набор ведёт себя
// сам, не уезжает никуда, и путь канона в нём законен.
// checkSpread checks what bears on a document travelling to a consumer. It
// applies to convention files only: the document the suite governs itself by
// travels nowhere, and a canon path inside it is lawful.
func checkSpread(s *suite.Suite, d *doc.Document, rep *Report) {
checkTopic(s, d, rep)
checkAxis(d, rep)
@@ -22,23 +22,25 @@ func checkSpread(s *suite.Suite, d *doc.Document, rep *Report) {
checkForeignTopicPrefix(s, d, rep)
}
// checkTopic сверяет тему из шапки с манифестом (META-28, META-29).
// checkTopic reconciles the topic from the front matter with the manifest
// (META-28, META-29).
func checkTopic(s *suite.Suite, d *doc.Document, rep *Report) {
topic := d.Front.Topic
at := d.Front.At["topic"]
switch {
case s.Manifest.TopicRetired(topic):
rep.Errorf(Spread, d.Path, at,
"тема %q значится среди выбывших: снятое имя другой теме не выдаётся", topic)
"topic %q is listed among the retired ones: a retired name is never handed to another topic", topic)
case !s.Manifest.TopicLive(topic):
rep.Errorf(Spread, d.Path, at,
"тема %q не объявлена в манифесте набора", topic)
"topic %q is not declared in the suite manifest", topic)
}
}
// checkAxis сверяет объявленную ось с путём файла. Ось объявляется в шапке, а
// не выводится из пути (META-38); но если директории осей используются,
// расхождение означает переезд файла без правки шапки.
// checkAxis reconciles the declared axis with the path of the file. An axis is
// declared in the front matter rather than derived from the path (META-38); but
// once axis directories are in use, a divergence means the file moved and the
// front matter did not.
func checkAxis(d *doc.Document, rep *Report) {
parts := strings.Split(path.Dir(d.Path), "/")
for i := 0; i+1 < len(parts); i++ {
@@ -59,13 +61,13 @@ func checkAxis(d *doc.Document, rep *Report) {
at = d.Front.At["prefix"]
}
rep.Errorf(Spread, d.Path, at,
"путь кладёт файл на ось %s=%s, а шапка объявляет %s=%q", key, parts[i+1], key, declared)
"the path puts the file on axis %s=%s, while the front matter declares %s=%q", key, parts[i+1], key, declared)
}
}
// checkExtends проверяет, что объявленная база существует и принадлежит той же
// теме. Ключ документирует связь слоёв для человека — документация, которая
// врёт, хуже отсутствующей.
// checkExtends verifies that the declared base exists and belongs to the same
// topic. The key documents the tie between layers for a human — and
// documentation that lies is worse than none.
func checkExtends(s *suite.Suite, d *doc.Document, rep *Report) {
if d.Front.Extends == "" {
return
@@ -74,22 +76,23 @@ func checkExtends(s *suite.Suite, d *doc.Document, rep *Report) {
target := resolveExtends(s, d.Front.Extends)
if target == nil {
rep.Errorf(Spread, d.Path, at,
"extends указывает на %q, а такого файла в наборе нет", d.Front.Extends)
"extends points at %q, and the suite holds no such file", d.Front.Extends)
return
}
if target.Front.Topic != d.Front.Topic {
rep.Errorf(Spread, d.Path, at,
"extends указывает на %q с темой %q, а файл несёт тему %q: слои одной темы объявляют одно имя",
"extends points at %q with topic %q, while the file carries topic %q: the layers of one topic declare one name",
d.Front.Extends, target.Front.Topic, d.Front.Topic)
}
if target.Front.Axis() {
rep.Errorf(Spread, d.Path, at,
"extends указывает на %q, а это не базовый слой: у него объявлена ось", d.Front.Extends)
"extends points at %q, which is not a base layer: it declares an axis", d.Front.Extends)
}
}
// resolveExtends ищет документ по пути, записанному в extends. Путь даётся от
// директории конвенций, поэтому пробуем и его, и путь от корня набора.
// resolveExtends looks up the document at the path written in extends. The path
// is given from the conventions directory, so both it and a path from the root
// of the suite are tried.
func resolveExtends(s *suite.Suite, ref string) *doc.Document {
ref = path.Clean(strings.TrimPrefix(ref, "./"))
for _, d := range s.Docs {
@@ -100,9 +103,10 @@ func resolveExtends(s *suite.Suite, ref string) *doc.Document {
return nil
}
// checkMechanized ищет метку механизации в тексте конвенции. Механизирована
// норма или нет — свойство репозитория, а не набора, поэтому место отметки —
// локальная часть копии (META-7).
// checkMechanized looks for the mark of mechanization in the text of a
// convention. Whether a norm is mechanized is a property of a repository rather
// than of the suite, so the place of the mark is the local part of the copy
// (META-7).
func checkMechanized(s *suite.Suite, d *doc.Document, rep *Report) {
word := s.Vocab.MarkWord(lang.Mechanized)
if word == "" {
@@ -115,21 +119,22 @@ func checkMechanized(s *suite.Suite, d *doc.Document, rep *Report) {
}
if containsWord(text, word) {
rep.Errorf(Spread, d.Path, n,
"метка %s стоит в тексте конвенции: её место — запись о механизации в локальной части копии", word)
"the %s mark stands in the text of a convention: its place is the note of mechanization in the local part of the copy", word)
}
return true
})
}
// mdPathRe ловит то, что выглядит путём к файлу набора.
// mdPathRe catches what looks like a path to a file of the suite.
var mdPathRe = regexp.MustCompile(`[\w./-]+\.md`)
// checkCanonPaths ищет путь файла канона в тексте конвенции (META-21). В
// репозитории потребителя конвенция лежит собранной, слои одной темы — секции
// одного файла, и путь `lang/go/logging.md` там не существует: ссылка на него
// умирает при сборке, причём молча — текст остаётся связным.
// checkCanonPaths looks for the path of a canon file in the text of a
// convention (META-21). In a consumer's repository a convention lies assembled,
// the layers of one topic are sections of one file, and the path
// `lang/go/logging.md` does not exist there: a reference to it dies on assembly,
// and dies in silence — the text stays coherent.
//
// Инлайн-код здесь не вырезается: путь в бэктиках — тоже путь.
// Inline code is not cut out here: a path in backticks is still a path.
func checkCanonPaths(s *suite.Suite, d *doc.Document, rep *Report) {
for n := d.Body; n <= d.Len(); n++ {
if d.Fenced(n) {
@@ -141,16 +146,17 @@ func checkCanonPaths(s *suite.Suite, d *doc.Document, rep *Report) {
continue
}
rep.Errorf(Spread, d.Path, n,
"в тексте стоит путь файла канона %q: ссылаются именем темы или идентификатором правила", candidate)
"the text holds the canon file path %q: refer by the name of a topic or the identifier of a rule", candidate)
}
}
}
// checkForeignTopicPrefix ищет префикс чужой темы в блоке нормы (META-20).
// Норму правила можно исполнить, имея один этот файл: репозиторий подписывается
// на произвольное подмножество конвенций, и графа зависимостей у него нет.
// Префикс базового слоя своей темы там допустим (META-24) — собранный файл
// начинается с него независимо от выбранных языка и стека.
// checkForeignTopicPrefix looks for the prefix of a foreign topic inside a norm
// block (META-20). The norm of a rule must be executable holding this one file:
// a repository subscribes to an arbitrary subset of the conventions, and it has
// no dependency graph by construction. The prefix of the base layer of its own
// topic is allowed there (META-24) — an assembled file starts with that layer
// whatever language and stack were chosen.
func checkForeignTopicPrefix(s *suite.Suite, d *doc.Document, rep *Report) {
own := s.Prefix(d)
for _, r := range d.Rules {
@@ -165,13 +171,13 @@ func checkForeignTopicPrefix(s *suite.Suite, d *doc.Document, rep *Report) {
}
if target.Front.Topic != d.Front.Topic {
rep.Errorf(Spread, d.Path, ref.Line,
"норма %s ссылается на %s из чужой темы %q: наружу смотрит только обоснование",
"the norm of %s refers to %s from the foreign topic %q: only the rationale looks outward",
r.ID(), ref.Text, target.Front.Topic)
continue
}
if target.Front.Axis() {
rep.Errorf(Spread, d.Path, ref.Line,
"норма %s ссылается на %s — слой своей темы, но не базовый: в копию он попадает по манифесту, и гарантии, что он рядом, нет",
"the norm of %s refers to %s, a layer of its own topic but not the base one: that layer reaches the copy through the manifest, so there is no guarantee it stands nearby",
r.ID(), ref.Text)
}
}