Türkçe hukuki belgeler için PDF dizgi motoru. Sözleşme, yönerge, ek ve
talimat metinlerini KISIM → MADDE → bent → fıkra düzeninde, matbaa
disipliniyle basar; sonra bastığını geri okuyup denetler.
M(2, "ÜCRET",
"<b>a) Net ücret:</b> Aylık net ücret 32.500,00 TL'dir (4857 s. K. m.32).",
"<b>b) Kesinti yasağı:</b> Kanunda gösterilen hâller dışında ücretten "
"<b>hiçbir kesinti yapılamaz.</b>")Numaralandırma, girinti, atıf italiği, sayfa kesme kuralları ve yetim başlık denetimi kendiliğinden işler.
ornekler/is-sozlesmesi.py
çıktısı — depoyu klonlayıp python3 ornekler/is-sozlesmesi.py
ile birebir üretebilirsiniz.
⚠️ Bu bir dizgi aracıdır, hukuki danışmanlık değildir. Metnin biçimini denetler, hukuka uygunluğunu denetlemez.atif_denetimibir atfın doğru maddeye gittiğini söyler; o maddenin doğru hüküm olduğunu söylemez. Ürettiğiniz belgenin hukuki sorumluluğu size aittir.
Türkçe bir sözleşmeyi kelime işlemciyle dizmek şu sorunları çözmez:
- Madde başlığı sayfanın dibinde yalnız kalır, gövdesi öbür sayfaya geçer.
- Sayfa geçişi bir tabloyu ortadan keser.
- Bir bent sayfada iki satır bırakıp devam eder.
- Madde eklenince atıflar sessizce yanlış maddeye gitmeye başlar — ölü atıf üretmeden, çünkü hedef madde vardır, sadece yanlıştır.
Son madde en sinsisi. Bir sözleşme 16 maddeden 22 maddeye yeniden numaralandığında "var mı yok mu" denetimi hiçbir hata bulmaz; hataları insan okuması yakalar, o da her zaman yakalamaz.
Bu kütüphane dördünü de yapısal olarak imkânsız kılar.
git clone https://github.com/niedy707/hukukdizgi.git
cd hukukdizgi
pip3 install reportlab pdfplumber
python3 ornekler/is-sozlesmesi.pyYazı tipi. Türkçe glifler için TTF zorunludur — ReportLab'ın gömülü
Times'ında ç ğ ı İ ö ş ü yoktur. ayar.py işletim sistemine göre Times New
Roman'ı (yoksa Liberation Serif'i) arar; bulamazsa açık bir hata verir,
sessizce başka yüze düşmez. Dört yüz de gerekir: kalın bir cümlenin içindeki
mevzuat atfı kalın+italik olur.
Tek yapılandırma dosyası hukukdizgi/ayar.py. Değerleri ya orada düzenleyin ya
da üreticinizin başında ezin — dizgi import'undan önce, yazı tipleri
orada kaydedilir:
from hukukdizgi import ayar
ayar.KURUM = "ÖRNEK LİMİTED ŞİRKETİ"
ayar.KENAR = 17 # mm
ayar.KISIM_RENK = "#12448C" # None → siyah
from hukukdizgi import dizgi, kurallar
from hukukdizgi.dizgi import antet, hukuki_dizgi, sayfali_canvas, veri_okuTam ve çalışan örnek: ornekler/is-sozlesmesi.py.
def uret(punto, oran, hedef):
"""AKIŞ HER ÇAĞRIDA SIFIRDAN KURULUR — esnek dizgi aynı belgeyi birkaç
aday punto/aralıkla belleğe basıp ölçer; flowable'lar tekrar kullanılamaz.
hedef=None → gerçek dosyaya yazılır."""
story = []
antet(story, "BELİRSİZ SÜRELİ İŞ SÖZLEŞMESİ", "4857 s. K.")
M, KISIM, atifla, sayac = hukuki_dizgi(
story, dizgi.W, punto=punto, oran=oran,
fikrali={(3, "b")}, # m.3/b (1)(2)(3) diye fıkralanır
kisim_yeni_sayfa=True,
)
KISIM("I", "TARAFLAR VE ÜCRET")
M(1, "TARAFLAR", "<b>a) İşveren:</b> …", bosluksuz=True)
M(2, "ÜCRET", "<b>a) Net ücret:</b> …", "<b>b) Kesinti yasağı:</b> …")
doc = SimpleDocTemplate(hedef or CIKTI, pagesize=A4, …)
doc.build(story, canvasmaker=sayfali_canvas(sol_alt="…", damga=True))
kurallar.esnek_dizgi(uret) # en iyi punto/aralığı seçer ve basarTek bir M() çağrısının ürettikleri: madde başlığı ve altındaki çizgi ·
a) b) bentleri · asılı girintili (1) (2) (3) fıkraları · italik
mevzuat atıfları (4857 s. K. m.63, m.68) · kalın vurgu · ve maddenin
ortasına giren, başlıktan asla ayrılmayan tablo.
| Seçenek | Ne yapar |
|---|---|
ara=[tablo] + blok_n=2 |
Tabloyu 2. bentten sonra, maddenin ortasına sokar; başlıktan ayrılmaz |
fikrali={(3, "b")} |
<br/><br/> ile bölünmüş bendi (1) (2) (3) diye fıkralar; ilk parça giriş cümlesi kalır |
yeni_sayfa=True |
Madde doğrudan sonraki sayfadan başlar |
bosluksuz=True |
Belgenin ilk madde başlığından önce boşluk bırakılmaz |
site="ornek.com" |
Başlığın sağına italik, tıklanabilir adres yazar |
DEVAM işareti |
Bir fıkranın ikinci paragrafı — numara almaz |
Bunlar üreticiye değil, SimpleDocTemplate.build'e sarmalıdır. Hangi
betikle basarsanız basın geçerlidir; butunle/tablo_koru/bent_kurali
çağırmanız gerekmez. Kapatmak için kurallar.KURAL_UYGULA = False.
| Kural | Uygulayan |
|---|---|
| Sayfa geçişi bir tabloyu asla kesmez | tablo_koru() |
| Başlık + açıklama + tablo ayrılmaz | butunle() |
| Yetim başlık yok — başlık sayfa dibinde yalnız kalmaz | baslik_bagla() |
| Üç satır kuralı — madde/fıkra/bent sayfada ≤3 satır bırakıp devam edemez; tamamı sonraki sayfaya geçer | Bent.split() |
| Öksüz satır yok — bölünen paragrafın her parçası ≥3 satır | Bent |
| Esnek dizgi — punto/aralık adayları belleğe basılır, ölçülür, yetim başlık bırakmayan seçilir | esnek_dizgi() |
| Bir bloğu sayfanın dibine yasla | DibeYasla |
ReportLab notu:
keepWithNextişaretli bir başlık, yükseklik hesaplarındaki uyuşmazlık yüzünden yine de sayfa dibinde yalnız kalabilir — bilinen ve çözülmemiş bir davranıştır.baslik_bagla()başlığın önüne ölçülmüş birCondPageBreakkoyarak bunu aşar.
Bir başlık ancak iki şart birlikte gerçekleşirse yetim sayılır: (1) altında o sayfada dört satırdan az kalmış, ve (2) madde o sayfada bitmemiş, gövdesi sonraki sayfaya taşmış. İkinci şart olmadan, sayfayı bitiren kısa bir madde (ör. belgenin son maddesi) yanlışlıkla yetim sayılır ve esnek dizgi bu hayalî ihlalden kaçmak için gereksiz yere punto küçültür.
Belge basıldıktan sonra çalışan bağımsız sınayıcılar. Motorun ürettiğine
güvenmez, PDF'i geri okurlar. Belge listesi belgeler.json'dan gelir:
{
"anlik": "atif-haritasi.json",
"ana": ["SÖZLEŞME", "ornekler/is-sozlesmesi.pdf"],
"ekler": [["EK-1", "ornekler/ek1.pdf"]]
}python3 araclar/atif_denetimi.py # denetle
python3 araclar/atif_denetimi.py --tam # tüm atıflar + hedef başlığı
python3 araclar/atif_denetimi.py --kaydet # onaylı anlık görüntüyü tazeleDört hata sınıfı:
- Ölü atıf — gösterdiği madde/bent hiç yok
- Hedef kayması — atıf duruyor ama gittiği başlık, onaylı anlık görüntüdekinden farklı (yeniden numaralamanın tipik hatası)
- Biçim — Türkçe ek uyumu (
Madde 5'daki→5'teki), aynı madde içindeMadde N/xyerine(x) bendikullanılmaması - Yetim — atıf hiçbir maddenin içinde değil
İki yön denetlenir: ekten ana belgeye (Sözleşme m.9/c) ve ekin kendi
maddelerine (Madde 27/b, (d) bendi). İkincisi kolayca gözden kaçan bir kör
noktadır.
Madde eklendiğinde, silindiğinde veya yeniden numaralandığında çalıştırılması zorunludur.
python3 araclar/pdf_kontrol.py # ana belge
python3 araclar/pdf_kontrol.py --hepsi # tüm set
python3 araclar/pdf_kontrol.py x.pdf # tek belgeBeş mercek: YAPI (madde/bent dizilimi, bent başlığı tutarlılığı) · İMLA (imla ikilileri, tekrarlanan kelime) · SAYI (belgenin kendi kısım/madde/ sayfa beyanı) · ŞEKİL (sayfa doluluğu, bölünmüş tablo, yetim başlık) · ATIF.
Mekanik katmanın temiz çıkması belgenin doğru olduğu anlamına gelmez. Anlam bütünlüğü okuması ayrıca yapılır.
python3 araclar/olc_vurgu.py uretici.pyGövdedeki kalın oranını ölçer. Ölçüt: %6'yı aşmasın, bir bentte en çok bir–iki vurgu. Bent ve madde başlıkları ölçüye girmez.
Kodun uygulamadığı ama uyulması gereken kurallar:
- Vurgu elle verilir. Kalıp eşleşmesiyle toplu kalın ekleyip silmek
yasaktır — cümlenin ortasından kelime kalınlaştırmak (
22:**00 saat**leri) böyle olur. Vurgu cümlenin dilbilgisel bütünlüğünü bölmez:<b>hiçbir kesinti yapılmaz</b>doğru,hiçbir <b>kesinti</b> yapılmazyanlıştır. - Değişken alanlar (tarih, ücret, ad): gövdeyle aynı yüz, bir punto
büyük, mavi
#12448C, kalın değil. Tek birdolgu()yardımcısıyla. - Ek adlandırması: bir belgenin kendi ekleri rakamla (EK-1, EK-2), başka belgenin eki harfle (EK-A) — imza setinde iki farklı "EK-1" dolaşmasın.
- Emoji kullanmayın. Times New Roman'da boş kutu basılır. Onay kutusu için
[ ]. Simgenin kendisi bilgi taşıyorsadizgi.simge_yuzu()kullanın. - Sayı biçimi Türkçe: binlik nokta, ondalık virgül (
56.082,92), eksi işareti−(U+2212). - Büyütme için
dizgi.buyuk()— Python'un.upper()/.title()metotları Türkçe farkında değildir,iharfini bozar.
Kimlik, adres, IBAN ve ücret gibi değerler üreticiye yazılmaz. Ayrı bir
veri dosyasında tutulur, veri_oku() ile okunur:
```ini
ad_soyad = Ad Soyad
ise_giris = 2025-05-09
net_ucret = 32.500,00
```python
K = veri_oku("veri.md")
K["ise_giris"] # datetime.date(2025, 5, 9)
Böylece aynı değer iki belgede farklı olamaz ve kişisel veri sürüm denetimine
karışmaz — gerçek projede bu dosya .gitignore'a alınır.
Karşı tarafa teslim edilmiş bir belgenin yeniden basılması, elindeki nüsha ile sizdekinin ayrışmasına yol açar — "belge sonradan değiştirildi" iddiasının en kolay dayanağı budur.
ayar.KILIT_DOSYA'da (varsayılan: çalışma klasöründe DONDURULDU.txt) adı
geçen PDF'ler basılamaz. Kilit SimpleDocTemplate.build'e konmuştur: hangi
yolla çalıştırılırsa çalıştırılsın — elle, betikle, for f in gen_*.py
döngüsüyle — dondurulmuş çıktı yazılamaz, BelgeDonduruldu ile durulur.
echo "sozlesme.pdf" >> DONDURULDU.txt # dondur
rm DONDURULDU.txt # çözÇözmeden önce karar verin: karşı tarafın elindeki nüsha ne olacak? Yeni nüsha teslim edilecek mi, yoksa değişiklik yalnızca ileriye mi işleyecek?
Kilit arşivin yerine geçmez; ikisi birlikte kullanılır. Teslim ettiğiniz
nüshanın birebir kopyasını ve shasum -a 256 *.pdf > SHA256.txt özetini ayrı
bir klasörde saklayın.
hukukdizgi/
├── ayar.py ← projeye göre değiştirilecek TEK dosya
├── dizgi.py ← stiller, sayfa öğeleri, KISIM/MADDE motoru
└── kurallar.py ← sayfa kesme kuralları, esnek dizgi, dondurma kilidi
araclar/
├── atif_denetimi.py
├── pdf_kontrol.py
├── olc_vurgu.py
└── gorsel_uret.py ← README görsellerini örnekten yeniden üretir
ornekler/
├── is-sozlesmesi.py
└── veri.md
varlik/ ← README görselleri (elle çizilmez, üretilir)
belgeler.json ← denetim araçlarının belge listesi
MIT — bkz. LICENSE.

