# Türkçe formlar

> Türkçe hata mesajları, TCKN/IBAN/telefon doğrulama ve il/ilçe seçimiyle form yazma.

create-trkit-app projelerindeki `src/app/iletisim/` dizini çalışan bir örnektir. Bu sayfa o örneği adım adım açıklar.

## 1. Şema

```ts title="src/app/iletisim/schema.ts"
import { cepTelefonu } from "@trkit-app-pack/validate";
import { isValidDistrict } from "@trkit-app-pack/address";
import { basHarfleriBuyut } from "@trkit-app-pack/format";
import { z } from "@/lib/zod"; // Türkçe hata mesajları

export const iletisimSchema = z
  .object({
    adSoyad: z.string().trim().min(3).max(80).transform(basHarfleriBuyut),
    eposta: z.email(),
    telefon: cepTelefonu,                       // "0532 123 45 67" → "+905321234567"
    il: z.coerce.number().int().min(1, "İl seçiniz").max(81),
    ilce: z.string({ message: "İlçe seçiniz" }).min(1, "İlçe seçiniz"),
    mesaj: z.string().trim().min(10).max(2000),
    ticariIleti: z.boolean().default(false),
  })
  .refine((v) => isValidDistrict(v.il, v.ilce), { path: ["ilce"], message: "Seçilen ilçe bu ile ait değil" });
```

Hazır mesajlar: "En az 3 karakter olmalıdır", "Geçerli bir e-posta adresi giriniz", "Bu alan zorunludur", "Geçerli bir cep telefonu giriniz (5XX XXX XX XX)".

## 2. Server action

```ts title="src/app/iletisim/actions.ts"
"use server";
import { iletisimSchema } from "./schema";

export async function iletisimGonder(_prev: FormState, formData: FormData): Promise<FormState> {
  const values = Object.fromEntries(formData) as Record<string, string>;
  const parsed = iletisimSchema.safeParse({ ...values, ticariIleti: values.ticariIleti === "on" });
  if (!parsed.success) {
    const errors: Record<string, string> = {};
    for (const i of parsed.error.issues) errors[String(i.path[0])] ??= i.message;
    return { status: "error", errors, values };
  }
  // parsed.data.telefon E.164 biçiminde, adSoyad düzgün büyük harfli
  return { status: "success", adSoyad: parsed.data.adSoyad };
}
```

## 3. Form

```tsx
const [state, action, pending] = useActionState(iletisimGonder, { status: "idle" });
const [konum, setKonum] = useState<IlIlceDegeri>({ il: null, ilce: null });

<form action={action}>
  <input name="telefon" type="tel" inputMode="tel" autoComplete="tel-national" placeholder="05XX XXX XX XX" />
  <IlIlceSecici value={konum} onChange={setKonum} name={{ il: "il", ilce: "ilce" }} error={{ il: err.il, ilce: err.ilce }} />
</form>
```

## Hazır şemalar

| Şema | Kabul eder | Dönüştürür |
|---|---|---|
| `tckn` | 11 hane, algoritma kontrolü | boşlukları temizler |
| `vkn` | 10 hane, algoritma kontrolü | |
| `vergiNo` | TCKN veya VKN (fatura formları) | |
| `iban` | TR IBAN, mod-97 | `TR33 0006 …` → `TR330006…` |
| `telefon` | mobil, sabit, 850 | E.164 `+90…` |
| `cepTelefonu` | yalnızca 5XX | E.164 |
| `plaka` | `34 ABC 123` vb. | `34ABC123` |
| `postaKodu` | 5 hane, il kodu 01–81 | |
| `mersis` | 16 hane | |

Özel mesaj için şema fabrikalarını kullanın: `tcknSchema({ message: "TC kimlik numaranızı kontrol edin" })`, `phoneSchema({ mobileOnly: true })`.

## İpuçları

- Telefon alanında `inputMode="tel"` mobilde rakam klavyesini açar.
- TCKN algoritma kontrolü numaranın gerçek bir kişiye ait olduğunu göstermez. Kimlik doğrulaması gerekiyorsa NVİ KPS servisi gerekir.
- Loglarda `maskTckn()` ve `maskPhone()` kullanın.
