54378c7355
El SDK CI - dev / build-and-test (pull_request) Successful in 6m57s
Drop the bilingual-string-table framing and the external-encoder plan (both wrong). Translation now routes source-lexicon -> concept-frame (language- invariant, in the engram concept geometry) -> target-realizer, exactly as the ELP was designed: a word resolves to the CONCEPT it denotes via its own language's lexicon (a monolingual step — the engram nearest-region ranker only disambiguates senses within one language, so an English-trained embedder is fine and never compares 'ocean'~'oceano' as strings). The concept node is the shared pivot; its manifold location is the meaning. - Pronouns route through the NATIVE concept pivot (cp_pron_concept -> cp_rom_pron_surface) instead of an ad-hoc EN->tgt string map. - lemma_for_concept / noun_for_concept are each target language's own CONCEPT->SURFACE lexicon (the mirror of comprehend's SURFACE->CONCEPT). - Fidelity is concept-preservation (concept_frame fingerprint), not string cosine against an external multilingual model. - Plural article agreement fixed (las/los, as/os). Verified: 'You never fought the ocean.' -> ES 'Usted nunca luchó el océano.' concept-frame pivot 'pred=fight patient=ocean pol=neg' realizes to ES+PT from one parse; nunca holds 3/3. Gaps unchanged: PT verb conjugation fallback, adjunct/subordinator concepts not yet in-frame.
227 lines
12 KiB
EmacsLisp
227 lines
12 KiB
EmacsLisp
// translate.el - ELP geometry-native translation faculty (concept-pivot).
|
|
//
|
|
// ARCHITECTURE (corrected — Will, 2026-08-14): translation is NOT a bilingual
|
|
// string map and needs NO external multilingual encoder. It routes through the
|
|
// engram's concept geometry:
|
|
//
|
|
// comprehend(source) → CONCEPT-FRAME (language-invariant, in the manifold) → realize(target)
|
|
//
|
|
// A word in any language is resolved to the CONCEPT it denotes via that
|
|
// language's own lexicon/morphology (a monolingual step — the engram's
|
|
// nearest-region ranker only ever disambiguates senses WITHIN one language, so
|
|
// an English-trained embedder is fine and never compares "ocean" to "océano" as
|
|
// strings). The concept-node's location in the manifold IS the meaning; it is
|
|
// the shared pivot. "océano" and "ocean" need not be near each other as surface
|
|
// tokens — they resolve to the SAME concept node.
|
|
//
|
|
// This file supplies each target language's CONCEPT→SURFACE lexicon (its own
|
|
// labeling of the shared concept nodes) — the mirror image of comprehend.el's
|
|
// SURFACE→CONCEPT resolvers (cp_pron_concept, cp_analyze_verb/cp_irr2, …). The
|
|
// frame produced by parse_spec() is the interlingua: one parse realizes into N
|
|
// targets. Concept coverage below is the "Slowness" poem's inventory; a concept
|
|
// with no target label passes through and is flagged oov (honest bound).
|
|
//
|
|
// SACRED: polarity is a concept and is never routed to a content lemma. The
|
|
// negative-adverb concept ("never") realizes to a target negator ("nunca"/"mai"),
|
|
// never to a content word.
|
|
//
|
|
// Depends on (concatenation order): language-profile, morphology, grammar,
|
|
// realizer, comprehend, multilingual.
|
|
|
|
// ── VERB concept → target lemma (each language's own labeling of the concept) ──
|
|
// The input is the language-invariant verb concept (English lemma = concept id,
|
|
// exactly as comprehend.el emits it). NOT a translation of a Spanish string.
|
|
fn lemma_for_concept(concept: String, lang: String) -> String {
|
|
if str_eq(lang, "en") { return concept }
|
|
if str_eq(lang, "es") {
|
|
if str_eq(concept, "fight") { return "luchar" }
|
|
if str_eq(concept, "touch") { return "tocar" }
|
|
if str_eq(concept, "wait") { return "esperar" }
|
|
if str_eq(concept, "see") { return "ver" }
|
|
if str_eq(concept, "break") { return "romper" }
|
|
if str_eq(concept, "stay") { return "quedar" }
|
|
if str_eq(concept, "call") { return "llamar" }
|
|
if str_eq(concept, "run") { return "correr" }
|
|
if str_eq(concept, "chase") { return "perseguir" }
|
|
if str_eq(concept, "take") { return "tomar" }
|
|
if str_eq(concept, "carry") { return "llevar" }
|
|
return ml_translate_pred(concept, "es")
|
|
}
|
|
if str_eq(lang, "pt") {
|
|
if str_eq(concept, "fight") { return "lutar" }
|
|
if str_eq(concept, "touch") { return "tocar" }
|
|
if str_eq(concept, "wait") { return "esperar" }
|
|
if str_eq(concept, "see") { return "ver" }
|
|
if str_eq(concept, "break") { return "quebrar" }
|
|
if str_eq(concept, "stay") { return "ficar" }
|
|
if str_eq(concept, "call") { return "chamar" }
|
|
if str_eq(concept, "run") { return "correr" }
|
|
if str_eq(concept, "chase") { return "perseguir" }
|
|
if str_eq(concept, "take") { return "tomar" }
|
|
if str_eq(concept, "carry") { return "levar" }
|
|
return ml_translate_pred(concept, "pt")
|
|
}
|
|
if str_eq(lang, "it") {
|
|
if str_eq(concept, "fight") { return "lottare" }
|
|
if str_eq(concept, "touch") { return "toccare" }
|
|
if str_eq(concept, "wait") { return "aspettare" }
|
|
if str_eq(concept, "see") { return "vedere" }
|
|
if str_eq(concept, "break") { return "rompere" }
|
|
if str_eq(concept, "stay") { return "restare" }
|
|
return ml_translate_pred(concept, "it")
|
|
}
|
|
return concept
|
|
}
|
|
|
|
// ── NOUN concept → [target lemma, gender] (target language's concept lexicon) ──
|
|
fn noun_for_concept(concept: String, lang: String) -> [String] {
|
|
let out: [String] = native_list_empty()
|
|
if str_eq(lang, "es") {
|
|
if str_eq(concept, "ocean") { let out = native_list_append(out, "océano"); let out = native_list_append(out, "m"); return out }
|
|
if str_eq(concept, "root") { let out = native_list_append(out, "raíz"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "roots") { let out = native_list_append(out, "raíces"); let out = native_list_append(out, "fp"); return out }
|
|
if str_eq(concept, "breaking") { let out = native_list_append(out, "ruptura"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "shoreline") { let out = native_list_append(out, "orilla"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "patience") { let out = native_list_append(out, "paciencia"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "wave") { let out = native_list_append(out, "ola"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "truth") { let out = native_list_append(out, "verdad"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "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(concept, "ocean") { let out = native_list_append(out, "oceano"); let out = native_list_append(out, "m"); return out }
|
|
if str_eq(concept, "root") { let out = native_list_append(out, "raiz"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "roots") { let out = native_list_append(out, "raízes"); let out = native_list_append(out, "fp"); return out }
|
|
if str_eq(concept, "breaking") { let out = native_list_append(out, "ruptura"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "shoreline") { let out = native_list_append(out, "costa"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "patience") { let out = native_list_append(out, "paciência"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "wave") { let out = native_list_append(out, "onda"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "truth") { let out = native_list_append(out, "verdade"); let out = native_list_append(out, "f"); return out }
|
|
if str_eq(concept, "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+number tag / lang. "f"|"m" singular, "fp"|"mp" plural.
|
|
fn article_for(gtag: String, lang: String) -> String {
|
|
if str_eq(lang, "es") {
|
|
if str_eq(gtag, "fp") { return "las" }
|
|
if str_eq(gtag, "mp") { return "los" }
|
|
if str_eq(gtag, "f") { return "la" }
|
|
return "el"
|
|
}
|
|
if str_eq(lang, "pt") {
|
|
if str_eq(gtag, "fp") { return "as" }
|
|
if str_eq(gtag, "mp") { return "os" }
|
|
if str_eq(gtag, "f") { return "a" }
|
|
return "o"
|
|
}
|
|
if str_eq(lang, "it") { if str_eq(gtag, "f") { return "la" } return "il" }
|
|
return "the"
|
|
}
|
|
|
|
// SURFACE→CONCEPT for an English object NP: strip determiner, return bare head
|
|
// (which, for content nouns, is already the concept id).
|
|
fn np_concept_head(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
|
|
}
|
|
|
|
// CONCEPT→SURFACE: realize an object-NP concept in the target language with its
|
|
// definite article. Unknown concept => pass the English head through (oov).
|
|
fn np_for_concept(np: String, lang: String) -> String {
|
|
if str_eq(np, "") { return "" }
|
|
let head: String = np_concept_head(np)
|
|
let pair: [String] = noun_for_concept(head, lang)
|
|
if native_list_len(pair) < 2 { return head }
|
|
let lemma: String = native_list_get(pair, 0)
|
|
let gtag: String = native_list_get(pair, 1)
|
|
return article_for(gtag, lang) + " " + lemma
|
|
}
|
|
|
|
// SURFACE→CONCEPT for a subject pronoun, then CONCEPT→SURFACE in the target —
|
|
// reusing comprehend.el's NATIVE concept-pivot (cp_pron_concept /
|
|
// cp_rom_pron_surface). This is the template the whole faculty follows.
|
|
fn pron_for_target(agent: String, lang: String) -> String {
|
|
let concept: String = cp_pron_concept(str_to_lower(agent))
|
|
if str_eq(concept, "") { return agent }
|
|
if str_eq(lang, "en") { return cp_pron_surface(concept) }
|
|
return cp_rom_pron_surface(concept, lang)
|
|
}
|
|
|
|
// The negative-adverb concept realized as the target's preverbal negator (SACRED).
|
|
fn negator_for_concept(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 ""
|
|
}
|
|
|
|
// Some irregular English pasts that comprehend's cp_irr2 does not yet lemmatize
|
|
// (source-side SURFACE→CONCEPT gap). Kept minimal; belongs long-term in cp_irr2.
|
|
fn concept_of_verb(w: String) -> String {
|
|
if str_eq(w, "broke") { return "break" }
|
|
if str_eq(w, "broken") { return "break" }
|
|
if str_eq(w, "took") { return "take" }
|
|
if str_eq(w, "ran") { return "run" }
|
|
return w
|
|
}
|
|
|
|
// ── the faculty: EN text → concept-frame → target surface ─────────────────────
|
|
fn translate_spec(text: String, tgt: String) -> [String] {
|
|
// 1. comprehend(source) → concept-frame (English lemmas = concept ids +
|
|
// SACRED polarity/neg_word). This frame lives in the concept geometry.
|
|
let spec: [String] = parse_spec(text)
|
|
let predc: String = concept_of_verb(slots_get(spec, "predicate"))
|
|
let patc: String = slots_get(spec, "patient")
|
|
let agentc: String = slots_get(spec, "agent")
|
|
let negw: String = slots_get(spec, "neg_word")
|
|
|
|
// 2. realize(target): resolve each concept to the target language's surface.
|
|
let spec = slots_set(spec, "predicate", lemma_for_concept(predc, tgt))
|
|
let spec = slots_set(spec, "patient", np_for_concept(patc, tgt))
|
|
let spec = slots_set(spec, "agent", pron_for_target(agentc, tgt))
|
|
let tw: String = negator_for_concept(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))
|
|
}
|
|
|
|
// Concept-frame fingerprint (for concept-preservation fidelity — geometry-native,
|
|
// NOT a string cosine): the source-language-invariant concept tuple.
|
|
fn concept_frame(text: String) -> String {
|
|
let spec: [String] = parse_spec(text)
|
|
let predc: String = concept_of_verb(slots_get(spec, "predicate"))
|
|
return "pred=" + predc + " patient=" + np_concept_head(slots_get(spec, "patient")) + " pol=" + slots_get(spec, "polarity")
|
|
}
|