Merge commit 'd703d79feb' into lang/foundations

This commit is contained in:
Orkun ÇAKILKAYA 2026-09-30 00:56:43 +03:00
commit 64adb052b4
6 changed files with 74 additions and 3 deletions

View file

@ -15,4 +15,5 @@ import "keys.ludic"
import "keyed.ludic"
import "keyed_render.ludic"
import "keyed_args.ludic"
import "mixed.ludic"
import "plural.ludic"

View file

@ -57,7 +57,7 @@ function kr_fill(i18n_st: mut I18nState, t: string, args: []string) -> string {
if h >= 1 {
var v = ""
if h < len(args) { v = args[h] }
if i18n_is_key(v) { v = keyed(i18n_st, v) } else if i18n_st.on and kr_words(v) { v = L(i18n_st, v) }
if i18n_is_key(v) or kx_mixed(v) { v = L(i18n_st, v) } else if i18n_st.on and kr_words(v) { v = L(i18n_st, v) }
r = r + t[seg..i] + v
i = hole_end(t, i)
seg = i

View file

@ -16,7 +16,6 @@ export function i18n_key(name: string) -> string { return kx_join(I18N_KEY, name
export function i18n_key_plural(name: string) -> string { return kx_join(I18N_PLURAL, name, "", "", "", "", 0) }
# the key's name without its marker ("pause.resume"), or the string as it is
@alloc_ok("a key's name: a slice of text already made, kept by whoever holds the key")
export function key_text(k: string) -> string {
if not i18n_is_key(k) { return k }
var e = 1
@ -25,7 +24,6 @@ export function key_text(k: string) -> string {
}
# the text of a key: drawn translated where it is drawn (its marked text, a free cast)
@alloc_ok("a cast: the key's own marked text, nothing is made")
export function tr(k: Key) -> string { return string(k) }
# a key's text with its holes, {1} .. {4}, filled by strings already made (a number, a name, another key)
@alloc_ok("a line with its holes, made when something happens and kept by what shows it")

View file

@ -0,0 +1,59 @@
# mixed.ludic - a key's text glued into an English line ("A {1}, {2} cm." given a name that is a key, or a
# name + "\n" + its blurb): each marked name made in the language in use, then the line as English. Interim,
# until every such line is a key of its own (26.9); a mark with arguments cannot be told from the line after it
# a key's name: a-z, 0-9, _ and . (every key the compiler derives or a game writes), a full stop at its
# end left to the sentence
function kx_name_byte(c: int) -> bool { return (c >= 97 and c <= 122) or (c >= 48 and c <= 57) or c == 95 or c == 46 }
function kx_name_end(s: string, i: int) -> int {
var e = i
while e < len(s) and kx_name_byte(s[e]) { e += 1 }
while e > i and s[e - 1] == 46 { e -= 1 }
return e
}
# a string with a mark that is not the whole of it: a mark past its start, or words after a key's name
export function kx_mixed(s: string) -> bool {
let n = len(s)
if n == 0 { return false }
if i18n_is_key(s) {
let e = kx_name_end(s, 1)
return e < n and s[e] != I18N_SEP
}
for i in 1 .. n { if s[i] == I18N_KEY or s[i] == I18N_PLURAL { return true } }
return false
}
# what L does with such a line: made once per distinct line in this language, kept with the keys
function kx_line(i18n_st: mut I18nState, s: string) -> string {
if i18n_st.kc == null { kc_clear(i18n_st) }
let ci = Dict.get_or(i18n_st.kc, s, -1)
if ci >= 0 { return i18n_st.kc_out[ci] }
var r = kx_unmix(i18n_st, s)
if i18n_st.on { r = whole(i18n_st, r) }
if Dict.size(i18n_st.kc) >= CACHE_MAX { kc_clear(i18n_st) }
@alloc_ok("a line with a key glued in, made into text: kept, up to CACHE_MAX")
Dict.set(i18n_st.kc, s, len(i18n_st.kc_out))
@alloc_ok("a line with a key glued in: as above")
push(i18n_st.kc_out, r)
return r
}
@alloc_ok("a line with a key glued in (a cache miss): once per distinct line")
function kx_unmix(i18n_st: mut I18nState, s: string) -> string {
var r = ""
var start = 0
var i = 0
while i < len(s) {
if s[i] == I18N_KEY or s[i] == I18N_PLURAL {
let e = kx_name_end(s, i + 1)
r = r + s[start..i] + keyed(i18n_st, s[i..e])
start = e
i = e
} else {
i += 1
}
}
return r + s[start..len(s)]
}

View file

@ -85,4 +85,16 @@ program I18nKeysTest {
expect(L(i18n_st, trf(k"catch.saw", "Day 3", "5:30", "", "")) == "5:30 saatinde 3. gun gordun.") # a pattern
expect(L(i18n_st, trf(k"catch.saw", "Nowhere known", "7", "", "")) == "7 saatinde Nowhere known gordun.") # no line: as it is
}
test "a key's text glued into an English line is made where it sits, until the line is a key of its own" (i18n_st: mut I18nState) {
start (i18n_st)
let elk = tr(k"species.elk.a_name")
expect(L(i18n_st, "Saw " + elk + ", 30 cm.") == "Saw an elk, 30 cm." and L(i18n_st, "Saw " + elk + ".") == "Saw an elk.")
expect(L(i18n_st, elk + ": 30 cm") == "an elk: 30 cm" and L(i18n_st, elk + "\n" + tr(k"pause.quit")) == "an elk\nQuit")
expect(L(i18n_st, "Not owned. " + tr(k"pause.quit")) == "Not owned. Quit" and L(i18n_st, elk + "Quit") == "an elkQuit")
expect(L(i18n_st, trf(k"catch.saw", "Seen: " + elk, "5:30", "", "")) == "You saw Seen: an elk at 5:30.")
i18n_load_text(i18n_st, tt())
expect(L(i18n_st, "Day " + tr(k"pause.resume")) == "Devam. gun") # the name made, then the line's own pattern
expect(L(i18n_st, trf(k"catch.saw", elk, "5:30", "", "")) == "5:30 saatinde bir geyik gordun.") # a key whole is untouched
}
}

View file

@ -1,6 +1,7 @@
# translate.ludic - what the game draws, in the language in use: a key (keyed_render.ludic); else, the old
# English form, exact, else a pattern, else padding taken off, else a paragraph a sentence at a time
export function L(i18n_st: mut I18nState, s: string) -> string {
if kx_mixed(s) { return kx_line(i18n_st, s) }
if i18n_is_key(s) { return keyed(i18n_st, s) }
if not i18n_st.on { return s }
let ci = Dict.get_or(i18n_st.cache, s, -1)