Adding gender to the config
build / build (push) Successful in 19s

This commit is contained in:
ml
2026-07-16 22:49:06 +02:00
parent 1ebbfebe31
commit 7a77c4a07d
26 changed files with 470 additions and 109 deletions
+112 -34
View File
@@ -130,52 +130,97 @@ static const TarotCardInfo k_cards[TAROT_DECK_SIZE] = {
/* Position names and one-line descriptions follow Waite's own account
* of "An Ancient Celtic Method of Divination" (Part III §7), in his
* original drawing order. */
* original drawing order. Waite addresses the querent as "him"
* throughout; that wording is kept verbatim as the GENDER_MALE variant
* below, and GENDER_FEMALE/GENDER_UNSPECIFIED are original paraphrases
* written for this project (not Waite's own text) so the reading can
* address the person it's actually for. Each array is indexed by
* Gender (tarot.h): [GENDER_UNSPECIFIED], [GENDER_MALE], [GENDER_FEMALE]. */
typedef struct {
const char *name;
const char *description;
const char *name[3];
const char *description[3];
} PositionInfo;
static const PositionInfo k_positions[TAROT_SPREAD_SIZE] = {
[POSITION_PRESENT] = {
"The Present",
"This covers him: the general influence affecting the matter."
{ "The Present", "The Present", "The Present" },
{
"This covers them: the general influence affecting the matter.",
"This covers him: the general influence affecting the matter.",
"This covers her: the general influence affecting the matter.",
}
},
[POSITION_CHALLENGE] = {
"The Challenge",
"This crosses him: the nature of the obstacle in the matter."
{ "The Challenge", "The Challenge", "The Challenge" },
{
"This crosses them: the nature of the obstacle in the matter.",
"This crosses him: the nature of the obstacle in the matter.",
"This crosses her: the nature of the obstacle in the matter.",
}
},
[POSITION_CROWN] = {
"The Crown",
"This crowns him: the aim or ideal, the best that can be achieved."
{ "The Crown", "The Crown", "The Crown" },
{
"This crowns them: the aim or ideal, the best that can be achieved.",
"This crowns him: the aim or ideal, the best that can be achieved.",
"This crowns her: the aim or ideal, the best that can be achieved.",
}
},
[POSITION_FOUNDATION] = {
"The Foundation",
"This is beneath him: the basis of the matter, already actual."
{ "The Foundation", "The Foundation", "The Foundation" },
{
"This is beneath them: the basis of the matter, already actual.",
"This is beneath him: the basis of the matter, already actual.",
"This is beneath her: the basis of the matter, already actual.",
}
},
[POSITION_RECENT_PAST] = {
"The Recent Past",
"This is behind him: the influence that is just passing away."
{ "The Recent Past", "The Recent Past", "The Recent Past" },
{
"This is behind them: the influence that is just passing away.",
"This is behind him: the influence that is just passing away.",
"This is behind her: the influence that is just passing away.",
}
},
[POSITION_NEAR_FUTURE] = {
"The Near Future",
"This is before him: the influence now coming into action."
{ "The Near Future", "The Near Future", "The Near Future" },
{
"This is before them: the influence now coming into action.",
"This is before him: the influence now coming into action.",
"This is before her: the influence now coming into action.",
}
},
[POSITION_ATTITUDE] = {
"Himself",
"His position or attitude in the circumstances."
{ "Themself", "Himself", "Herself" },
{
"Their position or attitude in the circumstances.",
"His position or attitude in the circumstances.",
"Her position or attitude in the circumstances.",
}
},
[POSITION_ENVIRONMENT] = {
"His House",
"His environment and the tendencies at work therein."
{ "Their House", "His House", "Her House" },
{
"Their environment and the tendencies at work therein.",
"His environment and the tendencies at work therein.",
"Her environment and the tendencies at work therein.",
}
},
[POSITION_HOPES_AND_FEARS] = {
"Hopes and Fears",
"His hopes or fears in the matter."
{ "Hopes and Fears", "Hopes and Fears", "Hopes and Fears" },
{
"Their hopes or fears in the matter.",
"His hopes or fears in the matter.",
"Her hopes or fears in the matter.",
}
},
[POSITION_OUTCOME] = {
"The Outcome",
"What will come: the final result of the matter."
{ "The Outcome", "The Outcome", "The Outcome" },
{
"What will come: the final result of the matter.",
"What will come: the final result of the matter.",
"What will come: the final result of the matter.",
}
},
};
@@ -229,13 +274,44 @@ static const char *card_field(const char *slug, const char *field, const char *f
return i18n_get(key, fallback);
}
static const char *position_field(const char *slug, const char *field, const char *fallback) {
char key[64];
strcpy(key, "position.");
strcat(key, slug);
strcat(key, ".");
strcat(key, field);
return i18n_get(key, fallback);
/* Suffix appended to the i18n key for the male/female variants - the
* unspecified/neutral variant uses the plain, unsuffixed key so it
* matches the field name callers already know (e.g. "position.
* attitude.name"), same convention as card_field()'s upright/reversed
* field names above. */
static const char *const k_gender_suffix[3] = {
[GENDER_UNSPECIFIED] = "",
[GENDER_MALE] = ".male",
[GENDER_FEMALE] = ".female",
};
static const char *const k_gender_slug[3] = {
[GENDER_UNSPECIFIED] = "unspecified",
[GENDER_MALE] = "male",
[GENDER_FEMALE] = "female",
};
static const char *position_field(const char *slug, const char *field, Gender gender,
const char *fallback) {
char neutral_key[80];
strcpy(neutral_key, "position.");
strcat(neutral_key, slug);
strcat(neutral_key, ".");
strcat(neutral_key, field);
if (gender == GENDER_UNSPECIFIED) return i18n_get(neutral_key, fallback);
/* Not every position's text actually varies by gender (e.g. "The
* Outcome" has no pronoun) - the .lang files only define a ".male"/
* ".female" key where the wording differs. So look up the neutral key
* first and use *that* (translated, if a catalog is loaded) as the
* fallback for the gendered key, rather than jumping straight past a
* loaded translation to the hardcoded English `fallback` whenever the
* gendered key happens to be absent. */
const char *neutral_text = i18n_get(neutral_key, fallback);
char key[88];
strcpy(key, neutral_key);
strcat(key, k_gender_suffix[gender]);
return i18n_get(key, neutral_text);
}
const char *tarot_card_name(TarotCard card) {
@@ -252,13 +328,15 @@ const char *tarot_card_meaning(TarotCard card, bool reversed) {
reversed ? k_cards[card].reversed : k_cards[card].upright);
}
const char *tarot_position_name(CelticCrossPosition position) {
return position_field(k_position_slug[position], "name", k_positions[position].name);
const char *tarot_position_name(CelticCrossPosition position, Gender gender) {
return position_field(k_position_slug[position], "name", gender, k_positions[position].name[gender]);
}
const char *tarot_position_description(CelticCrossPosition position) {
return position_field(k_position_slug[position], "desc", k_positions[position].description);
const char *tarot_position_description(CelticCrossPosition position, Gender gender) {
return position_field(k_position_slug[position], "desc", gender,
k_positions[position].description[gender]);
}
const char *tarot_card_slug(TarotCard card) { return k_card_slug[card]; }
const char *tarot_position_slug(CelticCrossPosition position) { return k_position_slug[position]; }
const char *tarot_gender_slug(Gender gender) { return k_gender_slug[gender]; }