Give the interpreter real Celtic Cross meanings and --format/--lang support

- guidance.c now prints last, after the full spread; both it and main.c's
  new Celtic Cross readout pull real Waite card meanings via tarot_data.c
  instead of just naming cards.
- interpreter-cli gains --format text|html|json and --lang en|de, matching
  deck-engine - required linking engine/src/tarot_data.c and i18n.c into
  the interpreter binary (a narrow, documented exception to its earlier
  "no engine .c files" policy) and writing German translations for
  narrative.c's/guidance.c's own text.
This commit is contained in:
ml
2026-07-11 19:39:30 +02:00
parent 41422adf98
commit 1662d550c7
23 changed files with 1894 additions and 296 deletions
+37
View File
@@ -1,7 +1,12 @@
#define _POSIX_C_SOURCE 200809L /* for mkstemp/fdopen */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../../engine/src/i18n.h"
#include "../src/narrative.h"
static const char *slurp(FILE *f) {
@@ -112,6 +117,37 @@ static void test_unknown_house_omits_area_framing(void) {
printf("PASS test_unknown_house_omits_area_framing\n");
}
/* Proves narrative_print() actually routes through i18n_get() rather
* than just printing the hardcoded fallback - loads a translation file
* that overrides one planet's base text and one house's area text, and
* checks the override wins. Run last: i18n_load() replaces the
* process-global catalog for the rest of the test binary's lifetime. */
static void test_translation_catalog_overrides_fallback_text(void) {
char path[] = "/tmp/deck_narrative_test_XXXXXX";
int fd = mkstemp(path);
assert(fd >= 0);
FILE *f = fdopen(fd, "w");
fprintf(f, "narrative.saturn.base=UEBERSETZTER SATURN TEXT\n");
fprintf(f, "narrative.house.3=UEBERSETZTES HAUS DREI\n");
fclose(f);
assert(i18n_load(path));
unlink(path);
Aspect a = { .transiting_planet = PLANET_SATURN, .natal_planet = PLANET_MOON,
.type = ASPECT_CONJUNCTION, .orb = 1.0 };
FILE *out = tmpfile();
narrative_print(out, "", &a, 3);
const char *text = slurp(out);
assert(strstr(text, "UEBERSETZTER SATURN TEXT") != NULL);
assert(strstr(text, "UEBERSETZTES HAUS DREI") != NULL);
assert(strstr(text, "depression") == NULL); /* English fallback must not leak through */
fclose(out);
printf("PASS test_translation_catalog_overrides_fallback_text\n");
}
int main(void) {
test_hard_aspect_shows_base_but_not_harmonious_bonus();
test_soft_aspect_adds_harmonious_bonus();
@@ -120,6 +156,7 @@ int main(void) {
test_discordant_aspect_on_empty_base_planet();
test_known_house_adds_area_framing();
test_unknown_house_omits_area_framing();
test_translation_catalog_overrides_fallback_text();
printf("All narrative tests passed.\n");
return 0;
}