@the-inclusionist/engine 9.0.0 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -78
- package/app/css/style.css +761 -377
- package/app/public/vendor/fonts/playwrite-cu.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-es-deco.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-es.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-gb-j.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-gb-s.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-pe.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-pt.woff2 +0 -0
- package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
- package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
- package/app/public/vendor/fonts.css +36 -84
- package/dist-pkg/boot/create-game.d.ts +499 -219
- package/dist-pkg/boot/create-game.js +3944 -562
- package/dist-pkg/core/a11y-sr.d.ts +25 -3
- package/dist-pkg/core/a11y-sr.js +38 -19
- package/dist-pkg/core/accessible-label.d.ts +17 -0
- package/dist-pkg/core/accessible-label.js +37 -0
- package/dist-pkg/core/accommodation-subjects.d.ts +26 -0
- package/dist-pkg/core/accommodation-subjects.js +32 -0
- package/dist-pkg/core/accommodations.d.ts +125 -0
- package/dist-pkg/core/accommodations.js +195 -0
- package/dist-pkg/core/actions.d.ts +108 -55
- package/dist-pkg/core/actions.js +122 -71
- package/dist-pkg/core/calm-mode.d.ts +31 -0
- package/dist-pkg/core/calm-mode.js +47 -0
- package/dist-pkg/core/camera-cycle.d.ts +15 -0
- package/dist-pkg/core/camera-cycle.js +7 -0
- package/dist-pkg/core/caption-duration.d.ts +15 -0
- package/dist-pkg/core/caption-duration.js +19 -0
- package/dist-pkg/core/cartridge-problems.d.ts +34 -0
- package/dist-pkg/core/cartridge-problems.js +53 -0
- package/dist-pkg/core/constants.d.ts +0 -54
- package/dist-pkg/core/constants.js +9 -76
- package/dist-pkg/core/contract.d.ts +142 -164
- package/dist-pkg/core/contract.js +222 -208
- package/dist-pkg/core/dom-query.d.ts +4 -4
- package/dist-pkg/core/dom-query.js +12 -20
- package/dist-pkg/core/entity.d.ts +62 -77
- package/dist-pkg/core/entity.js +18 -32
- package/dist-pkg/core/escape-html.d.ts +9 -10
- package/dist-pkg/core/escape-html.js +16 -20
- package/dist-pkg/core/flash-threshold.d.ts +17 -0
- package/dist-pkg/core/flash-threshold.js +113 -0
- package/dist-pkg/core/game-speed.d.ts +11 -0
- package/dist-pkg/core/game-speed.js +16 -0
- package/dist-pkg/core/genres.d.ts +20 -0
- package/dist-pkg/core/genres.js +44 -0
- package/dist-pkg/core/i18n.d.ts +71 -60
- package/dist-pkg/core/i18n.js +186 -200
- package/dist-pkg/core/loop.d.ts +17 -6
- package/dist-pkg/core/loop.js +26 -26
- package/dist-pkg/core/pause-icon-catalogue.d.ts +15 -0
- package/dist-pkg/core/pause-icon-catalogue.js +54 -0
- package/dist-pkg/core/ring.d.ts +17 -0
- package/dist-pkg/core/ring.js +29 -0
- package/dist-pkg/core/rng.d.ts +7 -12
- package/dist-pkg/core/rng.js +23 -53
- package/dist-pkg/core/route.d.ts +26 -26
- package/dist-pkg/core/route.js +126 -121
- package/dist-pkg/core/scenes.d.ts +37 -40
- package/dist-pkg/core/scenes.js +41 -43
- package/dist-pkg/core/screens.d.ts +4 -4
- package/dist-pkg/core/screens.js +11 -16
- package/dist-pkg/core/session-clock.d.ts +23 -0
- package/dist-pkg/core/session-clock.js +37 -0
- package/dist-pkg/core/setting-defaults.d.ts +61 -0
- package/dist-pkg/core/setting-defaults.js +66 -0
- package/dist-pkg/core/speech-rate.d.ts +29 -0
- package/dist-pkg/core/speech-rate.js +47 -0
- package/dist-pkg/core/state.d.ts +118 -118
- package/dist-pkg/core/state.js +322 -297
- package/dist-pkg/core/visual-cycles.d.ts +30 -0
- package/dist-pkg/core/visual-cycles.js +52 -0
- package/dist-pkg/core/visual-state.d.ts +13 -0
- package/dist-pkg/core/visual-state.js +6 -0
- package/dist-pkg/educational/activities-registry.d.ts +1 -1
- package/dist-pkg/educational/activities-registry.js +9 -8
- package/dist-pkg/educational/adaptive-engine.d.ts +11 -11
- package/dist-pkg/educational/adaptive-engine.js +17 -17
- package/dist-pkg/educational/segment-bar.d.ts +12 -12
- package/dist-pkg/educational/segment-bar.js +9 -9
- package/dist-pkg/i18n/en.js +324 -223
- package/dist-pkg/i18n/es.js +323 -223
- package/dist-pkg/i18n/pt.js +348 -226
- package/dist-pkg/input/default-bindings.d.ts +37 -38
- package/dist-pkg/input/default-bindings.js +127 -144
- package/dist-pkg/input/devices.d.ts +7 -7
- package/dist-pkg/input/devices.js +17 -16
- package/dist-pkg/input/edges.d.ts +23 -32
- package/dist-pkg/input/edges.js +23 -28
- package/dist-pkg/input/empathy-filter.d.ts +22 -0
- package/dist-pkg/input/empathy-filter.js +34 -0
- package/dist-pkg/input/face-map.d.ts +96 -0
- package/dist-pkg/input/face-map.js +255 -0
- package/dist-pkg/input/face-signals.d.ts +40 -0
- package/dist-pkg/input/face-signals.js +48 -0
- package/dist-pkg/input/gamepad.d.ts +195 -145
- package/dist-pkg/input/gamepad.js +383 -556
- package/dist-pkg/input/gaze-cycle.d.ts +64 -0
- package/dist-pkg/input/gaze-cycle.js +133 -0
- package/dist-pkg/input/gaze-relative.d.ts +68 -0
- package/dist-pkg/input/gaze-relative.js +142 -0
- package/dist-pkg/input/hand-map.d.ts +28 -0
- package/dist-pkg/input/hand-map.js +142 -0
- package/dist-pkg/input/input-cooldown.d.ts +17 -0
- package/dist-pkg/input/input-cooldown.js +39 -0
- package/dist-pkg/input/key-default.d.ts +30 -0
- package/dist-pkg/input/key-default.js +60 -0
- package/dist-pkg/input/keyboard-runtime.d.ts +15 -21
- package/dist-pkg/input/keyboard-runtime.js +23 -27
- package/dist-pkg/input/keyboard.d.ts +68 -63
- package/dist-pkg/input/keyboard.js +83 -105
- package/dist-pkg/input/keydown.d.ts +123 -137
- package/dist-pkg/input/keydown.js +284 -289
- package/dist-pkg/input/latch-edge.d.ts +33 -21
- package/dist-pkg/input/latch-edge.js +34 -35
- package/dist-pkg/input/latch-scope.d.ts +51 -50
- package/dist-pkg/input/latch-scope.js +61 -82
- package/dist-pkg/input/latch-store.d.ts +26 -30
- package/dist-pkg/input/latch-store.js +42 -50
- package/dist-pkg/input/latch-sync.d.ts +29 -29
- package/dist-pkg/input/latch-sync.js +25 -25
- package/dist-pkg/input/latch.d.ts +14 -17
- package/dist-pkg/input/latch.js +29 -37
- package/dist-pkg/input/pad-defaults.d.ts +13 -16
- package/dist-pkg/input/pad-defaults.js +21 -28
- package/dist-pkg/input/pad-reading.d.ts +76 -0
- package/dist-pkg/input/pad-reading.js +169 -0
- package/dist-pkg/input/pad-wizard.d.ts +99 -0
- package/dist-pkg/input/pad-wizard.js +256 -0
- package/dist-pkg/input/pointer-space.d.ts +19 -20
- package/dist-pkg/input/pointer-space.js +27 -32
- package/dist-pkg/input/pointer.d.ts +39 -40
- package/dist-pkg/input/pointer.js +42 -45
- package/dist-pkg/input/state.d.ts +101 -89
- package/dist-pkg/input/state.js +54 -134
- package/dist-pkg/input/switch-scan.d.ts +59 -0
- package/dist-pkg/input/switch-scan.js +67 -0
- package/dist-pkg/input/synthetic-source.d.ts +42 -0
- package/dist-pkg/input/synthetic-source.js +57 -0
- package/dist-pkg/input/touch-bindings.d.ts +127 -116
- package/dist-pkg/input/touch-bindings.js +158 -173
- package/dist-pkg/input/touch.d.ts +147 -72
- package/dist-pkg/input/touch.js +362 -126
- package/dist-pkg/input/transport-in-use.d.ts +107 -0
- package/dist-pkg/input/transport-in-use.js +130 -0
- package/dist-pkg/input/transports.d.ts +90 -117
- package/dist-pkg/input/transports.js +104 -106
- package/dist-pkg/input/virtual-controller.d.ts +82 -0
- package/dist-pkg/input/virtual-controller.js +69 -0
- package/dist-pkg/input/vocabulary-migration.d.ts +50 -49
- package/dist-pkg/input/vocabulary-migration.js +80 -79
- package/dist-pkg/input/voice-map.d.ts +59 -0
- package/dist-pkg/input/voice-map.js +123 -0
- package/dist-pkg/platform/audio-ambient.d.ts +13 -2
- package/dist-pkg/platform/audio-ambient.js +14 -14
- package/dist-pkg/platform/audio-earcons.d.ts +20 -19
- package/dist-pkg/platform/audio-earcons.js +51 -42
- package/dist-pkg/platform/audio-jingles.js +9 -10
- package/dist-pkg/platform/audio-mixer.d.ts +14 -2
- package/dist-pkg/platform/audio-mixer.js +31 -39
- package/dist-pkg/platform/audio-sonar.d.ts +49 -152
- package/dist-pkg/platform/audio-sonar.js +124 -302
- package/dist-pkg/platform/audio.d.ts +62 -19
- package/dist-pkg/platform/audio.js +193 -168
- package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
- package/dist-pkg/platform/choose-by-voice.js +157 -0
- package/dist-pkg/platform/flash-sampler.d.ts +19 -0
- package/dist-pkg/platform/flash-sampler.js +79 -0
- package/dist-pkg/platform/font-library.d.ts +77 -0
- package/dist-pkg/platform/font-library.js +98 -0
- package/dist-pkg/platform/font-library.json +721 -0
- package/dist-pkg/platform/heavy-catalogue.d.ts +77 -0
- package/dist-pkg/platform/heavy-catalogue.js +256 -0
- package/dist-pkg/platform/heavy-mirror.d.ts +20 -0
- package/dist-pkg/platform/heavy-mirror.js +73 -0
- package/dist-pkg/platform/heavy.d.ts +136 -0
- package/dist-pkg/platform/heavy.js +324 -0
- package/dist-pkg/platform/interruptible-speech.d.ts +23 -16
- package/dist-pkg/platform/interruptible-speech.js +77 -54
- package/dist-pkg/platform/kokoro-port.d.ts +27 -0
- package/dist-pkg/platform/kokoro-port.js +50 -0
- package/dist-pkg/platform/kokoro-runtime.d.ts +20 -0
- package/dist-pkg/platform/kokoro-runtime.js +52 -0
- package/dist-pkg/platform/kokoro.d.ts +70 -0
- package/dist-pkg/platform/kokoro.js +133 -0
- package/dist-pkg/platform/listener-scope.d.ts +12 -0
- package/dist-pkg/platform/listener-scope.js +90 -0
- package/dist-pkg/platform/locale-host.d.ts +14 -0
- package/dist-pkg/platform/locale-host.js +45 -0
- package/dist-pkg/platform/microphone.d.ts +51 -0
- package/dist-pkg/platform/microphone.js +118 -0
- package/dist-pkg/platform/onnx-runtime.d.ts +34 -0
- package/dist-pkg/platform/onnx-runtime.js +42 -0
- package/dist-pkg/platform/reading-in-worker.d.ts +64 -0
- package/dist-pkg/platform/reading-in-worker.js +125 -0
- package/dist-pkg/platform/reading-model.d.ts +94 -0
- package/dist-pkg/platform/reading-model.js +272 -0
- package/dist-pkg/platform/reading-runtime.d.ts +24 -0
- package/dist-pkg/platform/reading-runtime.js +164 -0
- package/dist-pkg/platform/reading-worker.d.ts +41 -0
- package/dist-pkg/platform/reading-worker.js +58 -0
- package/dist-pkg/platform/reading.d.ts +80 -0
- package/dist-pkg/platform/reading.js +136 -0
- package/dist-pkg/platform/speech-recognition.d.ts +60 -0
- package/dist-pkg/platform/speech-recognition.js +104 -0
- package/dist-pkg/platform/speech.d.ts +23 -1
- package/dist-pkg/platform/speech.js +29 -18
- package/dist-pkg/platform/storage-keys.d.ts +96 -0
- package/dist-pkg/platform/storage-keys.js +106 -0
- package/dist-pkg/platform/storage.d.ts +46 -111
- package/dist-pkg/platform/storage.js +104 -169
- package/dist-pkg/platform/tts.d.ts +85 -39
- package/dist-pkg/platform/tts.js +447 -127
- package/dist-pkg/platform/vision-loop.d.ts +23 -0
- package/dist-pkg/platform/vision-loop.js +56 -0
- package/dist-pkg/platform/vision.d.ts +132 -0
- package/dist-pkg/platform/vision.js +117 -0
- package/dist-pkg/platform/voice-listener.d.ts +40 -0
- package/dist-pkg/platform/voice-listener.js +88 -0
- package/dist-pkg/platform/voice-plan.d.ts +15 -98
- package/dist-pkg/platform/voice-plan.js +56 -143
- package/dist-pkg/platform/vosk-runtime.d.ts +96 -0
- package/dist-pkg/platform/vosk-runtime.js +151 -0
- package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
- package/dist-pkg/platform/vosk-vocabulary.js +178 -0
- package/dist-pkg/render/canvas.d.ts +13 -7
- package/dist-pkg/render/canvas.js +13 -13
- package/dist-pkg/render/crt.d.ts +48 -12
- package/dist-pkg/render/crt.js +78 -80
- package/dist-pkg/render/cvd-matrices.d.ts +22 -18
- package/dist-pkg/render/cvd-matrices.js +37 -38
- package/dist-pkg/render/hc-role-data.d.ts +7 -7
- package/dist-pkg/render/hc-role-data.js +14 -14
- package/dist-pkg/render/high-contrast.d.ts +67 -56
- package/dist-pkg/render/high-contrast.js +226 -217
- package/dist-pkg/render/low-vision-drawing.d.ts +5 -0
- package/dist-pkg/render/low-vision-drawing.js +46 -0
- package/dist-pkg/render/lq-filter.d.ts +32 -20
- package/dist-pkg/render/lq-filter.js +59 -65
- package/dist-pkg/render/port.d.ts +86 -88
- package/dist-pkg/render/port.js +17 -23
- package/dist-pkg/render/screen-pipeline.d.ts +42 -42
- package/dist-pkg/render/screen-pipeline.js +80 -87
- package/dist-pkg/render/sprite-fx.d.ts +2 -1
- package/dist-pkg/render/sprite-fx.js +16 -14
- package/dist-pkg/render/viewports.d.ts +20 -15
- package/dist-pkg/render/viewports.js +83 -114
- package/dist-pkg/render/viz-axes-labels.d.ts +47 -0
- package/dist-pkg/render/viz-axes-labels.js +88 -0
- package/dist-pkg/render/viz-axes.d.ts +89 -86
- package/dist-pkg/render/viz-axes.js +128 -116
- package/dist-pkg/render/viz-modes.d.ts +28 -29
- package/dist-pkg/render/viz-modes.js +40 -45
- package/dist-pkg/render/viz-refusal.d.ts +32 -0
- package/dist-pkg/render/viz-refusal.js +57 -0
- package/dist-pkg/render/viz-setters.d.ts +104 -66
- package/dist-pkg/render/viz-setters.js +182 -191
- package/dist-pkg/ui/aac-sets.d.ts +45 -0
- package/dist-pkg/ui/aac-sets.js +41 -0
- package/dist-pkg/ui/audio-choices.d.ts +68 -0
- package/dist-pkg/ui/audio-choices.js +98 -0
- package/dist-pkg/ui/audio-rows-that-apply.d.ts +12 -0
- package/dist-pkg/ui/audio-rows-that-apply.js +43 -0
- package/dist-pkg/ui/camera-control.d.ts +53 -0
- package/dist-pkg/ui/camera-control.js +48 -0
- package/dist-pkg/ui/changed-mark.d.ts +9 -8
- package/dist-pkg/ui/changed-mark.js +22 -53
- package/dist-pkg/ui/control-choices.d.ts +37 -0
- package/dist-pkg/ui/control-choices.js +84 -0
- package/dist-pkg/ui/debug-panel.d.ts +59 -43
- package/dist-pkg/ui/debug-panel.js +68 -69
- package/dist-pkg/ui/declared-words.d.ts +21 -0
- package/dist-pkg/ui/declared-words.js +66 -0
- package/dist-pkg/ui/dom.d.ts +10 -14
- package/dist-pkg/ui/dom.js +10 -47
- package/dist-pkg/ui/drawing-problems.d.ts +25 -0
- package/dist-pkg/ui/drawing-problems.js +94 -0
- package/dist-pkg/ui/eye-control.d.ts +36 -0
- package/dist-pkg/ui/eye-control.js +178 -0
- package/dist-pkg/ui/face-control.d.ts +25 -0
- package/dist-pkg/ui/face-control.js +183 -0
- package/dist-pkg/ui/focus-trap.d.ts +39 -49
- package/dist-pkg/ui/focus-trap.js +56 -65
- package/dist-pkg/ui/fonts.d.ts +157 -68
- package/dist-pkg/ui/fonts.js +305 -115
- package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
- package/dist-pkg/ui/footer-scroll-driver.js +201 -0
- package/dist-pkg/ui/footer-scroll.d.ts +38 -0
- package/dist-pkg/ui/footer-scroll.js +55 -0
- package/dist-pkg/ui/game-options.d.ts +47 -0
- package/dist-pkg/ui/game-options.js +158 -0
- package/dist-pkg/ui/gaze-overlay.d.ts +64 -0
- package/dist-pkg/ui/gaze-overlay.js +165 -0
- package/dist-pkg/ui/hand-control.d.ts +25 -0
- package/dist-pkg/ui/hand-control.js +143 -0
- package/dist-pkg/ui/help-panel.d.ts +87 -0
- package/dist-pkg/ui/help-panel.js +242 -0
- package/dist-pkg/ui/hud-bands.d.ts +62 -0
- package/dist-pkg/ui/hud-bands.js +146 -0
- package/dist-pkg/ui/hud-row.d.ts +34 -0
- package/dist-pkg/ui/hud-row.js +80 -0
- package/dist-pkg/ui/hud.d.ts +73 -73
- package/dist-pkg/ui/hud.js +94 -98
- package/dist-pkg/ui/item-announcement.d.ts +13 -12
- package/dist-pkg/ui/item-announcement.js +25 -26
- package/dist-pkg/ui/layout.d.ts +103 -28
- package/dist-pkg/ui/layout.js +117 -99
- package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
- package/dist-pkg/ui/libras-avatar-clip.js +86 -0
- package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
- package/dist-pkg/ui/libras-avatar-load.js +134 -0
- package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
- package/dist-pkg/ui/libras-avatar-plan.js +211 -0
- package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
- package/dist-pkg/ui/libras-avatar-player.js +226 -0
- package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
- package/dist-pkg/ui/libras-avatar-stage.js +208 -0
- package/dist-pkg/ui/libras-glosses.d.ts +28 -0
- package/dist-pkg/ui/libras-glosses.js +161 -0
- package/dist-pkg/ui/locale-flags.d.ts +16 -0
- package/dist-pkg/ui/locale-flags.js +30 -0
- package/dist-pkg/ui/loop-crash.d.ts +17 -17
- package/dist-pkg/ui/loop-crash.js +33 -62
- package/dist-pkg/ui/menu-intent.d.ts +61 -0
- package/dist-pkg/ui/menu-intent.js +88 -0
- package/dist-pkg/ui/menu-items.d.ts +20 -0
- package/dist-pkg/ui/menu-items.js +51 -0
- package/dist-pkg/ui/menu-nav.d.ts +98 -92
- package/dist-pkg/ui/menu-nav.js +398 -286
- package/dist-pkg/ui/mobility-choices.d.ts +26 -0
- package/dist-pkg/ui/mobility-choices.js +41 -0
- package/dist-pkg/ui/motion-choices.d.ts +31 -0
- package/dist-pkg/ui/motion-choices.js +68 -0
- package/dist-pkg/ui/motion-scene.d.ts +24 -19
- package/dist-pkg/ui/motion-scene.js +29 -61
- package/dist-pkg/ui/mount-panel.d.ts +81 -0
- package/dist-pkg/ui/mount-panel.js +61 -0
- package/dist-pkg/ui/panel-shell.d.ts +65 -31
- package/dist-pkg/ui/panel-shell.js +92 -66
- package/dist-pkg/ui/panel-widgets.d.ts +150 -0
- package/dist-pkg/ui/panel-widgets.js +294 -0
- package/dist-pkg/ui/pause-buttons.d.ts +35 -0
- package/dist-pkg/ui/pause-buttons.js +66 -0
- package/dist-pkg/ui/pause-icons.d.ts +261 -347
- package/dist-pkg/ui/pause-icons.js +671 -601
- package/dist-pkg/ui/pause-markup.d.ts +86 -0
- package/dist-pkg/ui/pause-markup.js +125 -0
- package/dist-pkg/ui/reach-notice.d.ts +22 -23
- package/dist-pkg/ui/reach-notice.js +55 -58
- package/dist-pkg/ui/scan-overlay.d.ts +23 -0
- package/dist-pkg/ui/scan-overlay.js +50 -0
- package/dist-pkg/ui/screen-text.d.ts +25 -0
- package/dist-pkg/ui/screen-text.js +152 -0
- package/dist-pkg/ui/session-clock.d.ts +32 -0
- package/dist-pkg/ui/session-clock.js +67 -0
- package/dist-pkg/ui/settings-aac.d.ts +70 -0
- package/dist-pkg/ui/settings-aac.js +208 -0
- package/dist-pkg/ui/settings-audio.d.ts +97 -114
- package/dist-pkg/ui/settings-audio.js +493 -425
- package/dist-pkg/ui/settings-controls.d.ts +53 -96
- package/dist-pkg/ui/settings-controls.js +143 -215
- package/dist-pkg/ui/settings-empathy.d.ts +39 -30
- package/dist-pkg/ui/settings-empathy.js +53 -60
- package/dist-pkg/ui/settings-mobility.d.ts +192 -0
- package/dist-pkg/ui/settings-mobility.js +332 -0
- package/dist-pkg/ui/settings-motion.d.ts +91 -70
- package/dist-pkg/ui/settings-motion.js +287 -198
- package/dist-pkg/ui/settings-panel.d.ts +58 -45
- package/dist-pkg/ui/settings-panel.js +189 -94
- package/dist-pkg/ui/settings-typo.d.ts +29 -78
- package/dist-pkg/ui/settings-typo.js +158 -129
- package/dist-pkg/ui/settings-visual.d.ts +29 -87
- package/dist-pkg/ui/settings-visual.js +240 -193
- package/dist-pkg/ui/shell.d.ts +112 -135
- package/dist-pkg/ui/shell.js +148 -217
- package/dist-pkg/ui/simulation-list.d.ts +27 -0
- package/dist-pkg/ui/simulation-list.js +76 -0
- package/dist-pkg/ui/simulation-over-the-world.d.ts +23 -0
- package/dist-pkg/ui/simulation-over-the-world.js +131 -0
- package/dist-pkg/ui/simulation-refusal.d.ts +5 -31
- package/dist-pkg/ui/simulation-refusal.js +8 -56
- package/dist-pkg/ui/switchable-control.d.ts +11 -0
- package/dist-pkg/ui/switchable-control.js +19 -0
- package/dist-pkg/ui/title.d.ts +3 -12
- package/dist-pkg/ui/title.js +49 -18
- package/dist-pkg/ui/top-band.d.ts +26 -0
- package/dist-pkg/ui/top-band.js +96 -0
- package/dist-pkg/ui/typo-choices.d.ts +71 -0
- package/dist-pkg/ui/typo-choices.js +85 -0
- package/dist-pkg/ui/visual-axes-panel.d.ts +11 -47
- package/dist-pkg/ui/visual-axes-panel.js +12 -94
- package/dist-pkg/ui/visual-choices.d.ts +77 -0
- package/dist-pkg/ui/visual-choices.js +107 -0
- package/dist-pkg/ui/vlibras.d.ts +77 -10
- package/dist-pkg/ui/vlibras.js +130 -81
- package/dist-pkg/ui/voice-control.d.ts +68 -0
- package/dist-pkg/ui/voice-control.js +276 -0
- package/dist-pkg/ui/voice-settings.d.ts +95 -0
- package/dist-pkg/ui/voice-settings.js +352 -0
- package/dist-pkg/ui/where-the-child-is.d.ts +31 -0
- package/dist-pkg/ui/where-the-child-is.js +70 -0
- package/docs/CREDITS.md +300 -44
- package/docs/LICENSES.md +189 -145
- package/package.json +51 -27
- package/scripts/check-cartridge.mjs +78 -0
- package/scripts/game-build.d.mts +25 -0
- package/scripts/game-build.mjs +144 -0
- package/scripts/heavy-into-the-delivery.mjs +388 -0
- package/scripts/libras-avatar.json +680 -0
- package/scripts/libras-avatar.mjs +246 -0
- package/scripts/libras-glosses/gloss.py +95 -0
- package/scripts/libras-glosses/pyproject.toml +32 -0
- package/scripts/libras-glosses/uv.lock +781 -0
- package/scripts/libras-glosses.mjs +351 -0
- package/scripts/licences/Apache-2.0.txt +176 -0
- package/scripts/licences/GPL-3.0.txt +674 -0
- package/scripts/licences/MIT.txt +17 -0
- package/scripts/licences/OFL-1.1.txt +86 -0
- package/scripts/licences/UFL-1.0.txt +96 -0
- package/scripts/licences/fonts.mjs +389 -0
- package/scripts/licences/third-party.mjs +301 -0
- package/scripts/licences/vosk-browser.NOTICE.txt +268 -0
- package/app/public/vendor/fonts/comicneue-400.woff2 +0 -0
- package/app/public/vendor/fonts/comicneue-700.woff2 +0 -0
- package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
- package/app/public/vendor/fonts/inter-400.woff2 +0 -0
- package/app/public/vendor/fonts/inter-700.woff2 +0 -0
- package/app/public/vendor/fonts/lato-400.woff2 +0 -0
- package/app/public/vendor/fonts/lato-700.woff2 +0 -0
- package/app/public/vendor/fonts/literata-400.woff2 +0 -0
- package/app/public/vendor/fonts/literata-700.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
- package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
- package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
- package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
- package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
- package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
- package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
- package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
- package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
- package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
- package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
- package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
- package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
- package/dist-pkg/core/anel.d.ts +0 -17
- package/dist-pkg/core/anel.js +0 -31
- package/dist-pkg/core/collision.d.ts +0 -21
- package/dist-pkg/core/collision.js +0 -62
- package/dist-pkg/core/layers.d.ts +0 -63
- package/dist-pkg/core/layers.js +0 -95
- package/dist-pkg/core/letter-grid.d.ts +0 -55
- package/dist-pkg/core/letter-grid.js +0 -116
- package/dist-pkg/core/password.d.ts +0 -34
- package/dist-pkg/core/password.js +0 -205
- package/dist-pkg/core/rotulo-acessivel.d.ts +0 -17
- package/dist-pkg/core/rotulo-acessivel.js +0 -41
- package/dist-pkg/core/run-state.d.ts +0 -115
- package/dist-pkg/core/run-state.js +0 -40
- package/dist-pkg/core/tiles.d.ts +0 -12
- package/dist-pkg/core/tiles.js +0 -61
- package/dist-pkg/core/world.d.ts +0 -4
- package/dist-pkg/core/world.js +0 -58
- package/dist-pkg/input/origem-sintetica.d.ts +0 -44
- package/dist-pkg/input/origem-sintetica.js +0 -60
- package/dist-pkg/input/transporte-em-uso.d.ts +0 -101
- package/dist-pkg/input/transporte-em-uso.js +0 -130
- package/dist-pkg/platform/audio-nav.d.ts +0 -51
- package/dist-pkg/platform/audio-nav.js +0 -99
- package/dist-pkg/platform/guide-intensity.d.ts +0 -40
- package/dist-pkg/platform/guide-intensity.js +0 -73
- package/dist-pkg/platform/pesados-catalogo.d.ts +0 -14
- package/dist-pkg/platform/pesados-catalogo.js +0 -177
- package/dist-pkg/platform/pesados.d.ts +0 -31
- package/dist-pkg/platform/pesados.js +0 -75
- package/dist-pkg/platform/vozes-prontas.d.ts +0 -28
- package/dist-pkg/platform/vozes-prontas.js +0 -61
- package/dist-pkg/render/camera.d.ts +0 -58
- package/dist-pkg/render/camera.js +0 -105
- package/dist-pkg/render/cenario-data.d.ts +0 -127
- package/dist-pkg/render/cenario-data.js +0 -145
- package/dist-pkg/render/city-tex.d.ts +0 -63
- package/dist-pkg/render/city-tex.js +0 -228
- package/dist-pkg/render/city-tiles.d.ts +0 -11
- package/dist-pkg/render/city-tiles.js +0 -140
- package/dist-pkg/render/draw.d.ts +0 -149
- package/dist-pkg/render/draw.js +0 -231
- package/dist-pkg/render/fx.d.ts +0 -63
- package/dist-pkg/render/fx.js +0 -123
- package/dist-pkg/render/minimap.d.ts +0 -11
- package/dist-pkg/render/minimap.js +0 -94
- package/dist-pkg/render/parallax.d.ts +0 -85
- package/dist-pkg/render/parallax.js +0 -158
- package/dist-pkg/render/player-anim.d.ts +0 -71
- package/dist-pkg/render/player-anim.js +0 -152
- package/dist-pkg/render/recycling-tex.d.ts +0 -48
- package/dist-pkg/render/recycling-tex.js +0 -164
- package/dist-pkg/render/scene-city.d.ts +0 -77
- package/dist-pkg/render/scene-city.js +0 -181
- package/dist-pkg/render/scene-parallax.d.ts +0 -72
- package/dist-pkg/render/scene-parallax.js +0 -426
- package/dist-pkg/render/scene-sky.d.ts +0 -126
- package/dist-pkg/render/scene-sky.js +0 -295
- package/dist-pkg/render/set-cenario.d.ts +0 -54
- package/dist-pkg/render/set-cenario.js +0 -103
- package/dist-pkg/render/textures.d.ts +0 -75
- package/dist-pkg/render/textures.js +0 -240
- package/dist-pkg/render/title-scene.d.ts +0 -46
- package/dist-pkg/render/title-scene.js +0 -75
- package/dist-pkg/render/weather.d.ts +0 -96
- package/dist-pkg/render/weather.js +0 -171
- package/dist-pkg/render/wheelchair-sprites.d.ts +0 -32
- package/dist-pkg/render/wheelchair-sprites.js +0 -69
- package/dist-pkg/render/world-tex.d.ts +0 -18
- package/dist-pkg/render/world-tex.js +0 -87
- package/dist-pkg/ui/activities-menu.d.ts +0 -258
- package/dist-pkg/ui/activities-menu.js +0 -648
- package/dist-pkg/ui/caa-sets.d.ts +0 -39
- package/dist-pkg/ui/caa-sets.js +0 -65
- package/dist-pkg/ui/latch-refusal.d.ts +0 -32
- package/dist-pkg/ui/latch-refusal.js +0 -60
- package/dist-pkg/ui/map-hub.d.ts +0 -56
- package/dist-pkg/ui/map-hub.js +0 -138
- package/dist-pkg/ui/settings-caa.d.ts +0 -45
- package/dist-pkg/ui/settings-caa.js +0 -137
- package/dist-pkg/ui/settings-motor.d.ts +0 -175
- package/dist-pkg/ui/settings-motor.js +0 -342
- package/dist-pkg/ui/webcam.d.ts +0 -7
- package/dist-pkg/ui/webcam.js +0 -93
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
const F = (family, names) => names.map((name) => ({ name, family }));
|
|
3
|
+
export const GENRES = Object.freeze([
|
|
4
|
+
...F('Action', ['Platform games', 'Shooter games', 'First-person shooters', 'Hero shooters', 'Light gun shooters',
|
|
5
|
+
"Shoot 'em ups", 'Fighting games', "Beat 'em up games", 'Stealth games', 'Survival games', 'Rhythm games',
|
|
6
|
+
'Battle royale games']),
|
|
7
|
+
...F('Action-adventure', ['Survival horror', 'Metroidvania']),
|
|
8
|
+
...F('Adventure', ['Text adventures', 'Graphic adventures', 'Visual novels', 'Interactive movie']),
|
|
9
|
+
...F('Puzzle', ['Breakout clone game', 'Logical game', 'Physics game', 'Programming game', 'Puzzle-platform game',
|
|
10
|
+
'Hidden object game', 'Reveal the picture game', 'Tile-matching game', 'Traditional puzzle game']),
|
|
11
|
+
...F('Role-playing', ['Action RPG', 'CRPG', 'MMORPG', 'Roguelikes', 'Tactical RPG', 'Sandbox RPG',
|
|
12
|
+
'First-person party-based RPG', 'Monster-taming']),
|
|
13
|
+
...F('Simulation', ['Construction and management simulation', 'Life simulation', 'Vehicle simulation']),
|
|
14
|
+
...F('Strategy', ['4X game', 'Artillery game', 'Auto battler', 'Auto chess', 'MOBA', 'RTS', 'RTT', 'Tower defense', 'TBS',
|
|
15
|
+
'TBT', 'Wargame', 'Grand strategy wargame']),
|
|
16
|
+
...F('Sports', ['Racing', 'Sports game']),
|
|
17
|
+
...F('MMO', ['MMO']),
|
|
18
|
+
...F('Other notable genres', ['Board game or card game']),
|
|
19
|
+
{ name: 'Casino game', family: 'Other notable genres', mark: 'refused' },
|
|
20
|
+
...F('Other notable genres', ['Digital collectible card game', 'Digital therapeutic video game', 'Gacha game']),
|
|
21
|
+
{ name: 'Horror game', family: 'Other notable genres', mark: 'avoid' },
|
|
22
|
+
...F('Other notable genres', ['Idle game', 'Party game', 'Photography game', 'Social deduction game', 'Trivia game',
|
|
23
|
+
'Typing game']),
|
|
24
|
+
].map((g) => Object.freeze(g)));
|
|
25
|
+
/** Is a declared genre acceptable? EMPTY means conformant; any line refuses the boot (a malformed declaration). */
|
|
26
|
+
export function genreProblems(genre) {
|
|
27
|
+
if (genre === undefined)
|
|
28
|
+
return [];
|
|
29
|
+
if (typeof genre !== 'string')
|
|
30
|
+
return ['genre: must be a genre name from the engine\'s list (ADR-0156), or absent'];
|
|
31
|
+
const g = GENRES.find((x) => x.name === genre);
|
|
32
|
+
if (!g)
|
|
33
|
+
return [`genre: «${genre}» is not in the engine's genre list (ADR-0156) - declare what the game plays like, or no genre`];
|
|
34
|
+
if (g.mark === 'refused')
|
|
35
|
+
return [`genre: Casino game is prohibited in this engine (ADR-0156 §2) - a cartridge that declares it does not boot`];
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
/** The line `problems` carries for an accepted genre with a mark: Horror game plays, and the author reads why to avoid it. */
|
|
39
|
+
export function genreWarning(genre) {
|
|
40
|
+
const g = typeof genre === 'string' ? GENRES.find((x) => x.name === genre) : undefined;
|
|
41
|
+
return g?.mark === 'avoid'
|
|
42
|
+
? `genre: Horror game is marked avoid - it is hard to make work for children (ADR-0156 §3); consider what else the game plays like`
|
|
43
|
+
: null;
|
|
44
|
+
}
|
package/dist-pkg/core/i18n.d.ts
CHANGED
|
@@ -1,71 +1,82 @@
|
|
|
1
1
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/** One language's dictionary: a key and its text. */
|
|
2
3
|
type LocaleDict = Record<string, string>;
|
|
4
|
+
/** The languages a page can switch to — a constant, so it stays a function of the module (ADR-0232 D3). */
|
|
5
|
+
export declare function availableLocales(): string[];
|
|
3
6
|
/**
|
|
4
|
-
*
|
|
5
|
-
* de qualquer `setLocale('en')` é atendido quando a troca acontecer.
|
|
6
|
-
*
|
|
7
|
-
* ⚠️ NÃO REAPLICA O DOM, de propósito. `applyDom` precisa de uma RAIZ, e alcançar o `document` global por
|
|
8
|
-
* baixo de quem chama é o achado 15, que já custou uma correção. Um consumidor que registre depois de o
|
|
9
|
-
* markup estático ter sido traduzido chama `applyDom(raiz)` ele mesmo — e o caso normal é registrar no boot,
|
|
10
|
-
* antes de existir texto na tela.
|
|
11
|
-
*/
|
|
12
|
-
export declare function registerDict(code: string, entries: LocaleDict): string[];
|
|
13
|
-
export declare function t(key: string, params?: Record<string, string | number>): string;
|
|
14
|
-
export declare function getLocale(): string;
|
|
15
|
-
/**
|
|
16
|
-
* A etiqueta BCP-47 do idioma corrente — o que se escreve em `<html lang>` e o que se entrega a APIs do
|
|
17
|
-
* navegador que falam (Web Speech) ou comparam idioma.
|
|
7
|
+
* The port the chosen language is kept through (ADR-0178): `platform/storage` has this shape.
|
|
18
8
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* propósito — o navegador escolhe a variante local, que é o certo, e fixar 'en-US' imporia sotaque americano
|
|
22
|
-
* a quem estivesse na Índia ou na Nigéria.
|
|
9
|
+
* 🔴 AND IT CARRIES THE BROWSER TOO (ADR-0221 step 7g): the page effects arrive as optional hooks that
|
|
10
|
+
* `platform/locale-host` builds and the composition root passes in, so `core` reaches no `document` or `window`.
|
|
23
11
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
12
|
+
* ⚠️ The hooks are OPTIONAL, and absent they mean «no page to tell»: a node test, a worker, a second engine in the same
|
|
13
|
+
* process.
|
|
26
14
|
*/
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
15
|
+
export interface LocalePort {
|
|
16
|
+
get(key: string, fallback: string | null): string | null;
|
|
17
|
+
set(key: string, value: string): unknown;
|
|
18
|
+
readonly KEYS: {
|
|
19
|
+
readonly lang: string;
|
|
20
|
+
};
|
|
21
|
+
/** What the HOST does once a language is kept: `<html lang>`, re-translating the markup, telling the page. */
|
|
22
|
+
readonly applied?: (locale: string, tag: string) => void;
|
|
23
|
+
/** The language the host prefers when nothing is stored (the browser's `navigator.language`). */
|
|
24
|
+
readonly preferred?: () => string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Hears a language ANOTHER root on the same page switched to — the page's signal to its host (`i18n:change`).
|
|
27
|
+
* The LANGUAGE is the page's (`<html lang>` is one attribute), so every root follows it (ADR-0232 D3 erratum point 3).
|
|
28
|
+
*/
|
|
29
|
+
readonly follow?: (react: (locale: string) => void) => void;
|
|
30
|
+
}
|
|
31
|
+
/** What a module that only TRANSLATES receives (ADR-0232 D3): a key and its `{param}`s in, the text of the page's language out. */
|
|
32
|
+
export type Translate = (key: string, params?: Record<string, string | number>) => string;
|
|
33
|
+
export declare function bcp47(code: string): string;
|
|
31
34
|
/**
|
|
32
|
-
*
|
|
33
|
-
* troca — que é assíncrona, porque os outros locales são chunks sob demanda.
|
|
35
|
+
* THE TRANSLATOR A ROOT BUILDS AND HANDS DOWN (ADR-0232 D3, and its errata).
|
|
34
36
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* `root` ENTRA em vez de ser lido do global, e foi o `boot/createGame()` que cobrou (item 13): a raiz de
|
|
39
|
-
* composição recebe o documento do hospedeiro por injeção e não tinha como repassá-lo — esta linha alcançava
|
|
40
|
-
* o `document` global por baixo dela. Num navegador dá no mesmo; no project `node` é a diferença entre
|
|
41
|
-
* bootar contra um DOM de mentira e não bootar. O padrão continua sendo o global, então nenhum chamador
|
|
42
|
-
* muda: é a mesma regra do `applyDom` logo acima.
|
|
37
|
+
* It holds everything that changes: the page's language as this root knows it, the dictionaries loaded, and the GAME's own
|
|
38
|
+
* dictionary, which no other root on the page reads. A module that only translates receives the bare `t`; one that reads or
|
|
39
|
+
* sets the language receives this object.
|
|
43
40
|
*/
|
|
44
|
-
export
|
|
41
|
+
export interface Translator {
|
|
42
|
+
readonly t: Translate;
|
|
43
|
+
/** The page's language code (`pt`, `en`, `es`). */
|
|
44
|
+
readonly locale: () => string;
|
|
45
|
+
/** The BCP-47 tag of a language, the page's by default — what speech and recognition are given. */
|
|
46
|
+
readonly bcp47: (code?: string) => string;
|
|
47
|
+
/** Switches the PAGE's language; every root on the page follows (through the port's `follow`). */
|
|
48
|
+
readonly setLocale: (code: string) => Promise<void>;
|
|
49
|
+
/** Hears a language change; returns the release (the root passes this through its disposing door, ADR-0220). */
|
|
50
|
+
readonly onChange: (react: (locale: string) => void) => () => void;
|
|
51
|
+
/** Translates the declarative markup (`data-i18n`, `data-i18n-aria`) under `root`. */
|
|
52
|
+
readonly applyDom: (root: ParentNode) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Boot: translates `root` in pt (synchronously, so the page is never blank) and, if the stored or preferred language is
|
|
55
|
+
* another, ASKS for the switch — asynchronous, because the other locales are on-demand chunks. Returns the locale now;
|
|
56
|
+
* whoever needs to wait calls `ready()`. `root` comes in, never the global `document` (finding 15 of `boot/create-game`).
|
|
57
|
+
*/
|
|
58
|
+
readonly init: (root: ParentNode) => string;
|
|
59
|
+
/** Resolves when the language chosen at boot has loaded. */
|
|
60
|
+
readonly ready: () => Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Registers a game's keys for a language IN THIS TRANSLATOR — its root's dictionary, which no other root on the page
|
|
63
|
+
* reads (ADR-0232 D3 erratum); returns the refused ones (markup).
|
|
64
|
+
*/
|
|
65
|
+
readonly registerDict: (code: string, entries: LocaleDict) => string[];
|
|
66
|
+
/** The keys this translator's game registered in one language and not another, for `problems` (study item E4). */
|
|
67
|
+
readonly dictionaryGaps: () => string[];
|
|
68
|
+
/**
|
|
69
|
+
* A WORD THE GAME DECLARED, by its key (ADR-0232 D3 erratum of 2026-09-25): resolved in the page's language from THIS
|
|
70
|
+
* game's dictionary, falling back to its pt — and `null` when the game's dictionary has it in neither. Never the key: a
|
|
71
|
+
* key on screen is an identifier in front of a child. Whoever draws decides what an absent word means (a row not drawn).
|
|
72
|
+
*/
|
|
73
|
+
readonly word: (key: string) => string | null;
|
|
74
|
+
/** Does this game's dictionary have `key` in any language? What `problems` asks of every declared key. */
|
|
75
|
+
readonly declares: (key: string) => boolean;
|
|
76
|
+
}
|
|
45
77
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* ========================= POR QUE ISTO PRECISOU EXISTIR =========================
|
|
49
|
-
* O `initI18n()` do main.js era a ÚLTIMA linha do boot, depois de o HUD, os menus de título e as telas de
|
|
50
|
-
* pausa já estarem montados. Para pt isso não custava nada — já estava tudo em português. Para en/es, custava
|
|
51
|
-
* metade da interface: o `applyDom` conserta o markup ESTÁTICO (`data-i18n`), mas o que o JavaScript monta
|
|
52
|
-
* (os botões de cenário, os de atividade) tinha capturado o texto de pt e ninguém reconstruía.
|
|
53
|
-
*
|
|
54
|
-
* O sintoma era desconcertante: `t('cen.cidade')` devolvia "City" e o botão na tela dizia "Cidade".
|
|
55
|
-
*
|
|
56
|
-
* Isto NÃO responde à pergunta maior — QUANDO a interface se reconstrói ao trocar de idioma EM EXECUÇÃO —,
|
|
57
|
-
* que segue com o Dev. Responde à menor, que não tem duas respostas: a interface não se constrói antes de o
|
|
58
|
-
* idioma ser conhecido.
|
|
78
|
+
* Builds a translator. `port` keeps the chosen language and tells the page (ADR-0178); without one there is no page to tell
|
|
79
|
+
* and nothing to keep, and `setLocale` refuses — a test that only translates needs none.
|
|
59
80
|
*/
|
|
60
|
-
export declare function
|
|
61
|
-
|
|
62
|
-
t: typeof t;
|
|
63
|
-
getLocale: typeof getLocale;
|
|
64
|
-
availableLocales: typeof availableLocales;
|
|
65
|
-
applyDom: typeof applyDom;
|
|
66
|
-
setLocale: typeof setLocale;
|
|
67
|
-
initI18n: typeof initI18n;
|
|
68
|
-
idiomaPronto: typeof idiomaPronto;
|
|
69
|
-
registerDict: typeof registerDict;
|
|
70
|
-
};
|
|
71
|
-
export default i18n;
|
|
81
|
+
export declare function createTranslator(port?: LocalePort): Translator;
|
|
82
|
+
export {};
|
package/dist-pkg/core/i18n.js
CHANGED
|
@@ -1,236 +1,222 @@
|
|
|
1
1
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
-
// i18n —
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
2
|
+
// core/i18n — internationalisation.
|
|
3
|
+
// The default language (pt) is a STATIC import, so its dictionary is ready before anything renders (a synchronous boot).
|
|
4
|
+
// The others load on demand when the language changes, as their own chunks (see the loaders below).
|
|
5
|
+
//
|
|
6
|
+
// 🔴 THIS MODULE HOLDS NO STATE (ADR-0232 D3, erratum of 2026-09-25). Everything that changes — the language in use, the
|
|
7
|
+
// dictionaries loaded, the game's own dictionary, who listens to a change, the boot's pending load, the port the choice is
|
|
8
|
+
// kept through — lives in the TRANSLATOR a composition root builds (`createTranslator`). What stays at module level is
|
|
9
|
+
// constant: the base dictionary, the list of languages, their loaders and their regions. Two roots on one page, or two
|
|
10
|
+
// test files, share nothing through this module.
|
|
7
11
|
import pt from '../i18n/pt.js';
|
|
8
|
-
import * as store from '../platform/storage.js';
|
|
9
12
|
const AVAILABLE = ['pt', 'en', 'es'];
|
|
10
|
-
const base = pt; //
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* abaixo, e esse glob é resolvido NO BUILD DESTA ENGINE, contra ESTA pasta. Um jogo que instala
|
|
21
|
-
* `@the-inclusionist/engine` não tem como pôr arquivo lá dentro, e `DICTS` é privado. Sem esta camada ele
|
|
22
|
-
* fica sem NENHUM caminho para as próprias chaves — e o pilar 3 não abre exceção para consumidor.
|
|
23
|
-
*
|
|
24
|
-
* CAMADA SEPARADA, e não `DICTS[code] = {...DICTS[code], ...extra}`: `DICTS.pt` É o objeto importado de
|
|
25
|
-
* `../i18n/pt.ts`. Mesclar ali mutaria o dicionário da própria engine, e dois jogos na mesma página herdariam
|
|
26
|
-
* as strings um do outro. `tests/i18n-consumer-dict.node.test.js` prende exatamente isso.
|
|
27
|
-
*/
|
|
28
|
-
const EXTRA = {};
|
|
29
|
-
/**
|
|
30
|
-
* Registra as chaves DESTE jogo para um idioma. Chamável antes de o idioma existir — quem registra `en` antes
|
|
31
|
-
* de qualquer `setLocale('en')` é atendido quando a troca acontecer.
|
|
32
|
-
*
|
|
33
|
-
* ⚠️ NÃO REAPLICA O DOM, de propósito. `applyDom` precisa de uma RAIZ, e alcançar o `document` global por
|
|
34
|
-
* baixo de quem chama é o achado 15, que já custou uma correção. Um consumidor que registre depois de o
|
|
35
|
-
* markup estático ter sido traduzido chama `applyDom(raiz)` ele mesmo — e o caso normal é registrar no boot,
|
|
36
|
-
* antes de existir texto na tela.
|
|
37
|
-
*/
|
|
38
|
-
export function registerDict(code, entries) {
|
|
39
|
-
const recusadas = [];
|
|
40
|
-
const aceites = {};
|
|
41
|
-
for (const chave in entries) {
|
|
42
|
-
if (temMarcacao(entries[chave]))
|
|
43
|
-
recusadas.push(chave);
|
|
13
|
+
const base = pt; // the base dictionary (fallback), typed
|
|
14
|
+
/** The languages a page can switch to — a constant, so it stays a function of the module (ADR-0232 D3). */
|
|
15
|
+
export function availableLocales() { return AVAILABLE.slice(); }
|
|
16
|
+
/** Puts `entries` into `layer` for `code`, refusing what carries markup (see `hasMarkup`); returns the refused keys. */
|
|
17
|
+
function addEntries(layer, code, entries) {
|
|
18
|
+
const refused = [];
|
|
19
|
+
const accepted = {};
|
|
20
|
+
for (const key in entries) {
|
|
21
|
+
if (hasMarkup(entries[key]))
|
|
22
|
+
refused.push(key);
|
|
44
23
|
else
|
|
45
|
-
|
|
24
|
+
accepted[key] = entries[key];
|
|
46
25
|
}
|
|
47
|
-
if (
|
|
48
|
-
//
|
|
49
|
-
//
|
|
26
|
+
if (refused.length) {
|
|
27
|
+
// Loud, not silent: whoever wrote the string has to know it did not go in. Dropping it quietly would put the raw
|
|
28
|
+
// key on screen with nothing explaining it, and that reads as an engine defect.
|
|
50
29
|
try {
|
|
51
|
-
console.error('[inclusionist] i18n:
|
|
30
|
+
console.error('[inclusionist] i18n: keys refused because they contain markup — ' + refused.join(', '));
|
|
52
31
|
}
|
|
53
32
|
catch { /* noop */ }
|
|
54
33
|
}
|
|
55
|
-
|
|
56
|
-
return
|
|
34
|
+
layer[code] = { ...layer[code], ...accepted };
|
|
35
|
+
return refused;
|
|
57
36
|
}
|
|
58
37
|
/**
|
|
59
|
-
* A
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* tag. Ele não alcança — e não tem como alcançar — o `EXTRA`: são strings que um JOGO regista em tempo de
|
|
64
|
-
* execução, de outro repositório (ADR-0083), e um teste desta árvore não as vê.
|
|
65
|
-
*
|
|
66
|
-
* ⚠️ E ELAS GANHAM DO DICIONÁRIO DA ENGINE. `resolver` consulta `EXTRA` primeiro, então um jogo pode sobrepor
|
|
67
|
-
* QUALQUER chave — inclusive as que a engine cola em markup. Sem este cheque, «i18n» tinha deixado de
|
|
68
|
-
* significar «texto que alguém desta árvore reviu», e nada registava a mudança.
|
|
69
|
-
*
|
|
70
|
-
* A verificação vai na FRONTEIRA e não nos sinks porque a fronteira é UMA: toda string de um jogo passa por
|
|
71
|
-
* aqui. Quinze sinks seriam quinze lugares para esquecer, e o esquecimento não deixa rasto.
|
|
72
|
-
*
|
|
73
|
-
* O crivo é deliberadamente grosseiro — `<` seguido de letra ou de barra, e `&` de entidade. Ele recusa
|
|
74
|
-
* `a < b` escrito com espaço? Não: `< ` não casa. Recusa «5<10»? Não, o dígito não casa. O que ele recusa é
|
|
75
|
-
* o que se parece com uma tag, e uma frase de interface que precise disso precisa de outra frase.
|
|
38
|
+
* THE KEYS A CARTRIDGE REGISTERED IN ONE OF THE THREE LANGUAGES AND NOT IN ANOTHER (study item E4; ADR-0010 pillar 3),
|
|
39
|
+
* one line per missing language, for `problems`. 📏 Measured: the games that register a dictionary do it in pt, en and es,
|
|
40
|
+
* and nothing checked it — a key forgotten in one language shows Portuguese there, and nobody is told.
|
|
41
|
+
* A cartridge that registered nothing is not accused: strings it never gave the engine, the engine cannot see.
|
|
76
42
|
*/
|
|
77
|
-
function
|
|
78
|
-
|
|
43
|
+
function gapsIn(layer) {
|
|
44
|
+
const registered = new Set();
|
|
45
|
+
for (const code of AVAILABLE)
|
|
46
|
+
for (const key in layer[code] ?? {})
|
|
47
|
+
registered.add(key);
|
|
48
|
+
if (!registered.size)
|
|
49
|
+
return [];
|
|
50
|
+
const SHOW = 5;
|
|
51
|
+
const gapLines = [];
|
|
52
|
+
for (const code of AVAILABLE) {
|
|
53
|
+
const missing = [...registered].filter((key) => !(key in (layer[code] ?? {})));
|
|
54
|
+
if (!missing.length)
|
|
55
|
+
continue;
|
|
56
|
+
const rest = missing.length > SHOW ? ` (and ${missing.length - SHOW} more)` : '';
|
|
57
|
+
gapLines.push(`the cartridge's dictionary lacks ${code} for ${missing.slice(0, SHOW).join(', ')}${rest}: `
|
|
58
|
+
+ `a child playing in ${code} reads the fallback there (CreateGameOptions.dictionaries)`);
|
|
59
|
+
}
|
|
60
|
+
return gapLines;
|
|
79
61
|
}
|
|
80
62
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
63
|
+
* Does a string carry markup?
|
|
64
|
+
*
|
|
65
|
+
* ⚠️ WHY THIS LIVES HERE, AND NOT IN THE ~15 SINKS THAT CONSUME i18n. The gate `tests/i18n-without-markup.node.test.js`
|
|
66
|
+
* sweeps THIS tree's dictionaries and proves no entry has a tag. It does not reach — and cannot reach — a game's own
|
|
67
|
+
* dictionary: those are strings a GAME registers at run time, from another repository (ADR-0083), and a test in this tree
|
|
68
|
+
* never sees them.
|
|
83
69
|
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
70
|
+
* ⚠️ AND THEY WIN OVER THE ENGINE'S DICTIONARY. The resolver looks at the game's dictionary first, so a game can override
|
|
71
|
+
* ANY key — including the ones the engine pastes into markup. Without this check "i18n" would have stopped meaning "text
|
|
72
|
+
* someone in this tree reviewed", and nothing would record the change.
|
|
86
73
|
*
|
|
87
|
-
*
|
|
88
|
-
* português, exatamente como já lê hoje quando falta chave na engine. Degradar é melhor que calar, e é a
|
|
89
|
-
* mesma escolha que o `.catch` mudo do `initI18n` já faz para o chunk que não carrega.
|
|
74
|
+
* The check sits at the BOUNDARY and not in the sinks because the boundary is ONE: every string from a game passes here.
|
|
90
75
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
76
|
+
* The sieve is deliberately coarse — `<` followed by a letter or a slash, and `&` of an entity. `a < b` with a space and
|
|
77
|
+
* "5<10" pass; what it refuses is what looks like a tag, and an interface sentence that needs one needs another sentence.
|
|
93
78
|
*/
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
if (doJogo && key in doJogo)
|
|
97
|
-
return doJogo[key];
|
|
98
|
-
if (key in dict)
|
|
99
|
-
return dict[key];
|
|
100
|
-
const doJogoEmPt = EXTRA.pt;
|
|
101
|
-
if (doJogoEmPt && key in doJogoEmPt)
|
|
102
|
-
return doJogoEmPt[key];
|
|
103
|
-
return key in base ? base[key] : key;
|
|
79
|
+
function hasMarkup(value) {
|
|
80
|
+
return typeof value === 'string' && (/<[a-zA-Z/!?]/.test(value) || /&[a-zA-Z#][a-zA-Z0-9]*;/.test(value));
|
|
104
81
|
}
|
|
105
|
-
/* =====================
|
|
106
|
-
*
|
|
107
|
-
* Isto era `import.meta.glob<{default: LocaleDict}>('../i18n/*.ts')`, e a razão escrita no topo do arquivo
|
|
108
|
-
* continua verdadeira para este repositório: o Vite gera um chunk por locale e o service worker o cacheia.
|
|
82
|
+
/* ===================== THE LOADERS, AND WHY THEY ARE NOT A GLOB =====================
|
|
109
83
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* transforme o módulo, `import.meta.glob` é `undefined` e a chamada estoura no carregamento.
|
|
115
|
-
* · E mesmo transformado, o padrão diz `*.ts` — ao lado do arquivo EMITIDO só existem `.js`. O glob casaria
|
|
116
|
-
* zero arquivos, `ensure()` cairia no `return base`, e todo idioma que não fosse pt viraria português
|
|
117
|
-
* SEM ERRO NENHUM. É o modo de falhar que este projeto já pagou uma vez, quando uma regex morreu em
|
|
118
|
-
* silêncio com a checagem verde.
|
|
84
|
+
* This used to be `import.meta.glob('../i18n/*.ts')`. ⚠️ In the PACKAGE build (`tsc -p tsconfig.pkg.json`) that line
|
|
85
|
+
* survives the emit intact, and there it is false twice over: `tsc` copies `import.meta.glob(...)` as an ordinary call
|
|
86
|
+
* (undefined in a consumer that does not transform the module), and the pattern says `*.ts` next to emitted `.js` files —
|
|
87
|
+
* every language but pt would silently become Portuguese.
|
|
119
88
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* ⚠️ E O CODE-SPLITTING NÃO SE PERDE, o que eu tinha suposto que se perderia. O que o Vite divide é o
|
|
124
|
-
* `import()` DINÂMICO, e ele continua aqui — a primeira versão deste comentário dizia que o custo eram
|
|
125
|
-
* "~63 KB de parse a mais", e o build de 2026-09-05 mostrou o contrário na saída: `dist/assets/en-*.js`
|
|
126
|
-
* (24,8 KB) e `dist/assets/es-*.js` (26,7 KB) seguem como chunks próprios, exatamente como com o glob. Quem
|
|
127
|
-
* fica em pt nunca os avalia. O custo real é UM: três linhas a manter à mão no dia em que entrar um quarto
|
|
128
|
-
* idioma — e `AVAILABLE` já era essa lista, então é o mesmo dia e o mesmo arquivo. */
|
|
89
|
+
* ENUMERATED, THEN — and code splitting is not lost, because what Vite splits is the dynamic `import()`: `en` and `es`
|
|
90
|
+
* still ship as their own chunks, and a child who stays in pt never evaluates them. The one cost is three lines to keep
|
|
91
|
+
* by hand the day a fourth language arrives — the same day and the same file as `AVAILABLE`. */
|
|
129
92
|
const loaders = {
|
|
130
93
|
en: () => import('../i18n/en.js'),
|
|
131
94
|
es: () => import('../i18n/es.js'),
|
|
132
95
|
};
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// Traduz uma chave; a cadeia de fallback está em `resolver()` logo acima. Interpola {param}.
|
|
136
|
-
export function t(key, params) {
|
|
137
|
-
let s = resolver(key);
|
|
96
|
+
/** Interpolates `{param}` into a resolved string. */
|
|
97
|
+
function interpolate(s, params) {
|
|
138
98
|
if (params)
|
|
139
99
|
for (const k in params)
|
|
140
100
|
s = s.replaceAll('{' + k + '}', String(params[k]));
|
|
141
101
|
return s;
|
|
142
102
|
}
|
|
143
|
-
export function getLocale() { return locale; }
|
|
144
103
|
/**
|
|
145
|
-
*
|
|
146
|
-
* navegador que falam (Web Speech) ou comparam idioma.
|
|
147
|
-
*
|
|
148
|
-
* Só o português precisa de região: 'pt' sozinho deixaria o navegador escolher entre pt-PT e pt-BR, e a
|
|
149
|
-
* diferença de prosódia é audível para uma criança brasileira. Inglês e espanhol ficam sem região de
|
|
150
|
-
* propósito — o navegador escolhe a variante local, que é o certo, e fixar 'en-US' imporia sotaque americano
|
|
151
|
-
* a quem estivesse na Índia ou na Nigéria.
|
|
104
|
+
* THE BCP-47 TAG OF A LANGUAGE — what `<html lang>` says and what the browser's speech and recognition are given.
|
|
152
105
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
106
|
+
* Each language carries the REGION its flag stands for (the Dev, 2026-09-16: «Brasil, Estados Unidos e México. Cada bandeira indica a
|
|
107
|
+
* localização para qual o app está configurado»): pt-BR, en-US, es-MX. Voices are still matched on the language alone
|
|
108
|
+
* (`voicesForLocale`), so a region narrows nothing a child can hear. A translator answers it for the page's language.
|
|
155
109
|
*/
|
|
156
|
-
|
|
157
|
-
export function
|
|
158
|
-
// Aplica as traduções declarativas do HTML: [data-i18n] → textContent; [data-i18n-aria] → aria-label.
|
|
159
|
-
export function applyDom(root = document) {
|
|
160
|
-
root.querySelectorAll('[data-i18n]').forEach((el) => { const k = el.getAttribute('data-i18n'); if (k)
|
|
161
|
-
el.textContent = t(k); });
|
|
162
|
-
root.querySelectorAll('[data-i18n-aria]').forEach((el) => { const k = el.getAttribute('data-i18n-aria'); if (k)
|
|
163
|
-
el.setAttribute('aria-label', t(k)); });
|
|
164
|
-
}
|
|
165
|
-
async function ensure(code) {
|
|
166
|
-
if (DICTS[code])
|
|
167
|
-
return DICTS[code];
|
|
168
|
-
const load = loaders[code];
|
|
169
|
-
if (!load)
|
|
170
|
-
return base; // idioma sem arquivo → cai no pt
|
|
171
|
-
const mod = await load();
|
|
172
|
-
DICTS[code] = mod.default;
|
|
173
|
-
return DICTS[code];
|
|
174
|
-
}
|
|
175
|
-
// Troca o idioma (carrega sob demanda), persiste, atualiza <html lang>, reaplica o DOM e avisa a UI.
|
|
176
|
-
export async function setLocale(code) {
|
|
177
|
-
if (!AVAILABLE.includes(code))
|
|
178
|
-
code = 'pt';
|
|
179
|
-
dict = await ensure(code);
|
|
180
|
-
locale = code;
|
|
181
|
-
store.set(STORE_KEY, code);
|
|
182
|
-
document.documentElement.lang = bcp47(code);
|
|
183
|
-
applyDom(document);
|
|
184
|
-
window.dispatchEvent(new CustomEvent('i18n:change', { detail: { locale } }));
|
|
185
|
-
}
|
|
186
|
-
function pickDefault() {
|
|
187
|
-
const saved = store.get(STORE_KEY, null);
|
|
188
|
-
if (saved && AVAILABLE.includes(saved))
|
|
189
|
-
return saved;
|
|
190
|
-
const nav = ((navigator.language || 'pt').slice(0, 2)).toLowerCase();
|
|
191
|
-
return AVAILABLE.includes(nav) ? nav : 'pt';
|
|
192
|
-
}
|
|
193
|
-
/** Promessa do carregamento pedido no boot. Resolve na hora quando o idioma é pt (dicionário estático). */
|
|
194
|
-
let pendente = Promise.resolve();
|
|
110
|
+
const REGION_OF = { pt: 'pt-BR', en: 'en-US', es: 'es-MX' };
|
|
111
|
+
export function bcp47(code) { return REGION_OF[code] ?? code; }
|
|
195
112
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
* Continua devolvendo o locale de forma síncrona e NÃO bloqueia por si: quem precisar esperar chama
|
|
200
|
-
* `idiomaPronto()`. Foi essa separação que faltava — ver o comentário lá embaixo.
|
|
201
|
-
*
|
|
202
|
-
* `root` ENTRA em vez de ser lido do global, e foi o `boot/createGame()` que cobrou (item 13): a raiz de
|
|
203
|
-
* composição recebe o documento do hospedeiro por injeção e não tinha como repassá-lo — esta linha alcançava
|
|
204
|
-
* o `document` global por baixo dela. Num navegador dá no mesmo; no project `node` é a diferença entre
|
|
205
|
-
* bootar contra um DOM de mentira e não bootar. O padrão continua sendo o global, então nenhum chamador
|
|
206
|
-
* muda: é a mesma regra do `applyDom` logo acima.
|
|
113
|
+
* Builds a translator. `port` keeps the chosen language and tells the page (ADR-0178); without one there is no page to tell
|
|
114
|
+
* and nothing to keep, and `setLocale` refuses — a test that only translates needs none.
|
|
207
115
|
*/
|
|
208
|
-
export function
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
116
|
+
export function createTranslator(port) {
|
|
117
|
+
let locale = 'pt';
|
|
118
|
+
let dict = base;
|
|
119
|
+
/** Dictionaries already loaded (pt built in). */
|
|
120
|
+
const loaded = { pt: base };
|
|
121
|
+
/** THIS game's dictionary. A separate layer and not a merge into `loaded`: `loaded.pt` IS the imported engine object. */
|
|
122
|
+
const own = {};
|
|
123
|
+
const listeners = new Set();
|
|
124
|
+
let pending = Promise.resolve();
|
|
125
|
+
/*
|
|
126
|
+
* The resolution chain, in five steps: 1. game in the current language · 2. engine in the current language · 3. game in pt ·
|
|
127
|
+
* 4. engine in pt · 5. the key itself. Step 3 keeps a game that only wrote pt READABLE in English (degrading beats going
|
|
128
|
+
* quiet); step 2 before step 3 because the engine's right language is worth more than the game's wrong one.
|
|
129
|
+
*/
|
|
130
|
+
const resolveKey = (key) => {
|
|
131
|
+
const fromGame = own[locale];
|
|
132
|
+
if (fromGame && key in fromGame)
|
|
133
|
+
return fromGame[key];
|
|
134
|
+
if (key in dict)
|
|
135
|
+
return dict[key];
|
|
136
|
+
const fromGameInPt = own.pt;
|
|
137
|
+
if (fromGameInPt && key in fromGameInPt)
|
|
138
|
+
return fromGameInPt[key];
|
|
139
|
+
return key in base ? base[key] : key;
|
|
140
|
+
};
|
|
141
|
+
const t = (key, params) => interpolate(resolveKey(key), params);
|
|
142
|
+
const applyDom = (root) => {
|
|
143
|
+
root.querySelectorAll('[data-i18n]').forEach((el) => { const k = el.getAttribute('data-i18n'); if (k)
|
|
144
|
+
el.textContent = t(k); });
|
|
145
|
+
root.querySelectorAll('[data-i18n-aria]').forEach((el) => { const k = el.getAttribute('data-i18n-aria'); if (k)
|
|
146
|
+
el.setAttribute('aria-label', t(k)); });
|
|
147
|
+
};
|
|
148
|
+
const ensure = async (code) => {
|
|
149
|
+
if (loaded[code])
|
|
150
|
+
return loaded[code];
|
|
151
|
+
const load = loaders[code];
|
|
152
|
+
if (!load)
|
|
153
|
+
return base; // a language with no file → falls back to pt
|
|
154
|
+
const mod = await load();
|
|
155
|
+
loaded[code] = mod.default;
|
|
156
|
+
return loaded[code];
|
|
157
|
+
};
|
|
158
|
+
const tellListeners = () => {
|
|
159
|
+
for (const listener of [...listeners]) {
|
|
160
|
+
try {
|
|
161
|
+
listener(locale);
|
|
162
|
+
}
|
|
163
|
+
catch { /* a listener failed; the language changed */ }
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const setLocale = async (requested) => {
|
|
167
|
+
// first, before anything changes: a language switched and then refused would leave the page half moved (ADR-0178)
|
|
168
|
+
if (!port)
|
|
169
|
+
throw new Error('core/i18n: setLocale on a translator without a port — the composition root builds it with the stored settings (ADR-0178)');
|
|
170
|
+
const code = AVAILABLE.includes(requested) ? requested : 'pt';
|
|
171
|
+
dict = await ensure(code);
|
|
172
|
+
locale = code;
|
|
173
|
+
port.set(port.KEYS.lang, code);
|
|
174
|
+
// 📌 The three page effects — `<html lang>`, re-translating the markup, telling the page — in ONE call to the host, which
|
|
175
|
+
// is what keeps this module free of `document` and `window` (ADR-0173, ADR-0221 step 7g).
|
|
176
|
+
port.applied?.(locale, bcp47(code));
|
|
177
|
+
tellListeners();
|
|
178
|
+
};
|
|
179
|
+
// 📌 ANOTHER ROOT SWITCHED THE PAGE: this one follows without keeping or telling again — the root that switched did both.
|
|
180
|
+
port?.follow?.((code) => {
|
|
181
|
+
if (code === locale || !AVAILABLE.includes(code))
|
|
182
|
+
return;
|
|
183
|
+
void ensure(code).then((d) => { dict = d; locale = code; tellListeners(); });
|
|
184
|
+
});
|
|
185
|
+
const pickDefault = () => {
|
|
186
|
+
const saved = port ? port.get(port.KEYS.lang, null) : null;
|
|
187
|
+
if (saved && AVAILABLE.includes(saved))
|
|
188
|
+
return saved;
|
|
189
|
+
const nav = ((port?.preferred?.() || 'pt').slice(0, 2)).toLowerCase();
|
|
190
|
+
return AVAILABLE.includes(nav) ? nav : 'pt';
|
|
191
|
+
};
|
|
192
|
+
const init = (root) => {
|
|
193
|
+
applyDom(root);
|
|
194
|
+
const def = pickDefault();
|
|
195
|
+
// A silent `.catch` on purpose: a locale chunk that fails to load degrades to pt, and degrading is FAR better than
|
|
196
|
+
// freezing the boot. Without it, an `await ready()` outside would bring the whole game down over the language.
|
|
197
|
+
if (def !== 'pt')
|
|
198
|
+
pending = setLocale(def).catch(() => { });
|
|
199
|
+
return locale;
|
|
200
|
+
};
|
|
201
|
+
const word = (key) => {
|
|
202
|
+
const inLocale = own[locale];
|
|
203
|
+
if (inLocale && key in inLocale)
|
|
204
|
+
return inLocale[key];
|
|
205
|
+
const inPt = own.pt;
|
|
206
|
+
return inPt && key in inPt ? inPt[key] : null;
|
|
207
|
+
};
|
|
208
|
+
return {
|
|
209
|
+
t,
|
|
210
|
+
locale: () => locale,
|
|
211
|
+
bcp47: (code = locale) => bcp47(code),
|
|
212
|
+
setLocale,
|
|
213
|
+
onChange: (react) => { listeners.add(react); return () => { listeners.delete(react); }; },
|
|
214
|
+
applyDom,
|
|
215
|
+
init,
|
|
216
|
+
ready: () => pending,
|
|
217
|
+
registerDict: (code, entries) => addEntries(own, code, entries),
|
|
218
|
+
dictionaryGaps: () => gapsIn(own),
|
|
219
|
+
word,
|
|
220
|
+
declares: (key) => Object.values(own).some((entries) => key in entries),
|
|
221
|
+
};
|
|
216
222
|
}
|
|
217
|
-
/**
|
|
218
|
-
* Resolve quando o idioma escolhido no boot terminou de carregar (na hora, se for pt).
|
|
219
|
-
*
|
|
220
|
-
* ========================= POR QUE ISTO PRECISOU EXISTIR =========================
|
|
221
|
-
* O `initI18n()` do main.js era a ÚLTIMA linha do boot, depois de o HUD, os menus de título e as telas de
|
|
222
|
-
* pausa já estarem montados. Para pt isso não custava nada — já estava tudo em português. Para en/es, custava
|
|
223
|
-
* metade da interface: o `applyDom` conserta o markup ESTÁTICO (`data-i18n`), mas o que o JavaScript monta
|
|
224
|
-
* (os botões de cenário, os de atividade) tinha capturado o texto de pt e ninguém reconstruía.
|
|
225
|
-
*
|
|
226
|
-
* O sintoma era desconcertante: `t('cen.cidade')` devolvia "City" e o botão na tela dizia "Cidade".
|
|
227
|
-
*
|
|
228
|
-
* Isto NÃO responde à pergunta maior — QUANDO a interface se reconstrói ao trocar de idioma EM EXECUÇÃO —,
|
|
229
|
-
* que segue com o Dev. Responde à menor, que não tem duas respostas: a interface não se constrói antes de o
|
|
230
|
-
* idioma ser conhecido.
|
|
231
|
-
*/
|
|
232
|
-
export function idiomaPronto() { return pendente; }
|
|
233
|
-
const i18n = { t, getLocale, availableLocales, applyDom, setLocale, initI18n, idiomaPronto, registerDict };
|
|
234
|
-
export default i18n;
|
|
235
|
-
if (typeof window !== 'undefined')
|
|
236
|
-
window.__i18n = i18n; // exposto p/ teste/preview
|