April 16, 2026 · Gökhan Oğuz

Teaching an App Turkish

Translating an AAC app isn't like translating a website. You can't run 3,436 symbol labels through Google Translate and call it done. This is the story of getting Sesla to actually speak Turkish — from symbol translations to grammar-aware sentence building.

3,436

Symbols Translated

100%

TR Coverage

325

Culturally Filtered

334

Grammar Tests

The Translation Problem

Mulberry Symbols were designed for English-speaking countries. Many symbols are straightforward — "cat" is "kedi," "water" is "su." But hundreds required real thought.

Take country flags. The English label "France" works fine, but the Turkish translation isn't "France" — it's "Fransa." And it's not just names: "football kit" becomes "futbol forması," "cricket" has no natural Turkish equivalent, and "Boxing Day" is meaningless outside the Commonwealth.

Then there are the duplicates. Machine translation gives you "Bayrak" for every flag, "Forma" for every kit, and identical translations for symbols that should be distinct. We ran four passes of deduplication scripts, differentiating 970+ symbols that would have had identical labels.

Cultural Filtering

An AAC app for Turkish children shouldn't show symbols for "Church of England," "Christening," or "Three Kings." These aren't offensive — they're just irrelevant, and they waste grid space that should go to symbols the child actually needs.

We built a hidden_tr flag system. 325 symbols are marked hidden for the Turkish locale:

The hidden symbols still exist in the data — they're just filtered at seed time. A future English-locale user sees all 3,436. A Turkish user sees 3,111.

SVG Rendering: The Invisible Bug

After loading all symbols, we noticed something odd: about 300 symbols rendered as solid black silhouettes. The SVGs looked fine in a browser but were dark in the app.

The culprit: CSS <style> blocks inside the SVGs. Mulberry uses CSS classes like .st0{fill:#ffffc2} for colors. Flutter's flutter_svg package doesn't parse CSS — it only reads inline fill and stroke attributes.

The fix was a Python script that parsed each SVG's CSS rules, resolved combined selectors (like .st2,.st3{fill:#fff} followed by .st3{stroke:#000} — where properties merge, not replace), and inlined them as direct SVG attributes. 317 SVGs fixed. Ten remain with @font-face declarations for embedded text — a minor cosmetic issue.

From Symbol Taps to Sentences

The real challenge isn't translation — it's grammar. When a child taps BenOkulGitmek, the app shouldn't speak "Ben Okul Gitmek" (I School To-go). It should say "Ben okula gidiyorum" (I'm going to school).

Three things happened there: "Okul" got lowercased (it's mid-sentence), it received the dative suffix "-a" (because "gitmek" is a movement verb and "okul" is a destination), and "gitmek" was conjugated to first-person present continuous with consonant softening (git → gid → gidiyorum).

The sentence builder does this in three passes:

Pass 1 — Scan for markers. Time markers set the tense: "Dün" (yesterday) → past, "Yarın" (tomorrow) → future. "Hayır" (no) triggers negation. Pronouns set the person. Subject nouns like "Anne" (mom) or "Köpek" (dog) trigger third person.

Pass 2 — Build output. The last verb infinitive gets conjugated with the detected tense, person, and negation. Preceding verbs stay infinitive (complement position). Location nouns before movement verbs get dative case.

Pass 3 — Lowercase. Non-first words get Turkish-aware lowercasing — this matters because Turkish has two distinct "i" letters: İ→i and I→ı.

The Benchmark

Grammar engines are only as good as their test coverage. We built a 334-case benchmark corpus covering:

All 334 cases pass. Three known gaps remain: accusative case marking ("bebeği" instead of "bebek"), word reordering (verb-before-noun sequences), and one verb not yet in the dictionary. These are documented as targetExpected fields in the test corpus — when the engine improves, the tests automatically detect the resolution.

AAC grammar doesn't need to be perfect. It needs to be better than the alternative — which is no grammar at all. "Ben okula gidiyorum" is miles ahead of "Ben Okul Gitmek."

Category Ordering

With 3,111 symbols across 16 categories, ordering matters. We wrote a sorting engine with curated priority lists for each category. Numbers go 0–9, then teens, tens, hundreds. Feelings start with "Mutlu" (happy), "Üzgün" (sad), "Kızgın" (angry). Actions start with core verbs: gitmek, gelmek, yapmak.

Items not in the priority list fall back to Turkish alphabetical order — with proper handling of ç, ğ, ı, ö, ş, ü. Not as trivial as it sounds when your sort function needs to know that "ç" comes after "c" but before "d."

What's Next

The Turkish language layer is solid. Next: beta testing with real families, App Store submission, and the features that only become obvious once real users start tapping symbols.