diff --git a/frontend/public/hosts/talafmt/robots.txt b/frontend/public/hosts/talafmt/robots.txt new file mode 100644 index 0000000..150b53e --- /dev/null +++ b/frontend/public/hosts/talafmt/robots.txt @@ -0,0 +1,64 @@ +# SPDX-FileCopyrightText: 2026 Progmasoft +# SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 + +User-agent: Googlebot +Allow: / + +User-agent: Google-Extended +Allow: / + +User-agent: OAI-SearchBot +Allow: / + +User-agent: ChatGPT-User +Allow: / + +User-agent: GPTBot +Disallow: / + +User-agent: Claude-SearchBot +Allow: / + +User-agent: Claude-User +Allow: / + +User-agent: ClaudeBot +Allow: / + +User-agent: PerplexityBot +Disallow: / + +User-agent: Perplexity-User +Disallow: / + +User-agent: Bytespider +Disallow: / + +User-agent: CCBot +Disallow: / + +User-agent: meta-externalagent +Disallow: / + +User-agent: meta-externalfetcher +Disallow: / + +User-agent: FacebookBot +Disallow: / + +User-agent: DuckAssistBot +Allow: / + +User-agent: Amazonbot +Disallow: / + +User-agent: Google-CloudVertexBot +Disallow: / + +User-agent: MistralAI-User +Disallow: / + +User-agent: * +Allow: / + +Sitemap: https://talafmt.tala.run/sitemap.xml diff --git a/frontend/public/hosts/talafmt/sitemap.xml b/frontend/public/hosts/talafmt/sitemap.xml new file mode 100644 index 0000000..afcb530 --- /dev/null +++ b/frontend/public/hosts/talafmt/sitemap.xml @@ -0,0 +1,20 @@ + + + + + + https://talafmt.tala.run/ + monthly + 1.0 + + + https://talafmt.tala.run/docs/command-line + monthly + 0.8 + + + https://talafmt.tala.run/docs/layout + monthly + 0.8 + + diff --git a/frontend/public/hosts/talalint/robots.txt b/frontend/public/hosts/talalint/robots.txt new file mode 100644 index 0000000..4fadfbd --- /dev/null +++ b/frontend/public/hosts/talalint/robots.txt @@ -0,0 +1,64 @@ +# SPDX-FileCopyrightText: 2026 Progmasoft +# SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 + +User-agent: Googlebot +Allow: / + +User-agent: Google-Extended +Allow: / + +User-agent: OAI-SearchBot +Allow: / + +User-agent: ChatGPT-User +Allow: / + +User-agent: GPTBot +Disallow: / + +User-agent: Claude-SearchBot +Allow: / + +User-agent: Claude-User +Allow: / + +User-agent: ClaudeBot +Allow: / + +User-agent: PerplexityBot +Disallow: / + +User-agent: Perplexity-User +Disallow: / + +User-agent: Bytespider +Disallow: / + +User-agent: CCBot +Disallow: / + +User-agent: meta-externalagent +Disallow: / + +User-agent: meta-externalfetcher +Disallow: / + +User-agent: FacebookBot +Disallow: / + +User-agent: DuckAssistBot +Allow: / + +User-agent: Amazonbot +Disallow: / + +User-agent: Google-CloudVertexBot +Disallow: / + +User-agent: MistralAI-User +Disallow: / + +User-agent: * +Allow: / + +Sitemap: https://talalint.tala.run/sitemap.xml diff --git a/frontend/public/hosts/talalint/sitemap.xml b/frontend/public/hosts/talalint/sitemap.xml new file mode 100644 index 0000000..3bbc63f --- /dev/null +++ b/frontend/public/hosts/talalint/sitemap.xml @@ -0,0 +1,20 @@ + + + + + + https://talalint.tala.run/ + monthly + 1.0 + + + https://talalint.tala.run/docs/command-line + monthly + 0.8 + + + https://talalint.tala.run/docs/checks + monthly + 0.8 + + diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 79a418b..8b46570 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -7,7 +7,7 @@ import { RouterLink, RouterView } from "vue-router"; import { localeLabels } from "./locales"; import { locale, supportedLocales, theme } from "./preferences"; import { contentRoutes } from "./content/routes"; -import { forumUrl, site, siteHome, siteTopics, siteUrl, type Site } from "./site"; +import { forumUrl, site, siteBrand, siteHome, sites, siteTopics, siteUrl, type Site } from "./site"; const labels = { "en-US": { @@ -62,12 +62,12 @@ const labels = { const copy = computed(() => labels[locale.value]); const hostname = window.location.hostname; -const brand = { language: "Tala", talac: "Talac", tazel: "Tazel" }[site]; -// The other two sites are linked by their names, which read the same in every language. -const siblings = (["language", "talac", "tazel"] as const) +const brand = siteBrand[site]; +// The other sites are linked by their names, which read the same in every language. +const siblings = sites .filter((other): other is Site => other !== site) .map((other) => ({ - label: { language: "Tala", talac: "Talac", tazel: "Tazel" }[other], + label: siteBrand[other], href: siteUrl(other, siteHome[other], hostname), })); diff --git a/frontend/src/components/DocShell.vue b/frontend/src/components/DocShell.vue index ac9ef67..5cdf934 100644 --- a/frontend/src/components/DocShell.vue +++ b/frontend/src/components/DocShell.vue @@ -6,7 +6,7 @@ import { computed, nextTick, onMounted, ref, watch } from "vue"; import { RouterLink } from "vue-router"; import { sidebarFor } from "../content/routes"; import { locale } from "../preferences"; -import { site } from "../site"; +import { site, siteBrand } from "../site"; /** * The frame of every documentation page: the topics of the site on the left, the page in a readable column, the @@ -50,7 +50,7 @@ const labels = { }, } as const; const copy = computed(() => labels[locale.value]); -const brand = { language: "Tala", talac: "Talac", tazel: "Tazel" }[site]; +const brand = siteBrand[site]; const sidebar = computed(() => sidebarFor(site, locale.value)); const position = computed(() => sidebar.value.findIndex((entry) => entry.path === props.path)); diff --git a/frontend/src/content/landing.ts b/frontend/src/content/landing.ts index ca76dd9..553e9f1 100644 --- a/frontend/src/content/landing.ts +++ b/frontend/src/content/landing.ts @@ -3,6 +3,8 @@ import type { Locale } from "../locales"; import type { Site } from "../site"; +import { talafmtLanding } from "./talafmt.ts"; +import { talalintLanding } from "./talalint.ts"; /** One tab of a "Why" section: a strength, a sentence about it and a sample that shows it. */ export type WhyTab = { label: string; caption: string; file: string; code: string }; @@ -750,4 +752,6 @@ export const landing: Record> = { copied: "הועתק", }, }, + talafmt: talafmtLanding, + talalint: talalintLanding, }; diff --git a/frontend/src/content/routes.ts b/frontend/src/content/routes.ts index 515d310..393bd0d 100644 --- a/frontend/src/content/routes.ts +++ b/frontend/src/content/routes.ts @@ -5,6 +5,8 @@ import type { Locale } from "../locales"; import { siteTopics, type Site } from "../site.ts"; import { syntaxRoutes } from "./syntax.ts"; import { talacRoutes } from "./talac.ts"; +import { talafmtRoutes } from "./talafmt.ts"; +import { talalintRoutes } from "./talalint.ts"; import { tazelRoutes } from "./tazel.ts"; import type { DocRoute } from "./types"; @@ -13,6 +15,8 @@ export const contentRoutes: Record = { language: syntaxRoutes, talac: talacRoutes, tazel: tazelRoutes, + talafmt: talafmtRoutes, + talalint: talalintRoutes, }; // The two hand-built pages of the language site name themselves in their own components; the sidebar of a content diff --git a/frontend/src/content/talafmt.ts b/frontend/src/content/talafmt.ts new file mode 100644 index 0000000..6d549ca --- /dev/null +++ b/frontend/src/content/talafmt.ts @@ -0,0 +1,434 @@ +// SPDX-FileCopyrightText: 2026 Progmasoft +// SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 + +import type { Locale } from "../locales"; +import type { LandingText, WhyTab } from "./landing"; +import type { DocRoute, DocTopic } from "./types"; + +// talafmt.tala.run. The facts follow the README of Progmasoft/talafmt, version 0.1.0; commands are the same in every +// language and only the prose is translated. +const inPlace = `talafmt Program.tala Library.tala`; +const check = `talafmt --check Program.tala Library.tala`; +const reports = `talafmt --emit=stdout Program.tala +talafmt --emit=json Program.tala`; +const tazel = `tazel fmt +tazel fmt -- --check`; +const usage = `talafmt Program.tala Library.tala +talafmt --check Program.tala Library.tala +talafmt --emit=stdout Program.tala +talafmt --help +talafmt --version`; +const repository = "https://github.com/Progmasoft/talafmt"; + +type TabWords = Record<"place" | "check" | "reports" | "tazel", { label: string; caption: string }>; + +function tabs(words: TabWords): WhyTab[] { + return [ + { ...words.place, file: "terminal", code: inPlace }, + { ...words.check, file: "terminal", code: check }, + { ...words.reports, file: "terminal", code: reports }, + { ...words.tazel, file: "terminal", code: tazel }, + ]; +} + +const next = (source: string) => [ + { label: "Tala", href: "https://tala.run/" }, + { label: "Talalint", href: "https://talalint.tala.run/" }, + { label: source, href: repository }, +]; + +export const talafmtLanding: Record = { + "en-US": { + title: "Talafmt — The Tala formatter", + description: + "talafmt gives every Tala file one layout: indentation, line endings, trailing whitespace and the final newline, never the text inside strings and comments.", + headline: "One layout for every Tala file.", + lead: "talafmt reads each file with the Tala lexer and parser before it changes anything, then evens out indentation, line endings, trailing whitespace and the final newline.", + primary: { label: "Command line", to: "/docs/command-line" }, + secondary: { label: "What it changes", to: "/docs/layout" }, + whyHeading: "Why Talafmt?", + tabs: tabs({ + place: { + label: "In place", + caption: + "Without options talafmt formats every file it is given in place and prints nothing.", + }, + check: { + label: "In continuous integration", + caption: "--check changes nothing and fails when any file would change.", + }, + reports: { + label: "Reports", + caption: + "stdout, coverage, checkstyle and json write the result to standard output and leave the files alone.", + }, + tazel: { + label: "From Tazel", + caption: "Tazel runs talafmt over the whole project; options for talafmt follow --.", + }, + }), + nextHeading: "Next", + next: next("Source"), + copy: "Copy", + copied: "Copied", + }, + "de-DE": { + title: "Talafmt — Der Formatierer von Tala", + description: + "talafmt gibt jeder Tala-Datei ein Layout: Einrückung, Zeilenenden, Leerzeichen am Zeilenende und den letzten Zeilenumbruch, nie den Text in Strings und Kommentaren.", + headline: "Ein Layout für jede Tala-Datei.", + lead: "talafmt liest jede Datei mit Lexer und Parser von Tala, bevor es etwas ändert, und gleicht dann Einrückung, Zeilenenden, Leerzeichen am Zeilenende und den letzten Zeilenumbruch an.", + primary: { label: "Befehlszeile", to: "/docs/command-line" }, + secondary: { label: "Was es ändert", to: "/docs/layout" }, + whyHeading: "Warum Talafmt?", + tabs: tabs({ + place: { + label: "Direkt in der Datei", + caption: + "Ohne Optionen formatiert talafmt jede übergebene Datei direkt und gibt nichts aus.", + }, + check: { + label: "In der kontinuierlichen Integration", + caption: "--check ändert nichts und schlägt fehl, wenn sich eine Datei ändern würde.", + }, + reports: { + label: "Berichte", + caption: + "stdout, coverage, checkstyle und json schreiben das Ergebnis in die Standardausgabe und lassen die Dateien in Ruhe.", + }, + tazel: { + label: "Aus Tazel", + caption: + "Tazel führt talafmt über das ganze Projekt aus; Optionen für talafmt folgen nach --.", + }, + }), + nextHeading: "Weiter", + next: next("Quellcode"), + copy: "Kopieren", + copied: "Kopiert", + }, + "ru-RU": { + title: "Talafmt — форматировщик Tala", + description: + "talafmt приводит каждый файл Tala к одному оформлению: отступы, концы строк, пробелы в конце строк и последний перевод строки, но никогда не текст внутри строк и комментариев.", + headline: "Единое оформление для каждого файла Tala.", + lead: "talafmt читает каждый файл лексером и парсером Tala, прежде чем что-либо менять, а затем выравнивает отступы, концы строк, пробелы в конце строк и последний перевод строки.", + primary: { label: "Командная строка", to: "/docs/command-line" }, + secondary: { label: "Что он меняет", to: "/docs/layout" }, + whyHeading: "Почему Talafmt?", + tabs: tabs({ + place: { + label: "На месте", + caption: + "Без параметров talafmt форматирует каждый переданный файл на месте и ничего не выводит.", + }, + check: { + label: "В непрерывной интеграции", + caption: + "--check ничего не меняет и завершается с ошибкой, если какой-либо файл изменился бы.", + }, + reports: { + label: "Отчёты", + caption: + "stdout, coverage, checkstyle и json пишут результат в стандартный вывод и не трогают файлы.", + }, + tazel: { + label: "Из Tazel", + caption: "Tazel запускает talafmt для всего проекта; параметры для talafmt идут после --.", + }, + }), + nextHeading: "Дальше", + next: next("Исходный код"), + copy: "Копировать", + copied: "Скопировано", + }, + "he-IL": { + title: "Talafmt — מעצב הקוד של Tala", + description: + "talafmt נותן לכל קובץ Tala פריסה אחת: הזחה, סופי שורה, רווחים בסוף שורה והשורה החדשה האחרונה, ולעולם לא את הטקסט שבתוך מחרוזות והערות.", + headline: "פריסה אחת לכל קובץ Tala.", + lead: "talafmt קורא כל קובץ עם המנתח הלקסיקלי והתחבירי של Tala לפני שהוא משנה משהו, ואז מיישר הזחה, סופי שורה, רווחים בסוף שורה והשורה החדשה האחרונה.", + primary: { label: "שורת הפקודה", to: "/docs/command-line" }, + secondary: { label: "מה הוא משנה", to: "/docs/layout" }, + whyHeading: "למה Talafmt?", + tabs: tabs({ + place: { + label: "במקום", + caption: "בלי אפשרויות talafmt מעצב במקום כל קובץ שניתן לו ולא מדפיס דבר.", + }, + check: { + label: "באינטגרציה רציפה", + caption: "‏--check לא משנה דבר ונכשל כשקובץ כלשהו היה משתנה.", + }, + reports: { + label: "דוחות", + caption: + "stdout,‏ coverage,‏ checkstyle ו־json כותבים את התוצאה לפלט התקני ומשאירים את הקבצים כמו שהם.", + }, + tazel: { + label: "מתוך Tazel", + caption: "Tazel מריץ את talafmt על כל הפרויקט; אפשרויות ל־talafmt באות אחרי ‎--.", + }, + }), + nextHeading: "הלאה", + next: next("קוד מקור"), + copy: "העתקה", + copied: "הועתק", + }, +}; + +const optionTerms = (d: { + inputs: string; + check: string; + emit: string; + help: string; + version: string; +}) => [ + { term: "Program.tala Library.tala …", detail: d.inputs }, + { term: "--check", detail: d.check }, + { term: "--emit=files|stdout|coverage|checkstyle|json", detail: d.emit }, + { term: "--help, -h", detail: d.help }, + { term: "--version, -v", detail: d.version }, +]; + +const commandLine: DocTopic = { + "en-US": { + nav: "Command line", + title: "Command line · Talafmt", + description: + "The command line of talafmt, the Tala formatter: inputs, --check, --emit and exit statuses.", + section: "TALAFMT / COMMAND LINE", + heading: "The formatter and its command line", + lead: "talafmt takes Tala sources and formats them in place. It formats nothing it cannot read: every input is checked with the Tala lexer and parser first.", + blocks: [ + { kind: "code", code: usage }, + { + kind: "terms", + items: optionTerms({ + inputs: + "One or more sources. The project configuration is evaluated once for all of them.", + check: "Changes nothing; the exit status fails when any source would change.", + emit: "files, the default, writes the sources in place. The others write the formatted source or a report to standard output and leave the files alone.", + help: "Prints the help.", + version: "Prints the version of talafmt.", + }), + }, + { kind: "heading", text: "How the command line is read" }, + { + kind: "text", + text: "A typed parser written by hand reads the command line. A line it cannot read ends with exit status 2, before any file is touched.", + }, + ], + }, + "de-DE": { + nav: "Befehlszeile", + title: "Befehlszeile · Talafmt", + description: + "Die Befehlszeile von talafmt, dem Formatierer von Tala: Eingaben, --check, --emit und Exit-Status.", + section: "TALAFMT / BEFEHLSZEILE", + heading: "Der Formatierer und seine Befehlszeile", + lead: "talafmt nimmt Tala-Quellen und formatiert sie direkt. Es formatiert nichts, was es nicht lesen kann: Jede Eingabe wird zuerst mit Lexer und Parser von Tala geprüft.", + blocks: [ + { kind: "code", code: usage }, + { + kind: "terms", + items: optionTerms({ + inputs: + "Eine oder mehrere Quellen. Die Projektkonfiguration wird einmal für alle ausgewertet.", + check: "Ändert nichts; der Exit-Status schlägt fehl, wenn sich eine Quelle ändern würde.", + emit: "files, die Vorgabe, schreibt die Quellen direkt. Die anderen schreiben die formatierte Quelle oder einen Bericht in die Standardausgabe und lassen die Dateien in Ruhe.", + help: "Gibt die Hilfe aus.", + version: "Gibt die Version von talafmt aus.", + }), + }, + { kind: "heading", text: "Wie die Befehlszeile gelesen wird" }, + { + kind: "text", + text: "Ein von Hand geschriebener, typisierter Parser liest die Befehlszeile. Eine Zeile, die er nicht lesen kann, endet mit Exit-Status 2, bevor eine Datei berührt wird.", + }, + ], + }, + "ru-RU": { + nav: "Командная строка", + title: "Командная строка · Talafmt", + description: + "Командная строка talafmt, форматировщика Tala: входные файлы, --check, --emit и коды завершения.", + section: "TALAFMT / КОМАНДНАЯ СТРОКА", + heading: "Форматировщик и его командная строка", + lead: "talafmt принимает исходные тексты Tala и форматирует их на месте. Он не форматирует то, что не может прочитать: каждый вход сначала проверяется лексером и парсером Tala.", + blocks: [ + { kind: "code", code: usage }, + { + kind: "terms", + items: optionTerms({ + inputs: + "Один или несколько исходных файлов. Конфигурация проекта вычисляется один раз для всех.", + check: + "Ничего не меняет; код завершения сообщает об ошибке, если какой-либо файл изменился бы.", + emit: "files, по умолчанию, записывает файлы на месте. Остальные пишут отформатированный текст или отчёт в стандартный вывод и не трогают файлы.", + help: "Выводит справку.", + version: "Выводит версию talafmt.", + }), + }, + { kind: "heading", text: "Как читается командная строка" }, + { + kind: "text", + text: "Командную строку читает типизированный парсер, написанный вручную. Строка, которую он не может прочитать, завершается с кодом 2 до того, как будет затронут хоть один файл.", + }, + ], + }, + "he-IL": { + nav: "שורת הפקודה", + title: "שורת הפקודה · Talafmt", + description: + "שורת הפקודה של talafmt, מעצב הקוד של Tala: קלטים, ‎--check,‏ ‎--emit וקודי יציאה.", + section: "TALAFMT / שורת הפקודה", + heading: "מעצב הקוד ושורת הפקודה שלו", + lead: "talafmt מקבל קובצי Tala ומעצב אותם במקום. הוא לא מעצב שום דבר שהוא לא יכול לקרוא: כל קלט נבדק קודם עם המנתח הלקסיקלי והתחבירי של Tala.", + blocks: [ + { kind: "code", code: usage }, + { + kind: "terms", + items: optionTerms({ + inputs: "קובץ מקור אחד או יותר. תצורת הפרויקט מחושבת פעם אחת לכולם.", + check: "לא משנה דבר; קוד היציאה נכשל כשקובץ כלשהו היה משתנה.", + emit: "files, ברירת המחדל, כותב את הקבצים במקום. האחרים כותבים את הקוד המעוצב או דוח לפלט התקני ומשאירים את הקבצים כמו שהם.", + help: "מדפיס את העזרה.", + version: "מדפיס את הגרסה של talafmt.", + }), + }, + { kind: "heading", text: "איך נקראת שורת הפקודה" }, + { + kind: "text", + text: "מנתח עם טיפוסים שנכתב ביד קורא את שורת הפקודה. שורה שהוא לא יכול לקרוא מסתיימת בקוד יציאה 2, לפני שקובץ כלשהו נוגע.", + }, + ], + }, +}; + +const layout: DocTopic = { + "en-US": { + nav: "What it changes", + title: "What it changes · Talafmt", + description: + "What talafmt changes in a Tala source, what it never touches, and how it handles encodings.", + section: "TALAFMT / LAYOUT", + heading: "What talafmt changes", + lead: "talafmt changes the physical layout of a source and nothing it means. The compiler's lossless model of the source tells code apart from comments, character literals, strings and raw strings.", + blocks: [ + { + kind: "text", + text: "Blocks in braces are indented four spaces per level, one line ending is used throughout the file, horizontal whitespace at the end of a line is removed, and the file ends with one newline.", + }, + { kind: "heading", text: "What it never touches" }, + { + kind: "text", + text: "Braces inside comments, character literals, strings and raw strings never change the indentation. Lines crossed by a multi-line raw string or a long comment keep their inner indentation and trailing whitespace exactly.", + }, + { kind: "heading", text: "Encodings" }, + { + kind: "text", + text: "talafmt.kts selects the input encoding, the output encoding and whether a byte order mark is written; every run obeys it. UTF-16 and UTF-32 output is little-endian.", + }, + { + kind: "note", + title: "Version 0.1.0", + text: "talafmt accepts what the compiler it is built with accepts; version 0.1.0 is built with the compiler of Tala 0.1.0.", + }, + ], + }, + "de-DE": { + nav: "Was es ändert", + title: "Was es ändert · Talafmt", + description: + "Was talafmt an einer Tala-Quelle ändert, was es nie berührt und wie es mit Kodierungen umgeht.", + section: "TALAFMT / LAYOUT", + heading: "Was talafmt ändert", + lead: "talafmt ändert das physische Layout einer Quelle und nichts an ihrer Bedeutung. Das verlustfreie Quellmodell des Compilers unterscheidet Code von Kommentaren, Zeichenliteralen, Strings und Raw-Strings.", + blocks: [ + { + kind: "text", + text: "Blöcke in geschweiften Klammern werden je Ebene um vier Leerzeichen eingerückt, die ganze Datei erhält ein einheitliches Zeilenende, horizontale Leerzeichen am Zeilenende werden entfernt, und die Datei endet mit genau einem Zeilenumbruch.", + }, + { kind: "heading", text: "Was es nie berührt" }, + { + kind: "text", + text: "Klammern in Kommentaren, Zeichenliteralen, Strings und Raw-Strings ändern die Einrückung nie. Zeilen, die ein mehrzeiliger Raw-String oder ein langer Kommentar kreuzt, behalten ihre innere Einrückung und ihre Leerzeichen am Zeilenende genau.", + }, + { kind: "heading", text: "Kodierungen" }, + { + kind: "text", + text: "talafmt.kts wählt die Eingabekodierung, die Ausgabekodierung und ob eine Byte-Order-Mark geschrieben wird; jeder Lauf folgt ihr. UTF-16- und UTF-32-Ausgaben sind Little-Endian.", + }, + { + kind: "note", + title: "Version 0.1.0", + text: "talafmt akzeptiert, was der Compiler akzeptiert, mit dem es gebaut ist; Version 0.1.0 ist mit dem Compiler von Tala 0.1.0 gebaut.", + }, + ], + }, + "ru-RU": { + nav: "Что он меняет", + title: "Что он меняет · Talafmt", + description: + "Что talafmt меняет в исходном тексте Tala, чего никогда не касается и как работает с кодировками.", + section: "TALAFMT / ОФОРМЛЕНИЕ", + heading: "Что меняет talafmt", + lead: "talafmt меняет физическое оформление исходного текста и ничего в его смысле. Модель исходного текста компилятора без потерь отличает код от комментариев, символьных литералов, строк и сырых строк.", + blocks: [ + { + kind: "text", + text: "Блоки в фигурных скобках получают по четыре пробела на уровень, во всём файле используется один вид конца строки, горизонтальные пробелы в конце строки удаляются, а файл заканчивается одним переводом строки.", + }, + { kind: "heading", text: "Чего он никогда не касается" }, + { + kind: "text", + text: "Скобки внутри комментариев, символьных литералов, строк и сырых строк никогда не меняют отступы. Строки, которые пересекает многострочная сырая строка или длинный комментарий, точно сохраняют свои внутренние отступы и пробелы в конце.", + }, + { kind: "heading", text: "Кодировки" }, + { + kind: "text", + text: "talafmt.kts выбирает входную и выходную кодировку и то, пишется ли метка порядка байтов; каждый запуск ей следует. Вывод в UTF-16 и UTF-32 — little-endian.", + }, + { + kind: "note", + title: "Версия 0.1.0", + text: "talafmt принимает то, что принимает компилятор, с которым он собран; версия 0.1.0 собрана с компилятором Tala 0.1.0.", + }, + ], + }, + "he-IL": { + nav: "מה הוא משנה", + title: "מה הוא משנה · Talafmt", + description: "מה talafmt משנה בקובץ Tala, במה הוא לעולם לא נוגע, ואיך הוא מטפל בקידודים.", + section: "TALAFMT / פריסה", + heading: "מה talafmt משנה", + lead: "talafmt משנה את הפריסה הפיזית של קובץ ושום דבר במשמעות שלו. המודל ללא אובדן של המהדר מבחין בין קוד לבין הערות, ליטרלים של תווים, מחרוזות ומחרוזות גולמיות.", + blocks: [ + { + kind: "text", + text: "בלוקים בסוגריים מסולסלים מוזחים בארבעה רווחים לכל רמה, סוף שורה אחד משמש בכל הקובץ, רווחים אופקיים בסוף שורה מוסרים, והקובץ מסתיים בשורה חדשה אחת.", + }, + { kind: "heading", text: "במה הוא לעולם לא נוגע" }, + { + kind: "text", + text: "סוגריים בתוך הערות, ליטרלים של תווים, מחרוזות ומחרוזות גולמיות לעולם לא משנים את ההזחה. שורות שעוברת דרכן מחרוזת גולמית מרובת שורות או הערה ארוכה שומרות בדיוק על ההזחה הפנימית ועל הרווחים שבסופן.", + }, + { kind: "heading", text: "קידודים" }, + { + kind: "text", + text: "talafmt.kts בוחר את קידוד הקלט, את קידוד הפלט ואם לכתוב סימן סדר בתים; כל הרצה מצייתת לו. פלט UTF-16 ו־UTF-32 הוא little-endian.", + }, + { + kind: "note", + title: "גרסה 0.1.0", + text: "talafmt מקבל את מה שהמהדר שאיתו הוא נבנה מקבל; גרסה 0.1.0 נבנתה עם המהדר של Tala 0.1.0.", + }, + ], + }, +}; + +export const talafmtRoutes: readonly DocRoute[] = [ + { path: "/docs/command-line", topic: commandLine }, + { path: "/docs/layout", topic: layout }, +]; diff --git a/frontend/src/content/talalint.ts b/frontend/src/content/talalint.ts new file mode 100644 index 0000000..6cf8b7c --- /dev/null +++ b/frontend/src/content/talalint.ts @@ -0,0 +1,432 @@ +// SPDX-FileCopyrightText: 2026 Progmasoft +// SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 + +import type { Locale } from "../locales"; +import type { LandingText, WhyTab } from "./landing"; +import type { DocRoute, DocTopic } from "./types"; + +// talalint.tala.run. The facts follow the README of Progmasoft/talalint, version 0.1.0; commands and check names are +// the same in every language and only the prose is translated. +const report = `talalint Program.tala Library.tala`; +const fix = `talalint --fix Program.tala`; +const checks = `compiler.TAT0080 a method reference that does not select one overload +compiler.TAT0076 a format the compiler rejects`; +const tazel = `tazel lint +tazel lint -- --fix`; +const usage = `talalint Program.tala +talalint --fix Program.tala +talalint --help +talalint --version`; +const repository = "https://github.com/Progmasoft/talalint"; + +type TabWords = Record<"report" | "compiler" | "fix" | "tazel", { label: string; caption: string }>; + +function tabs(words: TabWords): WhyTab[] { + return [ + { ...words.report, file: "terminal", code: report }, + { ...words.compiler, file: "checks", code: checks }, + { ...words.fix, file: "terminal", code: fix }, + { ...words.tazel, file: "terminal", code: tazel }, + ]; +} + +const next = (source: string) => [ + { label: "Tala", href: "https://tala.run/" }, + { label: "Talafmt", href: "https://talafmt.tala.run/" }, + { label: source, href: repository }, +]; + +export const talalintLanding: Record = { + "en-US": { + title: "Talalint — The Tala linter", + description: + "talalint reports what is wrong with Tala sources: the diagnostics of the Tala compiler and checks of the physical source, with safe fixes.", + headline: "Know what is wrong before it runs.", + lead: "talalint reports the diagnostics of the Tala compiler frontend and checks the physical source itself. --fix repairs only what is safe to repair.", + primary: { label: "Command line", to: "/docs/command-line" }, + secondary: { label: "What it checks", to: "/docs/checks" }, + whyHeading: "Why Talalint?", + tabs: tabs({ + report: { + label: "Report", + caption: "Every finding of every file it is given, with where it is.", + }, + compiler: { + label: "The compiler's judgement", + caption: + "Semantic diagnostics come from the compiler frontend itself, under the compiler check.", + }, + fix: { + label: "Safe fixes", + caption: "--fix repairs the physical source and never rewrites what the compiler reports.", + }, + tazel: { + label: "From Tazel", + caption: "Tazel runs talalint over the whole project; options for talalint follow --.", + }, + }), + nextHeading: "Next", + next: next("Source"), + copy: "Copy", + copied: "Copied", + }, + "de-DE": { + title: "Talalint — Der Linter von Tala", + description: + "talalint meldet, was an Tala-Quellen nicht stimmt: die Diagnosen des Tala-Compilers und Prüfungen der physischen Quelle, mit sicheren Korrekturen.", + headline: "Wissen, was nicht stimmt, bevor es läuft.", + lead: "talalint meldet die Diagnosen des Tala-Compiler-Frontends und prüft die physische Quelle selbst. --fix repariert nur, was sicher zu reparieren ist.", + primary: { label: "Befehlszeile", to: "/docs/command-line" }, + secondary: { label: "Was es prüft", to: "/docs/checks" }, + whyHeading: "Warum Talalint?", + tabs: tabs({ + report: { + label: "Bericht", + caption: "Jeder Befund jeder übergebenen Datei, mit seiner Stelle.", + }, + compiler: { + label: "Das Urteil des Compilers", + caption: + "Semantische Diagnosen kommen direkt aus dem Compiler-Frontend, unter der Prüfung compiler.", + }, + fix: { + label: "Sichere Korrekturen", + caption: + "--fix repariert die physische Quelle und schreibt nie um, was der Compiler meldet.", + }, + tazel: { + label: "Aus Tazel", + caption: + "Tazel führt talalint über das ganze Projekt aus; Optionen für talalint folgen nach --.", + }, + }), + nextHeading: "Weiter", + next: next("Quellcode"), + copy: "Kopieren", + copied: "Kopiert", + }, + "ru-RU": { + title: "Talalint — линтер Tala", + description: + "talalint сообщает, что не так в исходных текстах Tala: диагностику компилятора Tala и проверки физического текста, с безопасными исправлениями.", + headline: "Узнайте, что не так, до запуска.", + lead: "talalint сообщает диагностику фронтенда компилятора Tala и сам проверяет физический текст. --fix исправляет только то, что безопасно исправлять.", + primary: { label: "Командная строка", to: "/docs/command-line" }, + secondary: { label: "Что он проверяет", to: "/docs/checks" }, + whyHeading: "Почему Talalint?", + tabs: tabs({ + report: { + label: "Отчёт", + caption: "Каждая находка в каждом переданном файле, с её местом.", + }, + compiler: { + label: "Суждение компилятора", + caption: + "Семантическая диагностика приходит прямо из фронтенда компилятора, в проверке compiler.", + }, + fix: { + label: "Безопасные исправления", + caption: + "--fix исправляет физический текст и никогда не переписывает то, о чём сообщает компилятор.", + }, + tazel: { + label: "Из Tazel", + caption: + "Tazel запускает talalint для всего проекта; параметры для talalint идут после --.", + }, + }), + nextHeading: "Дальше", + next: next("Исходный код"), + copy: "Копировать", + copied: "Скопировано", + }, + "he-IL": { + title: "Talalint — הלינטר של Tala", + description: + "talalint מדווח מה לא תקין בקוד Tala: האבחונים של מהדר Tala ובדיקות של הטקסט הפיזי, עם תיקונים בטוחים.", + headline: "לדעת מה לא תקין לפני שזה רץ.", + lead: "talalint מדווח על האבחונים של החלק הקדמי של מהדר Tala ובודק בעצמו את הטקסט הפיזי. ‎--fix מתקן רק את מה שבטוח לתקן.", + primary: { label: "שורת הפקודה", to: "/docs/command-line" }, + secondary: { label: "מה הוא בודק", to: "/docs/checks" }, + whyHeading: "למה Talalint?", + tabs: tabs({ + report: { + label: "דוח", + caption: "כל ממצא בכל קובץ שניתן לו, עם המקום שלו.", + }, + compiler: { + label: "השיפוט של המהדר", + caption: "אבחונים סמנטיים מגיעים ישירות מהחלק הקדמי של המהדר, תחת הבדיקה compiler.", + }, + fix: { + label: "תיקונים בטוחים", + caption: "‏--fix מתקן את הטקסט הפיזי ולעולם לא משכתב את מה שהמהדר מדווח.", + }, + tazel: { + label: "מתוך Tazel", + caption: "Tazel מריץ את talalint על כל הפרויקט; אפשרויות ל־talalint באות אחרי ‎--.", + }, + }), + nextHeading: "הלאה", + next: next("קוד מקור"), + copy: "העתקה", + copied: "הועתק", + }, +}; + +const optionTerms = (d: { inputs: string; fix: string; help: string; version: string }) => [ + { term: "Program.tala …", detail: d.inputs }, + { term: "--fix", detail: d.fix }, + { term: "--help, -h", detail: d.help }, + { term: "--version, -v", detail: d.version }, +]; + +const commandLine: DocTopic = { + "en-US": { + nav: "Command line", + title: "Command line · Talalint", + description: "The command line of talalint, the Tala linter: inputs, --fix and exit statuses.", + section: "TALALINT / COMMAND LINE", + heading: "The linter and its command line", + lead: "talalint takes Tala sources and reports what it finds. It changes a file only when --fix asks it to, and then only safely.", + blocks: [ + { kind: "code", code: usage }, + { + kind: "terms", + items: optionTerms({ + inputs: "One or more sources to check.", + fix: "Applies the safe fixes, the layout talafmt gives with its defaults, then reports what is left; compiler diagnostics are never rewritten.", + help: "Prints the help.", + version: "Prints the version of talalint.", + }), + }, + { kind: "heading", text: "How the command line is read" }, + { + kind: "text", + text: "A typed parser written by hand reads the command line. A line it cannot read ends with exit status 2.", + }, + ], + }, + "de-DE": { + nav: "Befehlszeile", + title: "Befehlszeile · Talalint", + description: + "Die Befehlszeile von talalint, dem Linter von Tala: Eingaben, --fix und Exit-Status.", + section: "TALALINT / BEFEHLSZEILE", + heading: "Der Linter und seine Befehlszeile", + lead: "talalint nimmt Tala-Quellen und meldet, was es findet. Es ändert eine Datei nur, wenn --fix es verlangt, und dann nur sicher.", + blocks: [ + { kind: "code", code: usage }, + { + kind: "terms", + items: optionTerms({ + inputs: "Eine oder mehrere zu prüfende Quellen.", + fix: "Wendet die sicheren Korrekturen an, das Layout von talafmt mit seinen Vorgaben, und meldet danach, was übrig ist; Compiler-Diagnosen werden nie umgeschrieben.", + help: "Gibt die Hilfe aus.", + version: "Gibt die Version von talalint aus.", + }), + }, + { kind: "heading", text: "Wie die Befehlszeile gelesen wird" }, + { + kind: "text", + text: "Ein von Hand geschriebener, typisierter Parser liest die Befehlszeile. Eine Zeile, die er nicht lesen kann, endet mit Exit-Status 2.", + }, + ], + }, + "ru-RU": { + nav: "Командная строка", + title: "Командная строка · Talalint", + description: "Командная строка talalint, линтера Tala: входные файлы, --fix и коды завершения.", + section: "TALALINT / КОМАНДНАЯ СТРОКА", + heading: "Линтер и его командная строка", + lead: "talalint принимает исходные тексты Tala и сообщает о найденном. Он меняет файл, только если об этом просит --fix, и тогда только безопасно.", + blocks: [ + { kind: "code", code: usage }, + { + kind: "terms", + items: optionTerms({ + inputs: "Один или несколько исходных файлов для проверки.", + fix: "Применяет безопасные исправления — оформление talafmt с настройками по умолчанию — и сообщает, что осталось; диагностика компилятора никогда не переписывается.", + help: "Выводит справку.", + version: "Выводит версию talalint.", + }), + }, + { kind: "heading", text: "Как читается командная строка" }, + { + kind: "text", + text: "Командную строку читает типизированный парсер, написанный вручную. Строка, которую он не может прочитать, завершается с кодом 2.", + }, + ], + }, + "he-IL": { + nav: "שורת הפקודה", + title: "שורת הפקודה · Talalint", + description: "שורת הפקודה של talalint, הלינטר של Tala: קלטים, ‎--fix וקודי יציאה.", + section: "TALALINT / שורת הפקודה", + heading: "הלינטר ושורת הפקודה שלו", + lead: "talalint מקבל קובצי Tala ומדווח על מה שהוא מוצא. הוא משנה קובץ רק כש־‎--fix מבקש, ואז רק באופן בטוח.", + blocks: [ + { kind: "code", code: usage }, + { + kind: "terms", + items: optionTerms({ + inputs: "קובץ מקור אחד או יותר לבדיקה.", + fix: "מחיל את התיקונים הבטוחים, הפריסה של talafmt עם ברירות המחדל שלו, ואז מדווח על מה שנשאר; אבחוני המהדר לעולם לא משוכתבים.", + help: "מדפיס את העזרה.", + version: "מדפיס את הגרסה של talalint.", + }), + }, + { kind: "heading", text: "איך נקראת שורת הפקודה" }, + { + kind: "text", + text: "מנתח עם טיפוסים שנכתב ביד קורא את שורת הפקודה. שורה שהוא לא יכול לקרוא מסתיימת בקוד יציאה 2.", + }, + ], + }, +}; + +const checkTerms = (d: { + compiler: string; + whitespace: string; + endings: string; + newline: string; +}) => [ + { term: "compiler.", detail: d.compiler }, + { term: "format.trailingWhitespace", detail: d.whitespace }, + { term: "format.mixedLineEndings", detail: d.endings }, + { term: "format.missingFinalNewline", detail: d.newline }, +]; + +const checksTopic: DocTopic = { + "en-US": { + nav: "What it checks", + title: "What it checks · Talalint", + description: + "The checks of talalint 0.1.0: the compiler's diagnostics and its own checks of the physical source.", + section: "TALALINT / CHECKS", + heading: "What talalint checks", + lead: "talalint reports what the compiler it is built with reports, and adds checks of its own on the physical source.", + blocks: [ + { + kind: "terms", + items: checkTerms({ + compiler: + "The semantic diagnostics of the Tala compiler frontend, named after their compiler code.", + whitespace: "Spaces or tabs at the end of a physical line.", + endings: "More than one line-ending convention in one file.", + newline: "A non-empty file without a final newline.", + }), + }, + { kind: "heading", text: "Diagnostics of the compiler" }, + { + kind: "text", + text: "Version 0.1.0 is built with the compiler of Tala 0.1.0. Its diagnostics arrive under the compiler check with the compiler's code:", + }, + { kind: "code", code: checks }, + { + kind: "note", + title: "Fixes", + text: "--fix rewrites each file with the layout talafmt gives with its defaults, which clears the three format findings and also re-indents blocks; then talalint reports what is left. A compiler diagnostic is reported and left for you to fix.", + }, + ], + }, + "de-DE": { + nav: "Was es prüft", + title: "Was es prüft · Talalint", + description: + "Die Prüfungen von talalint 0.1.0: die Diagnosen des Compilers und eigene Prüfungen der physischen Quelle.", + section: "TALALINT / PRÜFUNGEN", + heading: "Was talalint prüft", + lead: "talalint meldet, was der Compiler meldet, mit dem es gebaut ist, und ergänzt eigene Prüfungen der physischen Quelle.", + blocks: [ + { + kind: "terms", + items: checkTerms({ + compiler: + "Die semantischen Diagnosen des Tala-Compiler-Frontends, benannt nach ihrem Compiler-Code.", + whitespace: "Leerzeichen oder Tabulatoren am Ende einer physischen Zeile.", + endings: "Mehr als eine Zeilenende-Konvention in einer Datei.", + newline: "Eine nicht leere Datei ohne Zeilenumbruch am Ende.", + }), + }, + { kind: "heading", text: "Diagnosen des Compilers" }, + { + kind: "text", + text: "Version 0.1.0 ist mit dem Compiler von Tala 0.1.0 gebaut. Seine Diagnosen erscheinen unter der Prüfung compiler mit dem Code des Compilers:", + }, + { kind: "code", code: checks }, + { + kind: "note", + title: "Korrekturen", + text: "--fix schreibt jede Datei mit dem Layout neu, das talafmt mit seinen Vorgaben erzeugt; das beseitigt die drei format-Befunde und rückt auch Blöcke neu ein. Danach meldet talalint, was übrig ist. Eine Compiler-Diagnose wird gemeldet und bleibt Ihnen überlassen.", + }, + ], + }, + "ru-RU": { + nav: "Что он проверяет", + title: "Что он проверяет · Talalint", + description: + "Проверки talalint 0.1.0: диагностика компилятора и собственные проверки физического текста.", + section: "TALALINT / ПРОВЕРКИ", + heading: "Что проверяет talalint", + lead: "talalint сообщает то, о чём сообщает компилятор, с которым он собран, и добавляет собственные проверки физического текста.", + blocks: [ + { + kind: "terms", + items: checkTerms({ + compiler: + "Семантическая диагностика фронтенда компилятора Tala, названная по коду компилятора.", + whitespace: "Пробелы или табуляции в конце физической строки.", + endings: "Больше одного вида концов строк в одном файле.", + newline: "Непустой файл без перевода строки в конце.", + }), + }, + { kind: "heading", text: "Диагностика компилятора" }, + { + kind: "text", + text: "Версия 0.1.0 собрана с компилятором Tala 0.1.0. Его диагностика приходит в проверке compiler с кодом компилятора:", + }, + { kind: "code", code: checks }, + { + kind: "note", + title: "Исправления", + text: "--fix переписывает каждый файл в оформлении, которое даёт talafmt с настройками по умолчанию: это убирает три находки format и заодно выравнивает отступы блоков. Затем talalint сообщает, что осталось. Диагностика компилятора сообщается, а исправлять её — вам.", + }, + ], + }, + "he-IL": { + nav: "מה הוא בודק", + title: "מה הוא בודק · Talalint", + description: "הבדיקות של talalint 0.1.0: האבחונים של המהדר ובדיקות משלו על הטקסט הפיזי.", + section: "TALALINT / בדיקות", + heading: "מה talalint בודק", + lead: "talalint מדווח את מה שהמהדר שאיתו הוא נבנה מדווח, ומוסיף בדיקות משלו על הטקסט הפיזי.", + blocks: [ + { + kind: "terms", + items: checkTerms({ + compiler: "האבחונים הסמנטיים של החלק הקדמי של מהדר Tala, בשם הקוד שלהם במהדר.", + whitespace: "רווחים או טאבים בסוף שורה פיזית.", + endings: "יותר ממוסכמה אחת של סוף שורה בקובץ אחד.", + newline: "קובץ לא ריק בלי שורה חדשה בסופו.", + }), + }, + { kind: "heading", text: "האבחונים של המהדר" }, + { + kind: "text", + text: "גרסה 0.1.0 נבנתה עם המהדר של Tala 0.1.0. האבחונים שלו מגיעים תחת הבדיקה compiler עם הקוד של המהדר:", + }, + { kind: "code", code: checks }, + { + kind: "note", + title: "תיקונים", + text: "‏--fix כותב כל קובץ מחדש בפריסה ש־talafmt נותן עם ברירות המחדל שלו; זה מנקה את שלושת ממצאי format וגם מזיח מחדש בלוקים. אחר כך talalint מדווח על מה שנשאר. אבחון של המהדר מדווח ונשאר לתיקון שלכם.", + }, + ], + }, +}; + +export const talalintRoutes: readonly DocRoute[] = [ + { path: "/docs/command-line", topic: commandLine }, + { path: "/docs/checks", topic: checksTopic }, +]; diff --git a/frontend/src/pages/DocPage.vue b/frontend/src/pages/DocPage.vue index 7b7ec07..d0f9e33 100644 --- a/frontend/src/pages/DocPage.vue +++ b/frontend/src/pages/DocPage.vue @@ -15,6 +15,8 @@ const source = { language: "src/content/syntax.ts", talac: "src/content/talac.ts", tazel: "src/content/tazel.ts", + talafmt: "src/content/talafmt.ts", + talalint: "src/content/talalint.ts", }[site]; diff --git a/frontend/src/pages/LandingPage.vue b/frontend/src/pages/LandingPage.vue index 777f137..89dab3a 100644 --- a/frontend/src/pages/LandingPage.vue +++ b/frontend/src/pages/LandingPage.vue @@ -7,14 +7,14 @@ import { RouterLink } from "vue-router"; import WhyTabs from "../components/WhyTabs.vue"; import { landing } from "../content/landing"; import { locale } from "../preferences"; -import { site } from "../site"; +import { site, siteBrand } from "../site"; /** * The first page of a site: one headline, two ways in, the "Why" tabs and a short row of next links. The state of * the project is said once, in the header, rather than in every paragraph. */ const text = computed(() => landing[site][locale.value]); -const brand = { language: "Tala", talac: "Talac", tazel: "Tazel" }[site]; +const brand = siteBrand[site];