diff --git a/.opencode/command/check.md b/.opencode/command/check.md new file mode 100644 index 00000000..04319767 --- /dev/null +++ b/.opencode/command/check.md @@ -0,0 +1,13 @@ +--- +description: Check a page for common mistakes +agent: plan +--- + +Check the page $ARGUMENTS for errors. When no language is provided, check all languages of the page. Common errors are: + +- Grammatical, typographical, or spelling errors +- Not following the common terms in defined in the glossary of `AGENTS.md` +- Content differs between the different languages. The content should always be the same. +- The page structure doesn't follow the archetype defined in `archetypes` +- Anchors of internal links are not matching the referenced and translated title +- Keywords are not translated as defined in the translations table in `AGENTS.md` diff --git a/.opencode/command/translate.md b/.opencode/command/translate.md new file mode 100644 index 00000000..09958191 --- /dev/null +++ b/.opencode/command/translate.md @@ -0,0 +1,16 @@ +--- +description: Translate a page +agent: build +--- + +Translate the page $ARGUMENTS into the other languages. +If the page already exists, only translate the added or changed parts. If the page doesn't exist, create it. + +Follow these rules: + +- Do not modify the meaning of content. Translate as 1:1 where possible. +- Use names of the translation language for cities (e.g., Köln in German, "Cologne" in English and "eau de Cologne" in French). +- Enforce the glossary and translations as defined in `AGENTS.md`. +- Do not translate the keys of the front matter section, the keys of shortcodes or partials. +- Use the corresponding archetype (defined in `archetypes`) as base for the translated page. +- Update anchors of internal links to the corresponding section in the target language. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..0bfe1f08 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,57 @@ +# FIP Guide Guidelines + +## Content Guidelines + +- Content MUST support all three languages (en, de, fr) +- NEVER change the meaning of content when translating. Always translate as 1:1. +- ALWAYS align the content with the corresponding base (defined in `archetypes`) +- ALWAYS use the exact translations for headlines (defined in `archetypes`) +- ALWAYS create new content pages with `hugo new {base}/{name}` where base can be `country`, `operator` or `booking`. + +### Glossary + +- Use "Freifahrtschein" instead of "Freifahrtsschein" +- Use "FIP Coupon" instead of "FIP free travel" +- Use "Motorail train" instead of "car train" +- Use "Break of journey" instead of "Journey Interruption" + +### Translations + +| Deutsch | Englisch | Französisch | +| ------------------- | --------------- | ---------------- | +| FIP Freifahrtschein | FIP Coupon | Coupon FIP | +| FIP Globalpreis | FIP Global Fare | Tarif Global FIP | +| FIP 50 Ticket | FIP 50 Ticket | Billet FIP 50 | + +## Development Guidelines + +### Build/Test Commands + +- `hugo serve`: Start local development server +- `hugo --gc --minify`: Build for production +- `npx prettier --write .`: Format code +- `npx pagefind --site public`: Generate search index +- `pre-commit run --all-files`: Run all pre-commit checks + +### Code Style & Conventions + +- **HTML Templates**: Use Hugo / Go template syntax +- **JavaScript**: ES6 modules with relative imports (`./filename.js`). +- **CSS/SCSS**: Use SCSS with BEM-like naming, variables defined in `_variables.scss` +- **Markdown**: Frontmatter in YAML format, use shortcodes for complex layouts +- **i18n**: Files in `i18n/` sorted alphabetically by key, support en/de/fr languages + +### File Structure + +- Content in `content/` with multilingual structure (`index.en.md`, `index.de.md`, `index.fr.md`) +- Layouts in `layouts/` following Hugo conventions: + - Partials for reusable components in HTML files in `layouts/partials/` + - Shortcodes for reusable components in Markdown files in `layouts/shortcodes/` +- Assets in `assets/` (processed) and `static/` (copied as-is) + +## Quality Standards + +- All commits MUST pass the pre-commit hooks defined in `.pre-commit-config.yaml` +- HTML templates must be valid Go template syntax +- Do NOT add any comments to the code +- NEVER create markdown files outside the content directory diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9c82f31..30f25a86 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,6 +65,8 @@ Now, enable `pre-commit` to run the check every time you want to commit changes: pre-commit install ``` +## Content Contributions + ### Add new pages To add a new country: @@ -84,3 +86,21 @@ To add a new booking platform: ```zsh hugo new booking/${PLATFORM} # Replace ${PLATFORM} with the name of the booking platform ``` + +### Use AI for translation and quality checks + +We provide commands to automatically translate and check pages. To define the commands, we use the [OpenCode AI framework](https://opencode.ai/). It's open source and can be used with different providers, models (OpenAI, Github Copilot, Anthropic), and [IDEs](https://opencode.ai/docs/ide/#installation). + +#### Installation + +1. Install OpenCode: https://opencode.ai/docs#install. +2. Run `opencode auth login` in a terminal, select the provider and log in. +3. Open the OpenCode CLI with `opencode` in a terminal. +4. Run `/models` to select the model you want to use. + +Inside the OpenCode Terminal, you can ask any question, similarly to Github Copilot or Claude Chat. In addition, we provide helpful commands: + +- `/translate {page}`: Update the translations and add missing translations of the page. `{page}` can be the name of an operator, a country, a booking plattform, or a path to a file. +- `/check {page}`: Check the page for common mistakes and report them. `{page}` can be the name of an operator, a country, a booking plattform, or a path to a file. + +That's the recommended way. However, you can still use other frontend ends like GitHub Copilot Chat and Claude Code. We provide an [`AGENTS.md`](https://agents.md/) file for these providers in the repository, but the custom commands are not available without OpenCode. diff --git a/archetypes/operator/index.de.md b/archetypes/operator/index.de.md index 140de138..f0cb41fd 100644 --- a/archetypes/operator/index.de.md +++ b/archetypes/operator/index.de.md @@ -30,6 +30,10 @@ operator: "{{ .File.ContentBaseName }}" ## Gültigkeit FIP Tickets + + FIP Freifahrtschein: <✅/⛔> \ FIP Freifahrt Angehörige: <✅/⛔> \ FIP 50 Tickets: <✅/⛔> \ diff --git a/archetypes/operator/index.en.md b/archetypes/operator/index.en.md index 116a04a1..9a65d731 100644 --- a/archetypes/operator/index.en.md +++ b/archetypes/operator/index.en.md @@ -30,6 +30,10 @@ operator: "{{ .File.ContentBaseName }}" ## Validity of FIP Tickets + + FIP Coupon: <✅/⛔> \ FIP Coupon for relatives: <✅/⛔> \ FIP 50 Tickets: <✅/⛔> \ diff --git a/archetypes/operator/index.fr.md b/archetypes/operator/index.fr.md index 7288083c..16159fa4 100644 --- a/archetypes/operator/index.fr.md +++ b/archetypes/operator/index.fr.md @@ -4,9 +4,9 @@ title: "{{ .File.ContentBaseName | upper }}" description: "" # Complète une description pour la compagnie ferroviaire country: # Ajoutez les abréviations des pays dans lesquels la compagnie ferroviaire opère en anglais. - - "pays1" - - "pays2" - - "pays3" + - "country1" + - "country2" + - "country3" operator: "{{ .File.ContentBaseName }}" --- @@ -30,6 +30,10 @@ operator: "{{ .File.ContentBaseName }}" ## Validité des Billets FIP + + Coupon FIP : <✅/⛔> \ Coupon FIP accompagnant : <✅/⛔> \ Billets FIP 50 : <✅/⛔> \ @@ -76,6 +80,16 @@ Tarif Global FIP : <✅/⛔> ## Catégories de classes + + + + ## Achat de billets et réservations ### En ligne diff --git a/content/operator/ns/index.en.md b/content/operator/ns/index.en.md index 6503d73b..64c85ae1 100644 --- a/content/operator/ns/index.en.md +++ b/content/operator/ns/index.en.md @@ -110,7 +110,7 @@ Trains of the Sneltrein / Regional-Express `RE` category, including the connecti ### Online {{% booking id="db-website" - subtitle="For national and cross-border connections" + subtitle="For cross-border ICE and IC connections" /%}} {{% booking id="db-website-fip-db" diff --git a/content/operator/ns/index.fr.md b/content/operator/ns/index.fr.md index 21ba8c60..c5c15b23 100644 --- a/content/operator/ns/index.fr.md +++ b/content/operator/ns/index.fr.md @@ -110,7 +110,7 @@ Les trains de la catégorie Sneltrein / Regional-Express `RE`, notamment les lia ### En ligne {{% booking id="db-website" - subtitle="Pour les trajets nationaux et internationaux" + subtitle="Pour les connexions ICE et IC transfrontalières" /%}} {{% booking id="db-website-fip-db" diff --git a/content/operator/oebb/index.de.md b/content/operator/oebb/index.de.md index bb6a095b..f838b611 100644 --- a/content/operator/oebb/index.de.md +++ b/content/operator/oebb/index.de.md @@ -19,7 +19,7 @@ Die ÖBB (Österreichische Bundesbahnen) ist die nationale Eisenbahngesellschaft - Aufpassen bei Zügen anderer Betreiber ohne FIP Akzeptanz - Kein FIP im Wiener Flughafenexpress `CAT` - Besondere Regeln in Zügen nach Italien, Nightjets, Autozügen und IC Bussen -- FIP Freifahrt der ÖBB gilt auch in Lichtenstein +- FIP Freifahrt der ÖBB gilt auch in Liechtenstein ## Gültigkeit FIP Tickets @@ -208,9 +208,9 @@ FIP Freifahrtscheine der ÖBB, **jedoch nicht der FS**, gelten im italienischen Auf der Linie REX63 werden zwischen Pamhagen und Neusiedl am See werden sowohl FIP Fahrkarten der ÖBB als auch der GySEV anerkannt. -### Lichtenstein +### Liechtenstein -Die Eisenbahn in Lichtenstein wird von der ÖBB betrieben. FIP Fahrkarten sind hier zu den österreichischen Konditionen und ohne Aufpreis gültig (Feldkirchen-Buchs SG). +Die Eisenbahn in Liechtenstein wird von der ÖBB betrieben. FIP Fahrkarten sind hier zu den österreichischen Konditionen und ohne Aufpreis gültig (Feldkirchen-Buchs SG). ### Wien Flughafen: City Airport Train (CAT) @@ -226,7 +226,7 @@ Wer mit regulären Wiener Öffi-Tickets (z. B. Einzelfahrten oder 24/48/72-Stund ### Schneebergbahn -Die Schneebergbahn ist zwar kein Teil der ÖBB oder FIP gewähnt jedoch bei Vorlage des FIP Ausweises 50% Rabatt auf Tickets. +Die Schneebergbahn ist zwar kein Teil der ÖBB oder FIP gewährt jedoch bei Vorlage des FIP Ausweises 50% Rabatt auf Tickets. ### ÖBB Postbus diff --git a/content/operator/oebb/index.fr.md b/content/operator/oebb/index.fr.md index 625537b4..f758c46c 100644 --- a/content/operator/oebb/index.fr.md +++ b/content/operator/oebb/index.fr.md @@ -45,7 +45,7 @@ Coût : \ **Description :** \ Trains rapides nationaux et internationaux de la catégorie la plus élevée des ÖBB. Ils relient régulièrement les principales villes autrichiennes, ainsi que l’Allemagne, l’Italie, la Tchéquie, la Hongrie, la Slovaquie et la Suisse. Trois classes de confort et un bistro à bord. Les Railjet avec moins d’arrêts sont commercialisés comme Railjet Xpress. -Pour les Railjet vers l’Italie, un supplément est à payer à partir de la frontière italienne. Voir [Conditions spéciales](##conditions-tarifaires-spéciales). \ +Pour les Railjet vers l’Italie, un supplément est à payer à partir de la frontière italienne. Voir [Conditions spéciales](#conditions-tarifaires-spéciales). \ **Réservation possible :** oui \ **Réservation obligatoire :** non {{% /expander %}}