summaryrefslogtreecommitdiff
path: root/lib/naming/lang.mli
blob: 3c62d26c371f736e57d03c93e98eee7eb74fca5c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
(** A language table: strings to strings, nothing more.

    Knows nothing about calendars, dates or rites, and never touches the
    filesystem -- callers hand it text. That is what lets every command use it
    without the kernel learning about presentation.

    Every lookup is TOTAL. A key with no entry returns THE KEY ITSELF, never the
    empty string: a partial translation must be usable from its first line, and
    an untranslated day must still print something a reader can act on. This is
    also why the pre-naming output (bare slugs) is exactly what an empty table
    produces -- the degraded case is the old behaviour, not a blank page. *)

type t

(** Parse INI text. Never raises. [Error] on a malformed file or a missing
    [\[meta\] lang].

    Two duplicate policies, both LAST-WINS:
    - A section name repeated in the file (e.g. two [\[celebration\]]
      blocks) has ALL of its blocks merged, not only the first -- a
      595-entry hand-edited language file WILL grow duplicate section
      headers as contributors append entries over time, and dropping a
      later block would silently lose real translations.
    - Where the same key appears more than once -- within one block or
      across two of them -- the value from further down the file wins.

    Both read the same order a reader would: later in the file overrides
    earlier. This is the OPPOSITE direction from
    {!Colitur_kernel.Overlay_ini.get} ([List.assoc_opt], first match) over
    the very same [section.fields] shape -- the two modules resolve a
    duplicate key in opposite directions, so do not assume one's behaviour
    from the other's. *)
val of_string : string -> (t, string) result

val code : t -> string
val fallback_code : t -> string option

(** [with_fallback t base] resolves through [t] first, then [base], then the key. *)
val with_fallback : t -> t -> t

(** The identity table: every lookup returns its key. This is what [--raw] uses,
    so raw output is one table passed around rather than a special case threaded
    through every call site. *)
val raw : t

val celebration : t -> string -> string
val season : t -> string -> string
val rank : t -> string -> string
val colour : t -> string -> string
val term : t -> string -> string

(** A rite id's reader-facing display name (e.g. ["ef"] ->
    ["Missale Romanum, editio typica 1962"]). A miss returns the id itself,
    same TOTAL-lookup contract as every other function here -- the same
    degradation an unnamed slug already gets, not a special case. *)
val rite : t -> string -> string

(** A Bible book's name, from the [\[bible\]] section. The key is
    [<book_id>.full] or [<book_id>.abbr] (e.g. ["luke.abbr"]). A miss returns
    the key itself, the same TOTAL-lookup contract as every other function
    here -- callers turn that into a real fallback via
    {!Colitur_citation.Book.default_spelling}, not this module. *)
val bible : t -> string -> string

(** [weekday t n], 0 = Sunday. Out-of-range [n] returns [string_of_int n]. *)
val weekday : t -> int -> string

(** [month t n], 1 = January. Out-of-range [n] returns [string_of_int n]. *)
val month : t -> int -> string

(** [month_abbr t n], 1 = January, e.g. ["Ian"]/["Jan"]. Same shape as
    {!month}: out-of-range [n] returns [string_of_int n], and a miss falls
    back through the chain to [string_of_int n] as well, never to [month]'s
    own full name -- an abbreviation is its own vocabulary, not a truncation
    of another lookup. *)
val month_abbr : t -> int -> string

(** Every (section-qualified key, value) pair, sorted. Used by [lang --dump] and
    [lang --check]. Keys are qualified as e.g. ["celebration.ef-epiphany"].

    Includes [\[bible\]] (["bible.luke.abbr"]): book names are translatable
    text, so a file missing them is genuinely incomplete and [lang --check]
    should say so. Deliberately EXCLUDES [\[sigla\]]: those are five citation-
    style settings with working defaults ({!Colitur_citation.Render.default_style}),
    not names a translator owes -- listing them here would make [--check]
    demand five settings from every language file. *)
val keys : t -> (string * string) list

(** The [\[sigla\]] section's raw fields, for
    {!Colitur_citation.Render.style_of_fields} to read. Values come back
    TRIMMED (whitespace at both ends) but still QUOTED if the file quoted
    them -- unquoting is [Render]'s job, not this module's, the same reason
    {!Colitur_kernel.Overlay_ini} (which this parses through) never unquotes
    either. An empty (or absent) [\[sigla\]] section returns [[]]; unlike
    every lookup above, there is no per-key TOTAL contract to keep here --
    this is a settings bag, not a translation table, and [Render] already
    supplies its own defaults for whatever is missing. *)
val sigla_fields : t -> (string * string) list