feat(kreyol): ouvrir la relecture et la prononciation aux locuteurs
Amendement de l'ADR 0005 : la relecture ne repose plus sur un relecteur unique. La porte ne s'abaisse pas — l'ouverture porte sur qui peut proposer, jamais sur qui peut valider. La communauté existait déjà - Lingua Libre compte 456 enregistrements en kréyòl gwadloupéyen, versés sur Commons sous licence libre. - Trois de nos treize noms y figuraient déjà — gouyav, kénèt, zikak — en CC BY-SA 4.0 et AVEC EXACTEMENT NOTRE GRAPHIE. Trois entrées sortent du doute par corroboration externe, sans que le projet décide quoi que ce soit. La question n'était pas qui trancherait, mais d'aller regarder. - En regard : 0 lexème Wikidata en gcf, 0 étiquette gcf sur les 13 items. Modèle de données - orthographe.statut : a_relire | en_discussion | relu. Un doute signalé sans question posée est refusé par le validateur — on ne décourage pas le lecteur, on l'appelle. 4 entrées en discussion : ake, medisinye, lorye-jonn, pom-dlo. - noms.variantes_gcf : les usages proposés sont conservés avec leur source et leur île, jamais écrasés. Une graphie identique au nom principal est refusée comme variante : c'est une corroboration, pas un désaccord. - audio : source, licence, url_description, locuteur crédité, valide. check:audio interroge Lingua Libre et trouve seul les prises existantes. Porte : 14/14 (5 cas ajoutés sur la langue et la prononciation). Pis-aller assumé : les 4 questions sont rédigées en français. Les écrire en kréyòl reviendrait à produire du kréyòl non relu au moment même où l'on reconnaît ne pas savoir le faire. Leur traduction est la première contribution demandée. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -74,6 +74,34 @@ function normaliserDanger(d) {
|
||||
return { ...reste, resume: resume ?? note };
|
||||
}
|
||||
|
||||
/**
|
||||
* Les questions posées aux locuteurs, affichées telles quelles dans le jeu.
|
||||
*
|
||||
* Ce sont des QUESTIONS, pas des corrections : le projet n'a pas à trancher l'orthographe
|
||||
* kréyòl (ADR 0005), mais il a le devoir de dire où il doute plutôt que d'afficher une
|
||||
* graphie douteuse avec l'aplomb d'une certitude.
|
||||
*
|
||||
* Une entrée qui figure ici sort en `statut: "en_discussion"`, ce qui déclenche l'affichage
|
||||
* de la question dans l'encyclopédie et dans le jeu.
|
||||
*/
|
||||
const QUESTIONS_KREYOL = {
|
||||
ake: "Nous écrivons « aki », mais l'identifiant du fruit dit « ake ». Laquelle des deux graphies est la bonne en Guadeloupe ? Et comment le prononcez-vous chez vous ?",
|
||||
medisinye: "« medsinyé » ou « medisinyé » ? Nous rencontrons les deux. Laquelle employez-vous ?",
|
||||
'lorye-jonn': "« lorié-jòn » ou « lorye-jonn » ? Nous ne savons pas trancher. Comment l'écrivez-vous ?",
|
||||
'pom-dlo':
|
||||
"Selon les îles, « pòm-dlo », « pòm-malaka » et « pòm-rose » ne désignent pas le même fruit. Lequel appelez-vous « pòm-dlo » ?"
|
||||
};
|
||||
|
||||
/**
|
||||
* Ces questions sont rédigées en français, et c'est un pis-aller assumé : demander en
|
||||
* français à des locuteurs kréyòl de corriger du kréyòl est un contresens. Mais rédiger
|
||||
* la question en kréyòl reviendrait à produire du kréyòl non relu au moment même où l'on
|
||||
* reconnaît ne pas savoir le faire (ADR 0005).
|
||||
*
|
||||
* Leur traduction en kréyòl fait donc partie des contributions demandées — c'est la
|
||||
* première tâche listée dans docs/kreyol-participatif.md.
|
||||
*/
|
||||
|
||||
/** Deux planches Blanco tronquées au même slug : on désambiguïse plutôt que de perdre un média. */
|
||||
function idsUniques(medias) {
|
||||
const vus = new Map();
|
||||
@@ -159,8 +187,13 @@ async function main() {
|
||||
$schema: '../../../../fruits.schema.json',
|
||||
id: e.id,
|
||||
categorie: e.categorie,
|
||||
noms: e.noms,
|
||||
orthographe: { norme: 'gwadloupeyen', statut: 'a_relire', relu_par: null },
|
||||
noms: { ...e.noms, variantes_gcf: [] },
|
||||
orthographe: {
|
||||
norme: 'gwadloupeyen',
|
||||
statut: QUESTIONS_KREYOL[e.id] ? 'en_discussion' : 'a_relire',
|
||||
relu_par: null,
|
||||
question_ouverte: QUESTIONS_KREYOL[e.id] ?? null
|
||||
},
|
||||
taxon: {
|
||||
scientifique: t.gbif.canonicalName ?? e.taxon.scientifique,
|
||||
famille: t.gbif.famille ?? e.taxon.famille,
|
||||
@@ -179,7 +212,15 @@ async function main() {
|
||||
danger: normaliserDanger(e.danger),
|
||||
indices: e.indices ?? {},
|
||||
medias: candidats,
|
||||
audio: { gcf: null, locuteur: null },
|
||||
audio: {
|
||||
gcf: null,
|
||||
locuteur: null,
|
||||
source: null,
|
||||
licence: null,
|
||||
url_description: null,
|
||||
valide: false,
|
||||
note: null
|
||||
},
|
||||
sources_factuelles: [],
|
||||
valide: false
|
||||
};
|
||||
|
||||
+172
-27
@@ -1,16 +1,23 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* check-audio.mjs — liste les enregistrements kréyòl manquants.
|
||||
* check-audio.mjs — état des prononciations kréyòl.
|
||||
*
|
||||
* Le brief §6 le demande explicitement : « prévois le contrat (audio.gcf, format .opus,
|
||||
* repli silencieux si le fichier manque) et un script de vérification listant les
|
||||
* enregistrements manquants. »
|
||||
* Le brief §6 le demande : « prévois le contrat (audio.gcf, format .opus, repli silencieux
|
||||
* si le fichier manque) et un script de vérification listant les enregistrements manquants ».
|
||||
*
|
||||
* Pas de synthèse vocale : ce script n'en fabrique aucune. Il produit une liste de courses
|
||||
* pour la séance d'enregistrement — une après-midi de terrain vaut dix heures de code.
|
||||
* Ce script fait deux choses :
|
||||
* 1. il liste ce qui manque localement ;
|
||||
* 2. il cherche sur **Lingua Libre** si quelqu'un a déjà enregistré le mot.
|
||||
*
|
||||
* Ce script n'échoue jamais : un enregistrement manquant est un travail à faire,
|
||||
* pas un défaut de build. Le jeu doit se replier en silence.
|
||||
* Le second point est le cœur de la démarche : Lingua Libre est l'atelier d'enregistrement
|
||||
* de Wikimedia, et ses prises sont versées sur Commons sous licence libre. Un nom enregistré
|
||||
* là-bas sert à ce jeu, mais aussi au Wiktionnaire, aux lexiques, aux synthèses vocales
|
||||
* futures — bref, à la langue, pas seulement à nous.
|
||||
*
|
||||
* Pas de synthèse vocale : ce script n'en fabrique aucune, et le schéma n'en accepte pas.
|
||||
* Ce script n'échoue jamais : un enregistrement manquant est un travail à faire.
|
||||
*
|
||||
* Sortie : docs/audio-a-enregistrer.md
|
||||
*/
|
||||
|
||||
import { readFile, readdir, writeFile, access } from 'node:fs/promises';
|
||||
@@ -20,6 +27,13 @@ import { dirname, join } from 'node:path';
|
||||
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
||||
const DATA = join(ROOT, 'src', 'lib', 'data', 'fruits');
|
||||
const STATIC = join(ROOT, 'static');
|
||||
const UA = 'ki-fwi-dataset/0.1 (https://o-k-i.net ; projet educatif ORGANISATION KA INTERNATIONALE)';
|
||||
|
||||
/** Élément Wikidata du kréyòl gwadloupéyen — sert de code de langue à Lingua Libre. */
|
||||
const Q_GWADLOUPEYEN = 'Q3006280';
|
||||
const CATEGORIE_LL = 'Lingua Libre pronunciation-gcf';
|
||||
|
||||
const pause = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
async function existe(p) {
|
||||
try {
|
||||
@@ -30,54 +44,185 @@ async function existe(p) {
|
||||
}
|
||||
}
|
||||
|
||||
async function commons(params) {
|
||||
const u = new URL('https://commons.wikimedia.org/w/api.php');
|
||||
for (const [k, v] of Object.entries({ format: 'json', formatversion: '2', ...params })) u.searchParams.set(k, v);
|
||||
const res = await fetch(u, { headers: { 'User-Agent': UA, Accept: 'application/json' } });
|
||||
if (!res.ok) throw new Error(`Commons ${res.status}`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
const sansBalises = (s) =>
|
||||
s
|
||||
? String(s)
|
||||
.replace(/<[^>]+>/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
: null;
|
||||
|
||||
/** Cherche un enregistrement du mot dans la catégorie Lingua Libre du kréyòl gwadloupéyen. */
|
||||
async function chercherLinguaLibre(mot) {
|
||||
const j = await commons({
|
||||
action: 'query',
|
||||
list: 'search',
|
||||
srnamespace: '6',
|
||||
srlimit: '3',
|
||||
srsearch: `incategory:"${CATEGORIE_LL}" ${mot}`
|
||||
});
|
||||
const trouves = j.query?.search ?? [];
|
||||
if (!trouves.length) return null;
|
||||
|
||||
const detail = await commons({
|
||||
action: 'query',
|
||||
prop: 'imageinfo',
|
||||
iiprop: 'url|mime|extmetadata',
|
||||
iiextmetadatafilter: 'LicenseShortName|Artist',
|
||||
titles: trouves[0].title
|
||||
});
|
||||
const p = detail.query?.pages?.[0];
|
||||
const i = p?.imageinfo?.[0];
|
||||
return {
|
||||
titre: p?.title ?? trouves[0].title,
|
||||
licence: sansBalises(i?.extmetadata?.LicenseShortName?.value),
|
||||
auteur: sansBalises(i?.extmetadata?.Artist?.value),
|
||||
url_fichier: i?.url ?? null,
|
||||
url_description: i?.descriptionurl ?? null,
|
||||
autres: trouves.length - 1
|
||||
};
|
||||
}
|
||||
|
||||
/** Combien d'enregistrements existent en tout dans cette langue ? Mesure l'état de la communauté. */
|
||||
async function tailleCategorie() {
|
||||
const j = await commons({ action: 'query', prop: 'categoryinfo', titles: `Category:${CATEGORIE_LL}` });
|
||||
return j.query?.pages?.[0]?.categoryinfo?.files ?? 0;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const horsLigne = process.argv.includes('--hors-ligne');
|
||||
const fichiers = (await readdir(DATA)).filter((f) => f.endsWith('.json')).sort();
|
||||
|
||||
const manquants = [];
|
||||
const absents = [];
|
||||
const presents = [];
|
||||
const dejaEnregistres = [];
|
||||
|
||||
let totalLL = 0;
|
||||
if (!horsLigne) {
|
||||
try {
|
||||
totalLL = await tailleCategorie();
|
||||
} catch {
|
||||
console.warn('⚠ Lingua Libre injoignable — rapport local uniquement.');
|
||||
}
|
||||
}
|
||||
|
||||
for (const f of fichiers) {
|
||||
const e = JSON.parse(await readFile(join(DATA, f), 'utf8'));
|
||||
if (!e.audio.gcf) {
|
||||
|
||||
if (e.audio.gcf) {
|
||||
if (await existe(join(STATIC, e.audio.gcf))) presents.push(e);
|
||||
else absents.push(e);
|
||||
} else {
|
||||
manquants.push(e);
|
||||
continue;
|
||||
}
|
||||
// Le chemin est absolu depuis la racine du site : /audio/<id>.opus → static/audio/<id>.opus
|
||||
if (await existe(join(STATIC, e.audio.gcf))) presents.push(e);
|
||||
else absents.push(e);
|
||||
|
||||
if (!horsLigne && !e.audio.gcf) {
|
||||
try {
|
||||
process.stdout.write(`→ Lingua Libre : ${e.noms.gcf}… `);
|
||||
const trouve = await chercherLinguaLibre(e.noms.gcf);
|
||||
console.log(trouve ? '✔ déjà enregistré' : '—');
|
||||
if (trouve) dejaEnregistres.push({ e, trouve });
|
||||
await pause(400);
|
||||
} catch {
|
||||
console.log('(échec de la requête)');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const l = [
|
||||
'# Enregistrements kréyòl à réaliser',
|
||||
'# Prononciations kréyòl — état et travail à faire',
|
||||
'',
|
||||
'> Généré par `npm run check:audio`. Aucune synthèse vocale : ces noms doivent être',
|
||||
'> prononcés par une voix humaine locale (brief §6).',
|
||||
'> Généré par `npm run check:audio`. **Aucune synthèse vocale** : ces noms doivent être',
|
||||
'> prononcés par une voix humaine locale (brief §6). Le locuteur conserve ses droits',
|
||||
'> voisins et est crédité nominativement.',
|
||||
'',
|
||||
"Format attendu : `.opus` — un fichier par entrée, déposé dans `static/audio/<id>.opus`.",
|
||||
'',
|
||||
`## À enregistrer (${manquants.length})`,
|
||||
'Format embarqué : `.opus`, un fichier par entrée dans `static/audio/<id>.opus`.',
|
||||
''
|
||||
];
|
||||
for (const e of manquants) l.push(`- [ ] **${e.noms.gcf}** — \`static/audio/${e.id}.opus\` _(${e.noms.fr ?? ''})_`);
|
||||
|
||||
if (totalLL) {
|
||||
l.push(
|
||||
'## Il existe déjà une communauté',
|
||||
'',
|
||||
`**${totalLL} enregistrements en kréyòl gwadloupéyen** sont déjà publiés sur`,
|
||||
`[Lingua Libre](https://lingualibre.org), l'atelier d'enregistrement de Wikimedia, et versés`,
|
||||
`sur Commons sous licence libre (langue \`gcf\`, [${Q_GWADLOUPEYEN}](https://www.wikidata.org/wiki/${Q_GWADLOUPEYEN})).`,
|
||||
'',
|
||||
'Enregistrer là-bas plutôt que dans notre coin, c’est faire servir sa voix au',
|
||||
'Wiktionnaire, aux lexiques et à tous les projets à venir — pas seulement à ce jeu.',
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
if (dejaEnregistres.length) {
|
||||
l.push(
|
||||
`## ✔ Déjà enregistrés par la communauté (${dejaEnregistres.length})`,
|
||||
'',
|
||||
'Ces noms n’ont pas besoin d’être réenregistrés : la prise existe, sous licence libre.',
|
||||
'Il reste à vérifier qu’il s’agit bien du fruit, puis à renseigner le bloc `audio`.',
|
||||
'',
|
||||
'**C’est aussi une corroboration de notre graphie** : le nom enregistré porte',
|
||||
'l’orthographe employée par le locuteur.',
|
||||
'',
|
||||
'| entrée | notre graphie | enregistrement | licence | locuteur |',
|
||||
'|---|---|---|---|---|'
|
||||
);
|
||||
for (const { e, trouve } of dejaEnregistres) {
|
||||
const t = trouve.titre.replace('File:', '').replace(/\|/g, '\\|');
|
||||
l.push(
|
||||
`| \`${e.id}\` | ${e.noms.gcf} | [${t.slice(0, 52)}](${trouve.url_description}) | ${trouve.licence ?? '?'} | ${(trouve.auteur ?? '?').slice(0, 40)} |`
|
||||
);
|
||||
}
|
||||
l.push('');
|
||||
}
|
||||
|
||||
const restants = manquants.filter((e) => !dejaEnregistres.some((d) => d.e.id === e.id));
|
||||
l.push(`## 🎙️ À enregistrer (${restants.length})`, '');
|
||||
if (!restants.length) l.push('_Rien à enregistrer._', '');
|
||||
for (const e of restants) {
|
||||
const q = e.orthographe.question_ouverte;
|
||||
l.push(`- [ ] **${e.noms.gcf}** — \`static/audio/${e.id}.opus\` _(${e.noms.fr ?? ''})_`);
|
||||
if (q) l.push(` ⚠ Orthographe en discussion : ${q}`);
|
||||
}
|
||||
l.push('');
|
||||
|
||||
if (absents.length) {
|
||||
l.push(`## Déclarés mais fichier introuvable (${absents.length})`, '');
|
||||
for (const e of absents) l.push(`- ⚠ \`${e.id}\` → \`${e.audio.gcf}\` absent de \`static/\``);
|
||||
l.push(`## ⚠ Déclarés mais fichier introuvable (${absents.length})`, '');
|
||||
for (const e of absents) l.push(`- \`${e.id}\` → \`${e.audio.gcf}\` absent de \`static/\``);
|
||||
l.push('');
|
||||
}
|
||||
if (presents.length) {
|
||||
l.push(`## En place (${presents.length})`, '');
|
||||
for (const e of presents) l.push(`- ✔ \`${e.id}\` — ${e.audio.locuteur ?? 'locuteur non renseigné'}`);
|
||||
for (const e of presents)
|
||||
l.push(`- \`${e.id}\` — ${e.audio.locuteur ?? 'locuteur non renseigné'} (${e.audio.licence ?? 'licence ?'})`);
|
||||
l.push('');
|
||||
}
|
||||
|
||||
l.push(
|
||||
'## Comment enregistrer',
|
||||
'',
|
||||
'Marche à suivre détaillée dans [`kreyol-participatif.md`](kreyol-participatif.md).',
|
||||
'En deux lignes : une pièce calme, un téléphone, le mot dit deux fois, naturellement.',
|
||||
'Une voix locale vaut mieux qu’un studio.',
|
||||
''
|
||||
);
|
||||
|
||||
await writeFile(join(ROOT, 'docs', 'audio-a-enregistrer.md'), l.join('\n'));
|
||||
|
||||
console.log(`À enregistrer : ${manquants.length}`);
|
||||
console.log(`Introuvables : ${absents.length}`);
|
||||
console.log(`En place : ${presents.length}`);
|
||||
console.log(`\nDéjà enregistrés par la communauté : ${dejaEnregistres.length}`);
|
||||
console.log(`À enregistrer : ${restants.length}`);
|
||||
console.log(`Introuvables : ${absents.length}`);
|
||||
console.log(`En place : ${presents.length}`);
|
||||
console.log('\n docs/audio-a-enregistrer.md');
|
||||
if (absents.length) console.log("\n⚠ Des chemins audio sont déclarés sans fichier : le jeu se repliera en silence.");
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
|
||||
@@ -112,7 +112,7 @@ const CAS = [
|
||||
regle: 'brief §8 — « ≥ 2 photos Commons par fruit avec auteur, licence et URL. »',
|
||||
muter: (e) => {
|
||||
e.medias = [mediaValide()];
|
||||
e.orthographe = { norme: 'gwadloupeyen', statut: 'relu', relu_par: 'relecteur' };
|
||||
e.orthographe = { norme: 'gwadloupeyen', statut: 'relu', relu_par: 'relecteur', question_ouverte: null };
|
||||
e.valide = true;
|
||||
}
|
||||
},
|
||||
@@ -131,6 +131,50 @@ const CAS = [
|
||||
e.medias = [mediaValide()];
|
||||
e.medias[0].valide_par = null;
|
||||
}
|
||||
},
|
||||
{
|
||||
nom: 'doute orthographique signalé sans question posée',
|
||||
regle: 'ADR 0005 — on ne signale pas un doute sans dire lequel, sinon on décourage au lieu d’appeler.',
|
||||
muter: (e) => {
|
||||
e.orthographe = { norme: 'gwadloupeyen', statut: 'en_discussion', relu_par: null, question_ouverte: null };
|
||||
}
|
||||
},
|
||||
{
|
||||
nom: 'enregistrement sans locuteur crédité',
|
||||
regle: 'brief §6 et LICENSE-CONTENT §4 — le locuteur conserve ses droits voisins et est crédité nominativement.',
|
||||
muter: (e) => {
|
||||
e.audio = {
|
||||
gcf: '/audio/kowosol.opus',
|
||||
locuteur: null,
|
||||
source: 'contributeur',
|
||||
licence: 'CC-BY-SA-4.0',
|
||||
url_description: null,
|
||||
valide: false,
|
||||
note: null
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
nom: 'enregistrement externe sans page d’origine',
|
||||
regle: 'brief §3 — toute ressource tierce porte sa source vérifiable.',
|
||||
muter: (e) => {
|
||||
e.audio = {
|
||||
gcf: '/audio/kowosol.opus',
|
||||
locuteur: 'Palé Kréyol',
|
||||
source: 'lingualibre',
|
||||
licence: 'CC-BY-SA-4.0',
|
||||
url_description: null,
|
||||
valide: false,
|
||||
note: null
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
nom: 'variante orthographique identique au nom principal',
|
||||
regle: 'ADR 0005 — une graphie confirmée est une corroboration, pas une variante : ne pas gonfler le doute.',
|
||||
muter: (e) => {
|
||||
e.noms.variantes_gcf = [{ graphie: e.noms.gcf, source: 'un locuteur', ile: 'gp', note: null }];
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -140,7 +184,7 @@ const TEMOIN = {
|
||||
attendu: 0,
|
||||
muter: (e) => {
|
||||
e.medias = [mediaValide(), muter(mediaValide(), (m) => (m.id = 'photo-temoin-2'))];
|
||||
e.orthographe = { norme: 'gwadloupeyen', statut: 'relu', relu_par: 'relecteur' };
|
||||
e.orthographe = { norme: 'gwadloupeyen', statut: 'relu', relu_par: 'relecteur', question_ouverte: null };
|
||||
e.valide = true;
|
||||
}
|
||||
};
|
||||
|
||||
+21
-1
@@ -132,8 +132,28 @@ async function main() {
|
||||
warn(f, 'entrée non encore validée pour publication');
|
||||
}
|
||||
|
||||
if (!e.audio.gcf) warn(f, 'aucun enregistrement kréyòl — le jeu devra se replier en silence');
|
||||
// Langue — ADR 0005. On ne tranche pas l'orthographe, mais on ne bâcle pas la question.
|
||||
if (e.orthographe.statut === 'en_discussion' && !e.orthographe.question_ouverte)
|
||||
err(f, "orthographe « en discussion » sans question posée — on ne signale pas un doute sans dire lequel");
|
||||
if (e.orthographe.statut === 'relu' && !e.orthographe.relu_par)
|
||||
err(f, 'orthographe déclarée relue sans nom de relecteur');
|
||||
for (const v of e.noms.variantes_gcf ?? [])
|
||||
if (v.graphie === e.noms.gcf)
|
||||
err(f, `variante « ${v.graphie} » identique au nom principal — c'est une corroboration, pas une variante`);
|
||||
|
||||
// Prononciation — brief §6 : voix humaine, jamais de synthèse.
|
||||
if (e.audio.gcf) {
|
||||
if (!e.audio.locuteur) err(f, 'enregistrement sans locuteur crédité — il conserve ses droits voisins');
|
||||
if (!e.audio.licence) err(f, 'enregistrement sans licence déclarée');
|
||||
if (e.audio.source && e.audio.source !== 'porteur' && !e.audio.url_description)
|
||||
err(f, `enregistrement de source « ${e.audio.source} » sans page d'origine`);
|
||||
if (!e.audio.valide) warn(f, 'enregistrement présent mais non validé — le jeu se repliera en silence');
|
||||
} else {
|
||||
warn(f, 'aucun enregistrement kréyòl — le jeu devra se replier en silence');
|
||||
}
|
||||
|
||||
if (e.orthographe.statut === 'a_relire') warn(f, 'orthographe kréyòl à relire');
|
||||
if (e.orthographe.statut === 'en_discussion') warn(f, 'orthographe kréyòl en discussion — question posée aux locuteurs');
|
||||
|
||||
entrees.push(e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user