elp(translate): EN->ES/PT geometric-free translation faculty

Adds the missing middle of the ELP: a deterministic EN-content-lemma ->
target-lemma bridge (translate.el) on top of comprehend.el (parse) and
realizer.el (inflect). English-only engram geometry cannot route
cross-lingually and vocabulary-XX.el carries no en_translation glosses, so
the honest no-LLM bridge is a wired lexicon (poem coverage; OOV passes
through). SACRED polarity/neg_word are carried untouched: 'never' localizes
to a negator ('nunca'), never to a content lemma.

Additive realizer extensions: agent_person/agent_number recognize Romance
target pronouns; the non-EN negation branch surfaces a carried neg_word
instead of the generic negator.

Verified on the real toolchain (elc->cc->run):
  'You never fought the ocean.' -> ES 'Tú nunca luchaste el océano.'
  'I never saw the breaking.'   -> ES 'Yo nunca vi la ruptura.'
nunca holds 3/3 negation lines. Known gaps: PT verb conjugation fallback
(lutarred), irregular EN lemma (broke->break), adjunct/subordinator passthrough.
This commit is contained in:
Neuron
2026-08-14 17:37:01 -05:00
parent ce34b94f88
commit 9b63a2a23b
3 changed files with 275 additions and 0 deletions
+207
View File
@@ -0,0 +1,207 @@
// translate.el - ELP geometric-free translation faculty (EN -> ES/PT/IT).
//
// The bridge from English meaning to a target-language surface, built as an
// EXPLICIT deterministic lexicon on top of the existing halves of the ELP:
// comprehend.el parse_spec(text) : EN surface -> meaning-spec (SACRED polarity)
// realizer.el realize(spec) : meaning-spec -> target surface (inflection)
// translate.el supplies the missing middle: EN content lemma -> target lemma.
//
// WHY an explicit table and not geometry: the live engram embedder
// (nomic-embed-text) is English-only cross-lingual nearest-neighbour routing
// is near-random (ocean~dog 0.51 > ocean~oceano 0.43), and vocabulary-XX.el
// carries no en_translation glosses. So the honest, deterministic, no-LLM bridge
// is a wired lexicon. Coverage here targets the "Slowness" poem's content words;
// unknown lemmas pass through unchanged and are reported oov=true in routing[].
//
// SACRED: polarity and neg_word are NEVER routed through the content bridge.
// "never" localizes to "nunca"/"nunca"/"mai" as a negator, never to a lemma.
//
// Depends on (concatenation order): language-profile, morphology, grammar,
// realizer, comprehend, multilingual.
// EN verb lemma -> target infinitive
fn tr_pred(lemma: String, lang: String) -> String {
if str_eq(lang, "en") { return lemma }
if str_eq(lang, "es") {
if str_eq(lemma, "fight") { return "luchar" }
if str_eq(lemma, "touch") { return "tocar" }
if str_eq(lemma, "wait") { return "esperar" }
if str_eq(lemma, "see") { return "ver" }
if str_eq(lemma, "break") { return "romper" }
if str_eq(lemma, "stay") { return "quedar" }
if str_eq(lemma, "call") { return "llamar" }
if str_eq(lemma, "run") { return "correr" }
if str_eq(lemma, "chase") { return "perseguir" }
if str_eq(lemma, "take") { return "tomar" }
if str_eq(lemma, "carry") { return "llevar" }
return tr_pred_fallback(lemma, "es")
}
if str_eq(lang, "pt") {
if str_eq(lemma, "fight") { return "lutar" }
if str_eq(lemma, "touch") { return "tocar" }
if str_eq(lemma, "wait") { return "esperar" }
if str_eq(lemma, "see") { return "ver" }
if str_eq(lemma, "break") { return "quebrar" }
if str_eq(lemma, "stay") { return "ficar" }
if str_eq(lemma, "call") { return "chamar" }
if str_eq(lemma, "run") { return "correr" }
if str_eq(lemma, "chase") { return "perseguir" }
if str_eq(lemma, "take") { return "tomar" }
if str_eq(lemma, "carry") { return "levar" }
return tr_pred_fallback(lemma, "pt")
}
if str_eq(lang, "it") {
if str_eq(lemma, "fight") { return "lottare" }
if str_eq(lemma, "touch") { return "toccare" }
if str_eq(lemma, "wait") { return "aspettare" }
if str_eq(lemma, "see") { return "vedere" }
if str_eq(lemma, "break") { return "rompere" }
if str_eq(lemma, "stay") { return "restare" }
return tr_pred_fallback(lemma, "it")
}
return lemma
}
// Second-tier verbs already covered by the older multilingual table.
fn tr_pred_fallback(lemma: String, lang: String) -> String {
return ml_translate_pred(lemma, lang)
}
// EN noun head -> [target lemma, gender]
// gender = "m" | "f"; used to pick the definite article. Empty lemma => unknown.
fn tr_noun_pair(head: String, lang: String) -> [String] {
let out: [String] = native_list_empty()
if str_eq(lang, "es") {
if str_eq(head, "ocean") { let out = native_list_append(out, "océano"); let out = native_list_append(out, "m"); return out }
if str_eq(head, "root") { let out = native_list_append(out, "raíz"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "roots") { let out = native_list_append(out, "raíces"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "breaking") { let out = native_list_append(out, "ruptura"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "shoreline") { let out = native_list_append(out, "orilla"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "patience") { let out = native_list_append(out, "paciencia"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "wave") { let out = native_list_append(out, "ola"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "truth") { let out = native_list_append(out, "verdad"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "silence") { let out = native_list_append(out, "silencio"); let out = native_list_append(out, "m"); return out }
return out
}
if str_eq(lang, "pt") {
if str_eq(head, "ocean") { let out = native_list_append(out, "oceano"); let out = native_list_append(out, "m"); return out }
if str_eq(head, "root") { let out = native_list_append(out, "raiz"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "roots") { let out = native_list_append(out, "raízes"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "breaking") { let out = native_list_append(out, "ruptura"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "shoreline") { let out = native_list_append(out, "costa"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "patience") { let out = native_list_append(out, "paciência"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "wave") { let out = native_list_append(out, "onda"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "truth") { let out = native_list_append(out, "verdade"); let out = native_list_append(out, "f"); return out }
if str_eq(head, "silence") { let out = native_list_append(out, "silêncio"); let out = native_list_append(out, "m"); return out }
return out
}
return out
}
// definite article for a gender/lang.
fn tr_def_article(gender: String, lang: String) -> String {
if str_eq(lang, "es") { if str_eq(gender, "f") { return "la" } return "el" }
if str_eq(lang, "pt") { if str_eq(gender, "f") { return "a" } return "o" }
if str_eq(lang, "it") { if str_eq(gender, "f") { return "la" } return "il" }
return "the"
}
// strip a leading English determiner, return the bare head noun (lowercased).
fn tr_strip_det(np: String) -> String {
let s: String = str_to_lower(np)
let dets: [String] = native_list_empty()
let dets = native_list_append(dets, "the ")
let dets = native_list_append(dets, "a ")
let dets = native_list_append(dets, "an ")
let dets = native_list_append(dets, "my ")
let dets = native_list_append(dets, "your ")
let dets = native_list_append(dets, "his ")
let dets = native_list_append(dets, "her ")
let dets = native_list_append(dets, "its ")
let dets = native_list_append(dets, "our ")
let dets = native_list_append(dets, "their ")
let dets = native_list_append(dets, "every ")
let i: Int = 0
let n: Int = native_list_len(dets)
while i < n {
let d: String = native_list_get(dets, i)
let dl: Int = str_len(d)
if str_len(s) > dl {
if str_eq(str_slice(s, 0, dl), d) {
return str_slice(s, dl, str_len(s))
}
}
let i = i + 1
}
return s
}
// translate an English object NP into a target NP with definite article.
// Unknown head => pass the English head through (honest OOV), no article.
fn tr_np(np: String, lang: String) -> String {
if str_eq(np, "") { return "" }
let head: String = tr_strip_det(np)
let pair: [String] = tr_noun_pair(head, lang)
if native_list_len(pair) < 2 { return head }
let lemma: String = native_list_get(pair, 0)
let gender: String = native_list_get(pair, 1)
let art: String = tr_def_article(gender, lang)
return art + " " + lemma
}
// translate an English subject pronoun to the target pronoun (keeps person).
fn tr_pronoun(agent: String, lang: String) -> String {
let a: String = str_to_lower(agent)
if str_eq(lang, "es") {
if str_eq(a, "i") { return "yo" }
if str_eq(a, "you") { return "" }
if str_eq(a, "he") { return "él" }
if str_eq(a, "she") { return "ella" }
if str_eq(a, "we") { return "nosotros" }
if str_eq(a, "they") { return "ellos" }
}
if str_eq(lang, "pt") {
if str_eq(a, "i") { return "eu" }
if str_eq(a, "you") { return "tu" }
if str_eq(a, "he") { return "ele" }
if str_eq(a, "she") { return "ela" }
if str_eq(a, "we") { return "nós" }
if str_eq(a, "they") { return "eles" }
}
return agent
}
// localize a standalone negative adverb (SACRED). "never" -> preverbal negator.
fn tr_neg_word(neg_word: String, lang: String) -> String {
let w: String = str_to_lower(neg_word)
if str_eq(w, "never") {
if str_eq(lang, "es") { return "nunca" }
if str_eq(lang, "pt") { return "nunca" }
if str_eq(lang, "it") { return "mai" }
}
return ""
}
// the faculty: EN text -> target surface
// Parses EN (mature path), swaps content lemmas via the wired bridge, carries
// SACRED polarity/neg_word untouched, and hands a target-lang spec to realize().
fn translate_spec(text: String, tgt: String) -> [String] {
let spec: [String] = parse_spec(text)
let pred: String = slots_get(spec, "predicate")
let pat: String = slots_get(spec, "patient")
let agent: String = slots_get(spec, "agent")
let negw: String = slots_get(spec, "neg_word")
let spec = slots_set(spec, "predicate", tr_pred(pred, tgt))
let spec = slots_set(spec, "patient", tr_np(pat, tgt))
let spec = slots_set(spec, "agent", tr_pronoun(agent, tgt))
// SACRED: neg_word localized to a negator, polarity left exactly as parsed.
let tw: String = tr_neg_word(negw, tgt)
if !str_eq(tw, "") { let spec = slots_set(spec, "neg_word", tw) }
let spec = slots_set(spec, "lang", tgt)
return spec
}
fn translate_line(text: String, tgt: String) -> String {
return realize(translate_spec(text, tgt))
}