Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .githooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Repo git hooks

This directory holds repo-tracked git hooks. They are **not** active by default
on a fresh clone — git looks at `.git/hooks/` first, which is local and untracked.

## One-time activation per clone

Run from the repo root:

```bash
git config core.hooksPath .githooks
```

That's it. From now on, hooks in this directory will fire on the appropriate
events.

## What's here

- **`pre-commit`** — i18n parity gate. Blocks any commit that adds/modifies a
`content/it/*.md` or `content/en/*.md` page without a matching sibling in the
other language tree carrying the same `translationKey:` frontmatter value.
Mirrors the server-side `.github/workflows/i18n-parity.yml` check.

## Bypassing

In a real emergency: `git commit --no-verify`. The server-side workflow is the
non-bypassable gate, so the only thing `--no-verify` buys you is faster local
iteration before push.
72 changes: 72 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# i18n parity gate — block commits where the staged content/it/* and
# content/en/* files don't pair up via translationKey.
#
# Dir-split layout: content/it/foo.md (Italian) and content/en/bar.md
# (English) are paired via the `translationKey:` frontmatter field. Both
# siblings must declare the same key. The hook scans the staged tree and
# fails if a touched page lacks a key or its counterpart key is missing
# from the OTHER language tree.
#
# Bypass for emergencies: git commit --no-verify (CI parity check is the
# non-bypassable gate — see .github/workflows/i18n-parity.yml).

set -euo pipefail

# Files staged for commit (Added/Modified/Renamed), filtered to content/{it,en}/*.md
mapfile -t staged < <(
git diff --cached --name-only --diff-filter=AMR \
| grep -E '^content/(it|en)/.*\.md$' || true
)

[[ ${#staged[@]} -eq 0 ]] && exit 0

# extract_key <path>: print translationKey value, empty if missing.
extract_key() {
awk '
/^---$/ { if (in_fm) exit; in_fm=1; next }
in_fm && /^translationKey:[[:space:]]*/ {
sub(/^translationKey:[[:space:]]*/, ""); gsub(/["'\''`]/, ""); print; exit
}
' "$1"
}

# has_key_in <key> <lang>: 0 if any content/<lang>/**/*.md declares translationKey=<key>.
has_key_in() {
local key="$1" lang="$2" f
[[ -d "content/$lang" ]] || return 1
while IFS= read -r f; do
[[ "$(extract_key "$f")" == "$key" ]] && return 0
done < <(find "content/$lang" -type f -name '*.md')
return 1
}

missing=()
for f in "${staged[@]}"; do
key=$(extract_key "$f")
# No translationKey = page declares no pairing yet; pre-translation
# half-step is allowed (the gate only enforces well-formed pairs, it
# does not force every page to be translated).
[[ -z "$key" ]] && continue

case "$f" in
content/it/*) other="en" ;;
content/en/*) other="it" ;;
*) continue ;;
esac

has_key_in "$key" "$other" || \
missing+=("$f → translationKey '$key' missing in content/$other/")
done

if [[ ${#missing[@]} -gt 0 ]]; then
echo "✗ i18n parity check failed:" >&2
printf ' - %s\n' "${missing[@]}" >&2
echo "" >&2
echo "Fix: add the missing sibling under content/<other-lang>/ with the same" >&2
echo "translationKey, or run 'git commit --no-verify' if you are intentionally" >&2
echo "staging a half-step (the CI parity check will still gate the PR)." >&2
exit 1
fi

exit 0
86 changes: 86 additions & 0 deletions .github/workflows/i18n-parity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: i18n parity

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
parity:
name: IT/EN parity check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Verify every content/{it,en}/*.md touched in this PR pairs via translationKey
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail

# Delta-based parity gate — mirrors .githooks/pre-commit. Only
# files touched in THIS PR are checked. For each touched
# content/{it,en}/*.md the resulting tree must contain a
# counterpart in the OTHER language tree carrying the same
# `translationKey:` frontmatter value.
if [[ -n "${BASE_SHA:-}" && -n "${HEAD_SHA:-}" ]]; then
range="$BASE_SHA..$HEAD_SHA"
else
range="HEAD^..HEAD"
fi

mapfile -t touched < <(
git diff --name-only --diff-filter=AMR "$range" \
| grep -E '^content/(it|en)/.*\.md$' || true
)

if [[ ${#touched[@]} -eq 0 ]]; then
echo "✓ no content/{it,en}/*.md touched in this range — parity OK"
exit 0
fi

extract_key() {
awk '
/^---$/ { if (in_fm) exit; in_fm=1; next }
in_fm && /^translationKey:[[:space:]]*/ {
sub(/^translationKey:[[:space:]]*/, ""); gsub(/["'"'"'`]/, ""); print; exit
}
' "$1"
}

has_key_in() {
local key="$1" lang="$2" f
[[ -d "content/$lang" ]] || return 1
while IFS= read -r f; do
[[ "$(extract_key "$f")" == "$key" ]] && return 0
done < <(find "content/$lang" -type f -name '*.md')
return 1
}

missing=()
for f in "${touched[@]}"; do
key=$(extract_key "$f")
# No translationKey = page declares no pairing yet.
[[ -z "$key" ]] && continue

case "$f" in
content/it/*) other="en" ;;
content/en/*) other="it" ;;
*) continue ;;
esac

has_key_in "$key" "$other" || \
missing+=("$f → translationKey '$key' missing in content/$other/")
done

if [[ ${#missing[@]} -gt 0 ]]; then
echo "::error::i18n parity broken:"
printf ' - %s\n' "${missing[@]}"
exit 1
fi

echo "✓ i18n parity OK (${#touched[@]} touched file(s) verified)"
56 changes: 56 additions & 0 deletions content/en/connect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
title: "How to Connect"
lead: "Everything you need to step into the world of Azzurra, in a few easy steps."
translationKey: page-come-connettersi
aliases: [/en/come-connettersi/]
---

## Quick connection via Web

The fastest way to join Azzurra is to use the **webchat** straight from your browser, no installation required.

→ [Open webchat.azzurra.chat](https://webchat.azzurra.chat)

Pick a nickname, choose a channel, and you're in.

---

## Connecting through an IRC client

If you'd rather use a dedicated client (recommended for the best experience), use the following parameters:

| Parameter | Value |
|-----------|-------|
| **Server** | `irc.azzurra.chat` |
| **Ports** | `6666`,`6667`,`6668`,`6669` (plain) |
| **SSL port** | `6697`,`9999` (recommended) |
| **IPv6** | supported |

### Recommended clients

- **[HexChat](https://hexchat.github.io/)** – Windows / Linux, free
- **[Textual](https://www.codeux.com/textual/)** – macOS
- **[WeeChat](https://weechat.org/)** – terminal, advanced
- **[mIRC](https://www.mirc.com/)** – Windows, the historic IRC client
- **[Irssi](https://irssi.org/)** – terminal

### Quick example (HexChat)

1. Open HexChat → *Network list*
2. Click **Add** and name the network "Azzurra"
3. Set the server to `irc.azzurra.chat/6697` and tick *Use SSL*
4. Enter your nickname and click **Connect**

---

## Main channels

| Channel | Description |
|---------|-------------|
| `#italia` | The general channel, the main meeting point |
| `#IRCHelp` | Technical help and support |

{{< info title="💡 First connection" >}}
On your first connection you may want to register your nickname.
Type: `/msg NickServ REGISTER <password> <email>`
{{< /info >}}
33 changes: 33 additions & 0 deletions content/en/contact.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: "Contact"
lead: "How to reach the Azzurra IRC Network staff."
translationKey: page-contatti
aliases: [/en/contatti/]
---

## IRC channels

The fastest way to reach the staff is right on the network:

| Channel | Purpose |
|---------|---------|
| `#IRCHelp` | General support, questions, reports |

---

## Generic addresses

For general matters that don't need an immediate reply, you can email the staff at <irc@azzurra.chat>.

---

## Abuse reports / K-Line

If your IP has been banned from the network or you'd like to report an abuse, use the dedicated section:

→ [K-Line removal request](/en/kline)


{{< info title="⏱️ Response times" >}}
The staff is made of volunteers. Response times may vary. For urgent assistance, head straight to `#IRCHelp` on the IRC network.
{{< /info >}}
79 changes: 79 additions & 0 deletions content/en/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
title: "FAQ"
lead: "Frequently asked questions about the Azzurra IRC Network."
translationKey: page-faq
---

## General

### What is Azzurra?

Azzurra is the longest-running Italian IRC network, founded in 1997. It offers a free, organised chat space for the Italian community and beyond.

### Is IRC still used in 2025?

Yes! IRC is one of the most stable and open messaging protocols around. Azzurra still hosts an active community with dozens of channels in daily use.

### Do I need to create an account to connect?

No. You can connect with any nickname without registering. **NickServ** registration is optional, but recommended to protect your nickname.

---

## Connection

### How do I connect?

Use the [webchat](https://webchat.azzurra.chat) right from your browser, or an IRC client like HexChat, WeeChat or mIRC. See the [How to Connect](/en/connect) page for full details.

### Which ports should I use?

- Port **6667** for plain connections
- Port **6697** for SSL/TLS connections (recommended)

### Can I use IPv6?

Yes — the network fully supports IPv6.

---

## Nicknames and accounts

### How do I register my nickname?

```
/msg NickServ REGISTER <password> <your@email.com>
```


---

## Channels

### How do I create a channel?

Join the channel with `/join #channelname`. If the channel doesn't exist, it'll be created and you'll automatically become its operator.

### How do I register a channel with ChanServ?

```
/msg ChanServ REGISTER #channelname password description
```

You must be a channel operator (have the `@` flag) to register it.

### I need help in a channel. Who do I ask?

Hop into `#IRCHelp`: staff and experienced users will be glad to help.

---

## Issues and reports

### How do I report a user violating the rules?

Join `#IRCHelp` and describe the problem. As an alternative, use the [contact form](/en/contact).

### My IP has been banned (K-Line). What do I do?

Head over to the [K-Line removal request](/en/kline) page and fill in the form.
28 changes: 28 additions & 0 deletions content/en/history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: "The Story of Azzurra"
lead: "From the origins in 1997 to today: how Italy's longest-running IRC network was born and grew."
translationKey: page-storia
aliases: [/en/storia/]
---

## The origins (1997)

Azzurra was born in **1997** out of the passion of a group of IRC enthusiasts who wanted to build a stable, safe Italian network — an alternative to the chats already available on the Internet, which were often chaotic and lacked clear rules.

From the very start, the staff focused on a precise goal: building a quality environment where users could communicate freely and respectfully.

## The growth (2000–2010)

Through the 2000s Azzurra became the leading Italian IRC community by number of users and active channels. The network gathered ever wider support and partnered with the major Italian Internet players of the time.

Those were the years of peak expansion: dozens of servers spread across Italy, thousands of users connected at the same time, channels dedicated to every imaginable topic.

## The transition (2020–2024)

In May 2020 the staff started a deep reorganisation of the network, with the goal of bringing back all the historic services in a stable, modern form. **SeenServ**, **StatServ** and the **UnoBot** bot all returned to active duty.

In June 2024 the network formally adopted the **azzurra.chat** domain, giving the current staff direct, independent governance and carrying forward a 27-year tradition.

## Today

Azzurra continues its mission: offering a free, stable and welcoming chat space for the Italian community. Servers are reachable at `irc.azzurra.chat` (port 6667, SSL 6697) and the webchat lives at [webchat.azzurra.chat](https://webchat.azzurra.chat).
Loading
Loading