Amélioration système de traduction: normalisation, lexique et couverture

Corrections majeures:
- Normalisation ligatures (œ→oe, æ→ae) pour éviter fragmentation tokens
- Normalisation complète lexique (clés + synonymes) sans accents
- Correction faux positif "dansent"→"dans" (longueur radical ≥5)

Enrichissement lexique (+212 entrées):
- Verbes: battre (pulum), penser/réfléchir (umis), voler (aliuk)
- Mots grammaticaux: nous (tanu), possessifs (sa/mon→na), démonstratifs (ce→ko)
- Temporels: hier/avant (at), demain/après (ok), autour (no)
- Formes conjuguées ajoutées pour manger, battre, penser

Améliorations techniques:
- Lemmatisation verbale améliorée (radical ≥5 lettres)
- Système normalizeText() dans lexiqueLoader.js
- Liaisons sacrées pour compositions culturelles

Note: Problème connu de lemmatisation à investiguer (formes fléchies non trouvées)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
StillHammer 2025-11-30 22:37:31 +08:00
parent fd3e286bb1
commit 889cd24319
10 changed files with 919 additions and 71 deletions

View File

@ -2,7 +2,8 @@
"permissions": {
"allow": [
"Bash(curl:*)",
"Bash(python -m json.tool:*)"
"Bash(python -m json.tool:*)",
"Bash(python3:*)"
],
"deny": [],
"ask": []

View File

@ -115,6 +115,29 @@ sili (regard) + -i- (agent) + aska (libre)
### Peuple
**Siliaska** = "Les porteurs du regard libre"
## API ConfluentTranslator
Le serveur de traduction (`ConfluentTranslator/server.js`) expose les endpoints suivants :
### Gestion des lexiques
- **GET** `/lexique` - Retourne le lexique ancien (legacy)
- **GET** `/api/lexique/:variant` - Retourne le lexique pour `proto` ou `ancien`
- **GET** `/api/stats` - Statistiques des lexiques chargés
- **POST** `/api/reload` - Recharge les lexiques (développement)
### Recherche et analyse
- **GET** `/api/search?q=<mot>&variant=<proto|ancien>&direction=<fr2conf|conf2fr>` - Recherche dans le lexique
- **POST** `/api/analyze/coverage` - Analyse la couverture d'un texte français avant traduction
### Traduction
- **POST** `/translate` - Traduction FR → Confluent avec système contextuel (retourne layers 1-3)
- **POST** `/api/translate/raw` - Traduction brute sans parsing (debug)
- **POST** `/api/translate/batch` - Traduction par lot de mots
- **POST** `/api/translate/conf2fr` - Traduction Confluent → FR
### Debug
- **POST** `/api/debug/prompt` - Génère le prompt système sans appeler le LLM
## Prochaines étapes
1. Enrichir le lexique (verbes, concepts abstraits, émotions...)

View File

@ -93,7 +93,7 @@ function searchConfluent(word, reverseIndex) {
}
// 5. NOUVEAU: Décomposition morphologique
const decompositions = decomposeWord(lowerWord);
const decompositions = decomposeWord(lowerWord, reverseIndex);
for (const decomp of decompositions) {
const part1Match = searchConfluent(decomp.part1, reverseIndex);
const part2Match = searchConfluent(decomp.part2, reverseIndex);

View File

@ -28,9 +28,11 @@ function tokenizeFrench(text) {
]);
// ÉTAPE 1: Normaliser et nettoyer le texte
// ORDRE IMPORTANT: lowercase → accents → contractions
// ORDRE IMPORTANT: lowercase → ligatures → accents → contractions
let processedText = text
.toLowerCase()
.replace(/œ/g, 'oe') // Ligature œ → oe (cœur → coeur)
.replace(/æ/g, 'ae') // Ligature æ → ae
.normalize('NFD') // Décompose les caractères accentués
.replace(/[\u0300-\u036f]/g, ''); // Retire les diacritiques (é→e, è→e, ê→e, etc.)
@ -143,7 +145,12 @@ function simpleLemmatize(word) {
if (word.endsWith(ending) && word.length > ending.length + 2) {
const root = word.slice(0, -ending.length);
forms.push(root + replacement);
forms.push(root); // juste la racine aussi
// Ajouter le radical seul UNIQUEMENT s'il fait au moins 5 lettres
// Évite: "dansent" → "dans" (4 lettres, faux positif avec particule "dans")
// Accepte: "écoutent" → "écoute" (6 lettres), "observent" → "observe" (7 lettres)
if (root.length >= 5) {
forms.push(root);
}
}
}
@ -175,9 +182,10 @@ function simpleLemmatize(word) {
* Cherche un mot dans le dictionnaire (correspondance exacte ou synonyme)
* @param {string} word - Mot à chercher
* @param {Object} dictionnaire - Dictionnaire du lexique
* @param {string} normalizedText - Texte original normalisé (pour vérifier frontières)
* @returns {Array} - Entrées trouvées avec score
*/
function searchWord(word, dictionnaire) {
function searchWord(word, dictionnaire, normalizedText = '') {
const results = [];
const lemmas = simpleLemmatize(word);
@ -224,9 +232,10 @@ function searchWord(word, dictionnaire) {
* @param {string[]} words - Liste de mots
* @param {Object} lexique - Lexique complet
* @param {number} maxEntries - Nombre max d'entrées
* @param {string} normalizedText - Texte original normalisé (pour vérifier frontières)
* @returns {Object} - Résultat avec entrées trouvées et métadonnées
*/
function findRelevantEntries(words, lexique, maxEntries) {
function findRelevantEntries(words, lexique, maxEntries, normalizedText = '') {
const foundEntries = new Map(); // key: mot_francais, value: entry
const wordsFound = []; // Pour Layer 2
const wordsNotFound = [];
@ -243,7 +252,7 @@ function findRelevantEntries(words, lexique, maxEntries) {
// Chercher chaque mot
for (const word of words) {
const results = searchWord(word, lexique.dictionnaire);
const results = searchWord(word, lexique.dictionnaire, normalizedText);
if (results.length > 0) {
// Prendre la meilleure correspondance
@ -380,6 +389,14 @@ function extractRoots(lexique) {
function analyzeContext(text, lexique, options = {}) {
const expansionLevel = options.expansionLevel || 1;
// 0. Normaliser le texte (pour vérifier frontières de mots plus tard)
const normalizedText = text
.toLowerCase()
.replace(/œ/g, 'oe')
.replace(/æ/g, 'ae')
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '');
// 1. Tokenization
const words = tokenizeFrench(text);
const uniqueWords = [...new Set(words)];
@ -387,8 +404,8 @@ function analyzeContext(text, lexique, options = {}) {
// 2. Calculer limite dynamique
const maxEntries = calculateMaxEntries(words.length);
// 3. Trouver entrées pertinentes
const searchResult = findRelevantEntries(uniqueWords, lexique, maxEntries);
// 3. Trouver entrées pertinentes (avec texte normalisé pour vérifier frontières)
const searchResult = findRelevantEntries(uniqueWords, lexique, maxEntries, normalizedText);
// 4. Expansion sémantique
const expandedEntries = expandContext(

View File

@ -1,6 +1,20 @@
const fs = require('fs');
const path = require('path');
/**
* Normalise un texte : lowercase + retire accents + ligatures
* @param {string} text - Texte à normaliser
* @returns {string} - Texte normalisé
*/
function normalizeText(text) {
return text
.toLowerCase()
.replace(/œ/g, 'oe')
.replace(/æ/g, 'ae')
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '');
}
/**
* Charge dynamiquement tous les fichiers de lexique d'un dossier
* @param {string} lexiqueDir - Chemin vers le dossier contenant les fichiers JSON
@ -33,7 +47,7 @@ function loadLexiqueFromDir(lexiqueDir) {
if (content.dictionnaire) {
// Fusionner les entrées
for (const [motFr, data] of Object.entries(content.dictionnaire)) {
const key = motFr.toLowerCase();
const key = normalizeText(motFr);
if (!result.dictionnaire[key]) {
result.dictionnaire[key] = {
@ -67,7 +81,7 @@ function loadLexiqueFromDir(lexiqueDir) {
result.dictionnaire[key].synonymes_fr.push(syn);
}
// Créer une entrée pour le synonyme qui pointe vers le mot principal
const synKey = syn.toLowerCase();
const synKey = normalizeText(syn);
if (!result.dictionnaire[synKey]) {
result.dictionnaire[synKey] = {
mot_francais: syn,
@ -119,7 +133,7 @@ function mergeSimpleLexique(baseDir, existingLexique) {
for (const [section, entries] of Object.entries(content.dictionnaire)) {
if (typeof entries === 'object') {
for (const [motFr, traduction] of Object.entries(entries)) {
const key = motFr.toLowerCase();
const key = normalizeText(motFr);
// N'ajouter que si pas déjà présent
if (!existingLexique.dictionnaire[key]) {
@ -210,7 +224,7 @@ function buildReverseIndex(lexique) {
*/
function searchLexique(lexique, query, direction = 'fr2conf') {
const results = [];
const queryLower = query.toLowerCase();
const queryLower = normalizeText(query);
if (direction === 'fr2conf') {
// Recherche exacte

View File

@ -2,45 +2,128 @@
// Système de décomposition morphologique pour le Confluent
// Permet de décomposer les mots composés selon le pattern Racine-Liaison-Racine
// Les 16 liaisons sacrées du Confluent
const SACRED_LIAISONS = {
// Agentivité
'i': 'agent',
'ie': 'agent_processus',
'ii': 'agent_répété',
'iu': 'agent_possédant',
const lexique = require('../data/lexique.json');
// Appartenance
'u': 'appartenance',
'ui': 'possession_agentive',
// ============================================================================
// CHARGEMENT DYNAMIQUE DES LIAISONS DEPUIS LE LEXIQUE
// ============================================================================
// Relation
'a': 'relation',
'aa': 'relation_forte',
'ae': 'relation_dimensionnelle',
'ao': 'relation_tendue',
/**
* Charge les liaisons sacrées depuis le lexique JSON
* @returns {Object} Dictionnaire des liaisons {liaison: {domaine, concept, description}}
*/
function loadSacredLiaisons() {
const liaisons = {};
// Tension
'o': 'tension',
'oa': 'tension_relationnelle',
if (lexique.liaisons) {
for (const [liaison, data] of Object.entries(lexique.liaisons)) {
liaisons[liaison] = {
domaine: data.domaine,
concept: data.concept,
description: data.description,
base: data.base
};
}
}
// Dimension
'e': 'dimension',
'ei': 'dimension_agentive',
'ea': 'dimension_relationnelle',
'eo': 'dimension_tendue'
};
return liaisons;
}
// Charger les liaisons depuis le lexique
const SACRED_LIAISONS = loadSacredLiaisons();
console.log(`[morphologicalDecomposer] Chargé ${Object.keys(SACRED_LIAISONS).length} liaisons sacrées depuis lexique.json`);
// ============================================================================
// VALIDATION DES RACINES
// ============================================================================
/**
* Vérifie si une partie ressemble à une racine valide du Confluent
* @param {string} part - Partie à valider
* @param {Object} reverseIndex - Index de recherche (optionnel)
* @returns {{isValid: boolean, found: boolean, confidence: number}}
*/
function validateRoot(part, reverseIndex = null) {
// Critères de base
if (part.length < 2) {
return { isValid: false, found: false, confidence: 0 };
}
let confidence = 0.5; // base
let found = false;
// 1. Vérifier si la partie existe dans l'index de recherche
if (reverseIndex) {
// Recherche exacte
if (reverseIndex.byWord && reverseIndex.byWord[part]) {
found = true;
confidence = 1.0;
return { isValid: true, found: true, confidence };
}
// Recherche par forme liée (enlever dernière voyelle)
if (reverseIndex.byFormeLiee) {
const formeLiee = part.endsWith('a') || part.endsWith('e') ||
part.endsWith('i') || part.endsWith('o') ||
part.endsWith('u')
? part.slice(0, -1)
: part;
if (reverseIndex.byFormeLiee[formeLiee]) {
found = true;
confidence = 0.95;
return { isValid: true, found: true, confidence };
}
}
}
// 2. Heuristiques morphologiques du Confluent
// Les racines finissent généralement par CV (consonne + voyelle)
const vowels = 'aeiou';
const lastChar = part[part.length - 1];
const secondLastChar = part.length > 1 ? part[part.length - 2] : '';
// Finit par voyelle = probable racine
if (vowels.includes(lastChar)) {
confidence += 0.2;
// Pattern CV en fin = très probable
if (secondLastChar && !vowels.includes(secondLastChar)) {
confidence += 0.2;
}
}
// 3. Longueur typique (3-4 caractères pour racines)
if (part.length >= 3 && part.length <= 5) {
confidence += 0.1;
}
return {
isValid: confidence >= 0.5,
found: false,
confidence: Math.min(confidence, 1.0)
};
}
// ============================================================================
// DÉCOMPOSITION MORPHOLOGIQUE
// ============================================================================
/**
* Décompose un mot composé non trouvé
* @param {string} word - Mot composé en confluent
* @returns {Array<{part1: string, liaison: string, liaisonMeaning: string, part2: string, pattern: string, confidence: number}>}
* @param {Object} reverseIndex - Index de recherche (optionnel, pour validation)
* @returns {Array<{part1: string, liaison: string, liaisonMeaning: string, part2: string, pattern: string, confidence: number, part1Valid: boolean, part2Valid: boolean}>}
*/
function decomposeWord(word) {
function decomposeWord(word, reverseIndex = null) {
const decompositions = [];
// Trier les liaisons par longueur décroissante (essayer 'aa' avant 'a')
const liaisonsSorted = Object.keys(SACRED_LIAISONS).sort((a, b) => b.length - a.length);
// Essayer chaque liaison sacrée
for (const [liaison, meaning] of Object.entries(SACRED_LIAISONS)) {
for (const liaison of liaisonsSorted) {
const index = word.indexOf(liaison);
// La liaison doit être au milieu du mot, pas au début ni à la fin
@ -48,15 +131,33 @@ function decomposeWord(word) {
const part1 = word.substring(0, index);
const part2 = word.substring(index + liaison.length);
// Valider que les deux parties ressemblent à des racines (au moins 2 caractères)
if (part1.length >= 2 && part2.length >= 2) {
// Valider les deux parties
const part1Validation = validateRoot(part1, reverseIndex);
const part2Validation = validateRoot(part2, reverseIndex);
// Les deux parties doivent ressembler à des racines
if (part1Validation.isValid && part2Validation.isValid) {
const liaisonData = SACRED_LIAISONS[liaison];
decompositions.push({
part1,
part1Found: part1Validation.found,
part1Confidence: part1Validation.confidence,
liaison,
liaisonMeaning: meaning,
liaisonDomaine: liaisonData.domaine,
liaisonConcept: liaisonData.concept,
liaisonDescription: liaisonData.description,
part2,
part2Found: part2Validation.found,
part2Confidence: part2Validation.confidence,
pattern: `${part1}-${liaison}-${part2}`,
confidence: calculateConfidence(part1, liaison, part2)
confidence: calculateConfidence(
part1,
liaison,
part2,
part1Validation,
part2Validation
)
});
}
}
@ -71,26 +172,39 @@ function decomposeWord(word) {
* @param {string} part1 - Première partie (racine)
* @param {string} liaison - Liaison sacrée
* @param {string} part2 - Deuxième partie (racine)
* @param {Object} part1Validation - Résultat de validation de part1
* @param {Object} part2Validation - Résultat de validation de part2
* @returns {number} Score de confiance entre 0 et 1
*/
function calculateConfidence(part1, liaison, part2) {
let score = 0.5; // base
function calculateConfidence(part1, liaison, part2, part1Validation, part2Validation) {
let score = 0.3; // base plus conservative
// Bonus si les parties finissent/commencent par des consonnes (plus typique du Confluent)
if (!'aeiou'.includes(part1[part1.length - 1])) score += 0.1;
if (!'aeiou'.includes(part2[0])) score += 0.1;
// BONUS MAJEUR : Si les deux parties sont trouvées dans le lexique
if (part1Validation.found && part2Validation.found) {
score = 0.95; // Très haute confiance !
} else if (part1Validation.found || part2Validation.found) {
score = 0.75; // Une partie trouvée = bonne confiance
} else {
// Utiliser la confiance des validations heuristiques
score = (part1Validation.confidence + part2Validation.confidence) / 2;
}
// Bonus si liaison courante (i, u, a sont plus fréquentes)
if (['i', 'u', 'a'].includes(liaison)) score += 0.2;
if (['i', 'u', 'a'].includes(liaison)) {
score += 0.05;
} else if (['aa', 'ii'].includes(liaison)) {
score += 0.03;
}
// Bonus si longueurs de parties équilibrées
const ratio = Math.min(part1.length, part2.length) / Math.max(part1.length, part2.length);
score += ratio * 0.2;
score += ratio * 0.05;
return Math.min(score, 1.0);
}
module.exports = {
decomposeWord,
SACRED_LIAISONS
SACRED_LIAISONS,
validateRoot
};

View File

@ -2,18 +2,104 @@
// Système de recherche par radicaux pour le traducteur Confluent→Français
// Permet de trouver les formes conjuguées et dérivées à partir des racines
// Suffixes verbaux identifiés dans le corpus
const VERBAL_SUFFIXES = [
'ak', // forme standard : mirak (voir), pasak (prendre), urak (être)
'an', // conjugaison : takan (porter), vokan (parler?)
'un', // conjugaison : kisun (transmettre), pasun (prendre?)
'is', // conjugaison : vokis (parler?)
'am', // conjugaison : sukam (forger)
'im', // conjugaison : verim (vérifier?)
'ok', // impératif : marqueur temporel
'ul', // passé? : marqueur temporel
'iran', // dérivé nominal : kisiran (enseignement/transmission?)
];
const lexique = require('../data/lexique.json');
// ============================================================================
// CHARGEMENT DYNAMIQUE DES SUFFIXES DEPUIS LE LEXIQUE
// ============================================================================
/**
* Extrait tous les conjugateurs depuis le lexique JSON
* @returns {Array<string>} Liste des conjugateurs (u, at, ok, ul, etc.)
*/
function getConjugateurs() {
const conjugateurs = [];
if (lexique.conjugateurs) {
// Temps : u, at, aan, ait, amat, en
if (lexique.conjugateurs.temps) {
conjugateurs.push(...Object.keys(lexique.conjugateurs.temps));
}
// Aspects : il, eol, eon, eom
if (lexique.conjugateurs.aspects) {
conjugateurs.push(...Object.keys(lexique.conjugateurs.aspects));
}
// Modes : ok, es, ul
if (lexique.conjugateurs.modes) {
conjugateurs.push(...Object.keys(lexique.conjugateurs.modes));
}
// Évidentiel : uv
if (lexique.conjugateurs.evidentiel) {
conjugateurs.push(...Object.keys(lexique.conjugateurs.evidentiel));
}
}
return conjugateurs;
}
/**
* Extrait les suffixes d'infinitif depuis la liste des verbes
* Analyse les patterns : racine "mira" verbe "mirak" = suffixe "k"
* @returns {Array<string>} Liste des suffixes d'infinitif (k, s, n, m, etc.)
*/
function getInfinitifSuffixes() {
const suffixes = new Set();
if (lexique.verbes) {
for (const verbe of lexique.verbes) {
if (verbe.infinitif && verbe.racine) {
// Extraire le suffixe : infinitif - racine
// Ex: "mirak" - "mira" = "k"
if (verbe.infinitif.startsWith(verbe.racine)) {
const suffix = verbe.infinitif.slice(verbe.racine.length);
if (suffix.length > 0) {
suffixes.add(suffix);
}
}
}
}
}
// Aussi chercher dans les racines avec propriété "verbe"
if (lexique.racines && lexique.racines.standards) {
for (const categorie of Object.values(lexique.racines.standards)) {
if (Array.isArray(categorie)) {
for (const racine of categorie) {
if (racine.verbe && racine.forme_base) {
// Ex: forme_base "mira" → verbe "mirak" = suffixe "k"
if (racine.verbe.startsWith(racine.forme_base)) {
const suffix = racine.verbe.slice(racine.forme_base.length);
if (suffix.length > 0) {
suffixes.add(suffix);
}
}
}
}
}
}
}
return Array.from(suffixes);
}
// Charger les suffixes depuis le lexique
const CONJUGATEURS = getConjugateurs();
const INFINITIF_SUFFIXES = getInfinitifSuffixes();
// Tous les suffixes verbaux = conjugateurs + suffixes d'infinitif
const VERBAL_SUFFIXES = [...CONJUGATEURS, ...INFINITIF_SUFFIXES];
console.log('[radicalMatcher] Chargé depuis lexique.json:');
console.log(` - ${CONJUGATEURS.length} conjugateurs:`, CONJUGATEURS.join(', '));
console.log(` - ${INFINITIF_SUFFIXES.length} suffixes d'infinitif:`, INFINITIF_SUFFIXES.join(', '));
console.log(` - ${VERBAL_SUFFIXES.length} suffixes verbaux totaux`);
// ============================================================================
// EXTRACTION DES RADICAUX
// ============================================================================
/**
* Extrait tous les radicaux possibles d'un mot
@ -23,20 +109,25 @@ const VERBAL_SUFFIXES = [
function extractRadicals(word) {
const candidates = [];
// Essayer chaque suffixe verbal connu
// 1. Essayer chaque suffixe verbal connu (conjugateurs + infinitifs)
for (const suffix of VERBAL_SUFFIXES) {
if (word.endsWith(suffix) && word.length > suffix.length + 1) {
const radical = word.slice(0, -suffix.length);
// Différencier conjugateurs et infinitifs pour la confiance
const isConjugateur = CONJUGATEURS.includes(suffix);
const type = isConjugateur ? 'conjugaison' : 'infinitif';
candidates.push({
radical,
suffix,
type: 'verbal',
confidence: 0.9
type,
confidence: isConjugateur ? 0.95 : 0.9
});
}
}
// Essayer sans suffixe (forme racine directe)
// 2. Essayer sans suffixe (forme racine directe)
if (word.length >= 3) {
candidates.push({
radical: word,
@ -46,8 +137,8 @@ function extractRadicals(word) {
});
}
// Essayer d'enlever dernière voyelle (forme liée -> forme pleine)
// mako → mak, voki → vok
// 3. Essayer d'enlever dernière voyelle (forme liée -> forme pleine)
// Ex: mako → mak, voki → vok
if (word.length >= 4 && 'aeiou'.includes(word[word.length - 1])) {
candidates.push({
radical: word.slice(0, -1),
@ -63,5 +154,7 @@ function extractRadicals(word) {
module.exports = {
extractRadicals,
VERBAL_SUFFIXES
VERBAL_SUFFIXES,
CONJUGATEURS,
INFINITIF_SUFFIXES
};

View File

@ -438,6 +438,101 @@
"synonymes_fr": [
"elles"
]
},
"nous": {
"traductions": [
{
"confluent": "tanu",
"type": "pronom",
"categorie": "personnel",
"note": "Pronom 1ère personne pluriel"
}
]
},
"sa": {
"traductions": [
{
"confluent": "na",
"type": "particule",
"categorie": "possession",
"note": "Possessif (réutilise particule génitif na)"
}
],
"synonymes_fr": [
"son",
"ses",
"mon",
"ma",
"mes",
"ton",
"ta",
"tes",
"notre",
"nos",
"votre",
"vos",
"leur",
"leurs"
]
},
"ce": {
"traductions": [
{
"confluent": "ko",
"type": "determinant",
"categorie": "demonstratif",
"note": "Démonstratif (radical ko-)"
}
],
"synonymes_fr": [
"cet",
"cette",
"ces"
]
},
"avant": {
"traductions": [
{
"confluent": "at",
"type": "particule",
"categorie": "temps",
"note": "Avant/passé (réutilise marqueur passé at)"
}
],
"synonymes_fr": [
"hier",
"auparavant"
]
},
"apres": {
"traductions": [
{
"confluent": "ok",
"type": "particule",
"categorie": "temps",
"note": "Après/futur (réutilise marqueur futur ok)"
}
],
"synonymes_fr": [
"après",
"demain",
"ensuite"
]
},
"autour": {
"traductions": [
{
"confluent": "no",
"type": "particule",
"categorie": "lieu",
"note": "Autour/spatial (réutilise particule locative no)"
}
],
"synonymes_fr": [
"près",
"proche",
"alentour"
]
}
}
}

View File

@ -809,6 +809,20 @@
"domaine": "action",
"note": "Consommer de la nourriture"
}
],
"synonymes_fr": [
"mange",
"manges",
"mangeons",
"mangez",
"mangent",
"mangeais",
"mangeait",
"mangions",
"mangiez",
"mangeaient",
"mangeant",
"mangé"
]
},
"devorer": {
@ -935,6 +949,109 @@
"rejoignant",
"rejoint"
]
},
"battre": {
"racine_fr": "bat",
"traductions": [
{
"confluent": "pulum",
"type": "verbe",
"racine": "pulu",
"forme_liee": "pul",
"structure": "CVCVC",
"domaine": "action",
"note": "Battre (cœur), pulser, rythme vital"
}
],
"synonymes_fr": [
"bat",
"bats",
"battons",
"battez",
"battent",
"battais",
"battait",
"battions",
"battiez",
"battaient",
"battant",
"battu"
]
},
"penser": {
"racine_fr": "pens",
"traductions": [
{
"confluent": "umis",
"type": "verbe",
"racine": "umi",
"forme_liee": "um",
"structure": "VCVC",
"domaine": "action_cognitive",
"note": "Penser, réfléchir - activité mentale (même racine que méditer)"
}
],
"synonymes_fr": [
"réfléchir",
"pense",
"penses",
"pensons",
"pensez",
"pensent",
"pensais",
"pensait",
"pensions",
"pensiez",
"pensaient",
"pensant",
"pensé",
"réfléchis",
"réfléchit",
"réfléchissons",
"réfléchissez",
"réfléchissent",
"réfléchissais",
"réfléchissait",
"réfléchissions",
"réfléchissiez",
"réfléchissaient",
"réfléchissant",
"réfléchi"
]
},
"voler": {
"racine_fr": "vol",
"traductions": [
{
"confluent": "aliuk",
"type": "verbe",
"racine": "aliu",
"forme_liee": "ali",
"structure": "CVCVC",
"domaine": "action",
"note": "Voler, s'envoler, planer dans les airs"
}
],
"synonymes_fr": [
"vole",
"voles",
"volons",
"volez",
"volent",
"volais",
"volait",
"volions",
"voliez",
"volaient",
"volant",
"volé",
"s'envoler",
"envole",
"envoles",
"envolons",
"envolez",
"envolent"
]
}
}
}

View File

@ -0,0 +1,374 @@
{
"_comment": "Vocabulaire alimentaire et culinaire de la Confluence",
"_source": "Basé sur civjdr/Background/2024-10-28-le-village.md",
"dictionnaire": {
"poisson": {
"racine_fr": "poiss",
"traductions": [
{
"confluent": "pisu",
"type": "racine",
"forme_liee": "pis",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Poisson - source vitale de protéines (même racine que pêcher)"
}
],
"synonymes_fr": [
"poissons"
]
},
"gibier": {
"racine_fr": "gibier",
"traductions": [
{
"confluent": "zana",
"type": "racine",
"forme_liee": "zan",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Gibier chassé (lié à zanak-chasser)"
}
],
"synonymes_fr": [
"proie"
]
},
"baie": {
"racine_fr": "bai",
"traductions": [
{
"confluent": "beka",
"type": "racine",
"forme_liee": "bek",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Baies - fruits sauvages essentiels"
}
],
"synonymes_fr": [
"baies",
"petits fruits"
]
},
"tubercule": {
"racine_fr": "tubercul",
"traductions": [
{
"confluent": "tuba",
"type": "racine",
"forme_liee": "tub",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Tubercules, racines comestibles"
}
],
"synonymes_fr": [
"racine",
"tubercules"
]
},
"fruit": {
"racine_fr": "fruit",
"traductions": [
{
"confluent": "veka",
"type": "racine",
"forme_liee": "vek",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Fruits génériques"
}
],
"synonymes_fr": [
"fruits"
]
},
"mollusque": {
"racine_fr": "mollusqu",
"traductions": [
{
"confluent": "molu",
"type": "racine",
"forme_liee": "mol",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Mollusques, coquillages"
}
],
"synonymes_fr": [
"coquillage",
"mollusques"
]
},
"graine": {
"racine_fr": "grain",
"traductions": [
{
"confluent": "seka",
"type": "racine",
"forme_liee": "sek",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Graines comestibles"
}
],
"synonymes_fr": [
"graines",
"semence"
]
},
"galette": {
"racine_fr": "galet",
"traductions": [
{
"confluent": "panu",
"type": "racine",
"forme_liee": "pan",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Galette, pain plat"
}
],
"synonymes_fr": [
"pain",
"crêpe",
"galettes"
]
},
"herbe": {
"racine_fr": "herb",
"traductions": [
{
"confluent": "pala",
"type": "racine",
"forme_liee": "pal",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Herbes aromatiques"
}
],
"synonymes_fr": [
"herbes",
"aromate",
"aromates"
]
},
"morsure-des-ancetres": {
"racine_fr": null,
"traductions": [
{
"confluent": "aiteopalu",
"type": "composition",
"composition": "ait-eo-palu",
"sens_litteral": "Ancêtre-éternel-qui-brûle",
"racines": ["aita", "palu"],
"liaison": "eo",
"structure": "composition_sacree",
"domaine": "nourriture_sacree",
"note": "Gingembre sauvage très estimé, épice sacrée - utilise liaison sacrée eo (totalité/éternel)"
}
],
"synonymes_fr": [
"gingembre sauvage",
"epice sacree"
]
},
"larmes-du-ciel": {
"racine_fr": null,
"traductions": [
{
"confluent": "zeruosi",
"type": "composition",
"composition": "zer-u-osi",
"sens_litteral": "Ciel-de-mort (larmes célestes)",
"racines": ["zeru", "osi"],
"liaison": "u",
"structure": "composition_sacree",
"domaine": "nourriture_sacree",
"note": "Plat cérémoniel traditionnel - poisson fumé, gibier, Morsure-des-Ancêtres, herbes et baies. Utilise liaison u (appartenance)"
}
],
"synonymes_fr": [
"plat ceremoniel",
"plat traditionnel"
]
},
"fumer": {
"racine_fr": "fum",
"traductions": [
{
"confluent": "simus",
"type": "verbe",
"racine": "simu",
"forme_liee": "sim",
"structure": "CVCV",
"domaine": "technique_culinaire",
"note": "Fumer (aliment), technique de conservation"
}
],
"synonymes_fr": [
"fume",
"fumes",
"fumons",
"fumez",
"fument",
"fumais",
"fumait",
"fumions",
"fumiez",
"fumaient",
"fumant",
"fumé",
"fumée"
]
},
"secher": {
"racine_fr": "séch",
"traductions": [
{
"confluent": "sekus",
"type": "verbe",
"racine": "seku",
"forme_liee": "sek",
"structure": "CVCV",
"domaine": "technique_culinaire",
"note": "Sécher (aliment), conservation"
}
],
"synonymes_fr": [
"sécher",
"sèche",
"sèches",
"séchons",
"séchez",
"sèchent",
"séchais",
"séchait",
"séchions",
"séchiez",
"séchaient",
"séchant",
"séché",
"sec",
"sèche"
]
},
"griller": {
"racine_fr": "grill",
"traductions": [
{
"confluent": "palus",
"type": "verbe",
"racine": "palu",
"forme_liee": "pal",
"structure": "CVCV",
"domaine": "technique_culinaire",
"note": "Griller, cuire sur feu"
}
],
"synonymes_fr": [
"grille",
"grilles",
"grillons",
"grillez",
"grillent",
"grillais",
"grillait",
"grillions",
"grilliez",
"grillaient",
"grillant",
"grillé",
"cuire",
"rôtir"
]
},
"cuisiner": {
"racine_fr": "cuisin",
"traductions": [
{
"confluent": "nekas",
"type": "verbe",
"racine": "neka",
"forme_liee": "nek",
"structure": "CVCV",
"domaine": "technique_culinaire",
"note": "Cuisiner, préparer (même racine que faire)"
}
],
"synonymes_fr": [
"cuisine",
"cuisines",
"cuisinons",
"cuisinez",
"cuisinent",
"cuisinais",
"cuisinait",
"cuisinions",
"cuisiniez",
"cuisinaient",
"cuisinant",
"cuisiné",
"preparer",
"préparer"
]
},
"infuser": {
"racine_fr": "infus",
"traductions": [
{
"confluent": "urapis",
"type": "composition",
"composition": "ura-pis",
"sens_litteral": "Eau-tremper",
"racines": ["ura", "pisu"],
"structure": "composition",
"domaine": "technique_culinaire",
"note": "Infuser, faire tremper dans l'eau"
}
],
"synonymes_fr": [
"infuse",
"infusion",
"tremper"
]
},
"reserve": {
"racine_fr": "réserv",
"traductions": [
{
"confluent": "zaku",
"type": "racine",
"forme_liee": "zak",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Réserves alimentaires (lié à garder/protéger)"
}
],
"synonymes_fr": [
"réserves",
"provisions",
"stock"
]
},
"nourriture": {
"racine_fr": "nourritur",
"traductions": [
{
"confluent": "muki",
"type": "racine",
"forme_liee": "muk",
"structure": "CVCV",
"domaine": "nourriture",
"note": "Nourriture (racine de manger)"
}
],
"synonymes_fr": [
"aliment",
"aliments",
"repas"
]
}
}
}