feat(ui): translate="no", and a title of several lines translated whole or line by line
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
7605a0253c
commit
6bd3228990
9 changed files with 76 additions and 1 deletions
|
|
@ -529,6 +529,9 @@ applies to both:
|
||||||
|
|
||||||
`ui_translator(fn)`, `ui_sounds(fn)` and `ui_clock(fn)` hand the runtime the program's
|
`ui_translator(fn)`, `ui_sounds(fn)` and `ui_clock(fn)` hand the runtime the program's
|
||||||
language, sounds and time. `import "ludic.ui/screen.ludic"` is the 2D screen's renderer.
|
language, sounds and time. `import "ludic.ui/screen.ludic"` is the 2D screen's renderer.
|
||||||
|
Every text a template shows is translated, except inside `translate="no"` (and `translate="yes"`
|
||||||
|
inside that translates again). A `title` of several lines is translated whole when the translator
|
||||||
|
knows it whole, else line by line.
|
||||||
- **The look is CSS.**
|
- **The look is CSS.**
|
||||||
- Colours: `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`, `rgb()`, `rgba()` and the basic names,
|
- Colours: `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`, `rgb()`, `rgba()` and the basic names,
|
||||||
usually through `var(--...)` from a theme.
|
usually through `var(--...)` from a theme.
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,8 @@ What a game's screens found missing, now in `ludic.ui`:
|
||||||
`ui_scroll_set(id, px)` moves one once;
|
`ui_scroll_set(id, px)` moves one once;
|
||||||
- `linear-gradient(...)` backgrounds; `aspect-ratio`; `object-fit` for pictures (the renderer's
|
- `linear-gradient(...)` backgrounds; `aspect-ratio`; `object-fit` for pictures (the renderer's
|
||||||
`image_w` / `image_h`) and `ui_object_fit` for natives;
|
`image_w` / `image_h`) and `ui_object_fit` for natives;
|
||||||
|
- `translate="no"` keeps an element's text as written; a title of several lines is translated whole,
|
||||||
|
else line by line;
|
||||||
- a transition lands exactly on its end value (it had stopped a rounding error short of it, at every
|
- a transition lands exactly on its end value (it had stopped a rounding error short of it, at every
|
||||||
frame rate).
|
frame rate).
|
||||||
|
|
||||||
|
|
|
||||||
44
examples/library/ui_translate.ludic
Normal file
44
examples/library/ui_translate.ludic
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# ui_translate.ludic — translation: translate="no" keeps an element's text (and everything inside it)
|
||||||
|
# as written, translate="yes" inside it translates again; a title of several lines is translated whole
|
||||||
|
# when the translator knows it whole, else line by line, and not inside translate="no".
|
||||||
|
import "ludic.ui"
|
||||||
|
program UiTranslate {
|
||||||
|
numbers float
|
||||||
|
var said: []string = new []string
|
||||||
|
var now: float = 0.0
|
||||||
|
const PAGE: string = "<ui><screen name='t'><p>Hello</p><p translate='no'>Hello</p><div translate='no'><p>Hello</p><p translate='yes'>Hello</p></div><p class='a' title='Save\\nQuit'>a</p><p class='b' title='Line one\\nLine two'>b</p><div translate='no'><p class='c' title='Line one\\nLine two'>c</p></div></screen></ui>"
|
||||||
|
function tr(s: string) -> string {
|
||||||
|
if s == "Hello" { return "Merhaba" }
|
||||||
|
if s == "Save\\nQuit" { return "Kaydet ve cik" }
|
||||||
|
if s == "Line one" { return "Satir bir" }
|
||||||
|
if s == "Line two" { return "Satir iki" }
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function rec_text(x: float, y: float, s: string, size: float, c: int, a: float) -> void { push(said, s) }
|
||||||
|
function clock() -> float { return now }
|
||||||
|
function tip(root: UiNode, k: int) -> string {
|
||||||
|
let n = root.children[k]
|
||||||
|
let i = new UiInput
|
||||||
|
i.x = n.x + 1.0
|
||||||
|
i.y = n.y + 1.0
|
||||||
|
ui_input(i)
|
||||||
|
ui_show("t", null, 0.0, 0.0, 400.0, 400.0)
|
||||||
|
now = now + 1.0
|
||||||
|
said = new []string
|
||||||
|
ui_input(i)
|
||||||
|
ui_show("t", null, 0.0, 0.0, 400.0, 400.0)
|
||||||
|
return `{said[len(said) - 2]}/{said[len(said) - 1]}`
|
||||||
|
}
|
||||||
|
entry {
|
||||||
|
let b = new UiBackend
|
||||||
|
b.text = fn rec_text
|
||||||
|
ui_backend(b)
|
||||||
|
ui_translator(fn tr)
|
||||||
|
ui_clock(fn clock)
|
||||||
|
ui_load_text(PAGE, "t.xml")
|
||||||
|
let root: UiNode = ui_nodes("t", null)
|
||||||
|
ui_place(root, 0.0, 0.0, 400.0, 400.0)
|
||||||
|
let texts = `{root.children[0].text} {root.children[1].text} {root.children[2].children[0].text} {root.children[2].children[1].text}`
|
||||||
|
print(`{texts} | {tip(root, 3)} | {tip(root, 4)} | {tip(root, 5)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,7 +26,9 @@ function ui_px(v: float) -> float {
|
||||||
if ui_be != null and ui_be.scale != null { return v * ui_be.scale() }
|
if ui_be != null and ui_be.scale != null { return v * ui_be.scale() }
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
var tr_no: bool = false # inside translate="no" while a frame is built
|
||||||
function ui_tr(s: string) -> string {
|
function ui_tr(s: string) -> string {
|
||||||
|
if tr_no { return s }
|
||||||
if ui_be != null and ui_be.translate != null { return ui_be.translate(s) }
|
if ui_be != null and ui_be.translate != null { return ui_be.translate(s) }
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,14 @@ function bd_elem(k: UiTpl, e: UiEnv, key: string) -> UiNode {
|
||||||
if k.on_keys[i] == "press" { n.act = k.on_acts[i] }
|
if k.on_keys[i] == "press" { n.act = k.on_acts[i] }
|
||||||
}
|
}
|
||||||
lc_note(key, k.on_keys, k.on_acts, e)
|
lc_note(key, k.on_keys, k.on_acts, e)
|
||||||
|
let was_no = tr_no
|
||||||
|
let say = ui_attr_text(n, "translate")
|
||||||
|
if say == "no" { tr_no = true } else if say == "yes" { tr_no = false }
|
||||||
bd_kids(k.kids, e, key, n.children)
|
bd_kids(k.kids, e, key, n.children)
|
||||||
if k.text != null { el_text(n, ui_tr(ui_eval_text(k.text, e))) }
|
if k.text != null { el_text(n, ui_tr(ui_eval_text(k.text, e))) }
|
||||||
el_inline(n)
|
el_inline(n)
|
||||||
if k.tag == "input" or k.tag == "select" or k.tag == "progress" or k.tag == "meter" { ct_build(n) }
|
if k.tag == "input" or k.tag == "select" or k.tag == "progress" or k.tag == "meter" { ct_build(n) }
|
||||||
|
tr_no = was_no
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
function el_kind(n: UiNode, tag: string) -> void {
|
function el_kind(n: UiNode, tag: string) -> void {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import "popover.ludic"
|
||||||
import "popover_anchor.ludic"
|
import "popover_anchor.ludic"
|
||||||
import "popover_within.ludic"
|
import "popover_within.ludic"
|
||||||
import "tooltip.ludic"
|
import "tooltip.ludic"
|
||||||
|
import "tooltip_text.ludic"
|
||||||
import "life.ludic"
|
import "life.ludic"
|
||||||
import "tpl.ludic"
|
import "tpl.ludic"
|
||||||
import "tpl_lines.ludic"
|
import "tpl_lines.ludic"
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ function tt_track(scope: UiNode, x: float, y: float) -> void {
|
||||||
tt_key = n.key
|
tt_key = n.key
|
||||||
tt_since = an_now()
|
tt_since = an_now()
|
||||||
}
|
}
|
||||||
tt_text = ui_tr(ui_attr_text(n, "title"))
|
tt_text = tt_translate(n, ui_attr_text(n, "title"))
|
||||||
tt_x = x
|
tt_x = x
|
||||||
tt_y = y
|
tt_y = y
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
packages/ludic.ui/tooltip_text.ludic
Normal file
18
packages/ludic.ui/tooltip_text.ludic
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# tooltip_text.ludic - a title in the program's language: the whole of it when the translator knows
|
||||||
|
# it, else line by line; and not at all inside translate="no" (the nearest translate= out from it)
|
||||||
|
function tt_translate(n: UiNode, s: string) -> string {
|
||||||
|
var at = n
|
||||||
|
while at != null {
|
||||||
|
let say = ui_attr_text(at, "translate")
|
||||||
|
if say == "no" { return s }
|
||||||
|
if say == "yes" { break }
|
||||||
|
at = at.parent
|
||||||
|
}
|
||||||
|
let whole = ui_tr(s)
|
||||||
|
if whole != s { return whole }
|
||||||
|
let lines = tt_lines(s)
|
||||||
|
if len(lines) < 2 { return whole }
|
||||||
|
var out = ui_tr(lines[0])
|
||||||
|
for i in 1 .. len(lines) { out = out + "\n" + ui_tr(lines[i]) }
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
@ -771,6 +771,7 @@ function cmd_dev_test() -> int {
|
||||||
controller_case("library/ui_nine", "", "cap 0 12 18 30/ 0 8 8 16 | wide 0 12 88 100/ 0 12 28 40 | odd 10 21 21 31/ 4 8 8 13", "ui_nine.ludic (L11: a nine-slice's corners clamped to half the box each way, on whole pixels)")
|
controller_case("library/ui_nine", "", "cap 0 12 18 30/ 0 8 8 16 | wide 0 12 88 100/ 0 12 28 40 | odd 10 21 21 31/ 4 8 8 13", "ui_nine.ludic (L11: a nine-slice's corners clamped to half the box each way, on whole pixels)")
|
||||||
controller_case("library/ui_scroll_hold", "", "120 50 0 top 120 | 80 50 0 top 80 | 80 50 0 top 80 | 80 50 70 top 80 | 80 50 30 top 80", "ui_scroll_hold.ludic (L11: scroll-top holds a box at an offset, on-scroll follows the wheel, ui_scroll_set moves one once)")
|
controller_case("library/ui_scroll_hold", "", "120 50 0 top 120 | 80 50 0 top 80 | 80 50 0 top 80 | 80 50 70 top 80 | 80 50 30 top 80", "ui_scroll_hold.ludic (L11: scroll-top holds a box at an offset, on-scroll follows the wheel, ui_scroll_set moves one once)")
|
||||||
controller_case("library/ui_fill", "", "0,0 2x20 #030303 .. 98,0 2x20 #fcfcfc | 0,20 50x2 #f2000d .. 0,38 50x2 #0d00f2 .. 0,58 50x2 #0000ff of 70 | 0,85 100x50 | -50,160 200x100 clipped 1 | ratio 90 knob 60", "ui_fill.ludic (L11: linear-gradient backgrounds, object-fit contain and cover, aspect-ratio for boxes and natives)")
|
controller_case("library/ui_fill", "", "0,0 2x20 #030303 .. 98,0 2x20 #fcfcfc | 0,20 50x2 #f2000d .. 0,38 50x2 #0d00f2 .. 0,58 50x2 #0000ff of 70 | 0,85 100x50 | -50,160 200x100 clipped 1 | ratio 90 knob 60", "ui_fill.ludic (L11: linear-gradient backgrounds, object-fit contain and cover, aspect-ratio for boxes and natives)")
|
||||||
|
controller_case("library/ui_translate", "", "Merhaba Hello Hello Merhaba | c/Kaydet ve cik | Satir bir/Satir iki | Line one/Line two", "ui_translate.ludic (L11: translate=no and yes, a title of several lines translated whole or line by line)")
|
||||||
controller_case("library/ui_inputs", "", "count 12 12 32 0.5 0 | 20 32 0.5 0 | 19 32 0.5 0 | How many to carry | Space bar listening 1 19 9 0.5 0 | 19 9 0.5 0 | 19 0 0.5 0 | 60% 0.50 s | 19 0 0.6 9 | 7!", "ui_inputs.ludic (L11: number fields, key capture with Esc and Backspace, notes, range formats, an event named set, a string prop given a number)")
|
controller_case("library/ui_inputs", "", "count 12 12 32 0.5 0 | 20 32 0.5 0 | 19 32 0.5 0 | How many to carry | Space bar listening 1 19 9 0.5 0 | 19 9 0.5 0 | 19 0 0.5 0 | 60% 0.50 s | 19 0 0.6 9 | 7!", "ui_inputs.ludic (L11: number fields, key capture with Esc and Backspace, notes, range formats, an event named set, a string prop given a number)")
|
||||||
controller_case("library/ui_boxes", "", "list 120 of 200 | text at 32 152 wide, 3 lines, row 60 | zero 0x0 | half 140x36 pad 4 2 | order abc at 16 | fill 98x8 of 200x12", "ui_boxes.ludic (L11: flex-shrink to the leftover room, text wrapping beside its siblings, zero sizes, calc(), order, the range track as a row)")
|
controller_case("library/ui_boxes", "", "list 120 of 200 | text at 32 152 wide, 3 lines, row 60 | zero 0x0 | half 140x36 pad 4 2 | order abc at 16 | fill 98x8 of 200x12", "ui_boxes.ludic (L11: flex-shrink to the leftover room, text wrapping beside its siblings, zero sizes, calc(), order, the range track as a row)")
|
||||||
controller_case("library/ui_look", "", "root div.in.i.m pad 5 margin 9 color #ff0000 text Hi 2,53 #102030 | text Hi 0,50 #eeeeee | opacity 0.25 | nine 40 #ffffff nine 40 #ff0000 of 2 image photo.png #ffffff | image icon:tent #00ff00 | text first line 29,205 #eeeeee | text second line 29,223 #eeeeee by id at 84,50 | flipped at 246,268 100x32", "ui_look.ludic (L11: nested components styled by specificity, text-shadow, ui_opacity, border-image tints, pictures, tooltip lines, anchored popovers)")
|
controller_case("library/ui_look", "", "root div.in.i.m pad 5 margin 9 color #ff0000 text Hi 2,53 #102030 | text Hi 0,50 #eeeeee | opacity 0.25 | nine 40 #ffffff nine 40 #ff0000 of 2 image photo.png #ffffff | image icon:tent #00ff00 | text first line 29,205 #eeeeee | text second line 29,223 #eeeeee by id at 84,50 | flipped at 246,268 100x32", "ui_look.ludic (L11: nested components styled by specificity, text-shadow, ui_opacity, border-image tints, pictures, tooltip lines, anchored popovers)")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue