aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--client/.gitignore1
-rw-r--r--client/makefile2
-rw-r--r--locale/en.ini1
-rw-r--r--locale/tools/src/main.rs50
-rw-r--r--test-client/.gitignore2
-rw-r--r--test-client/locale.ts14
-rw-r--r--test-client/main.ts4
-rw-r--r--test-client/makefile13
-rw-r--r--test-client/protocol.ts1
-rw-r--r--test-client/visual.ts30
11 files changed, 95 insertions, 25 deletions
diff --git a/.gitignore b/.gitignore
index ff418aaf..3cd84959 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,3 @@
/target
-/test-client/*.js
/specs/*.html
-/client/menu/book/book_*.webp*
*~
diff --git a/client/.gitignore b/client/.gitignore
index 3f695f45..a1c6d43d 100644
--- a/client/.gitignore
+++ b/client/.gitignore
@@ -1,2 +1,3 @@
.godot
/po
+/menu/book/book_*.webp*
diff --git a/client/makefile b/client/makefile
index 085ed748..c9a58f04 100644
--- a/client/makefile
+++ b/client/makefile
@@ -35,6 +35,6 @@ po/locales.csv: $(LT)
@mkdir -p po
$(LT) export-godot-csv ../locale $@
-po/%.po: ../locale/%.ini $(LT)
+po/%.po: ../locale/%.ini $(LT) ../locale/en.ini
@mkdir -p po
$(LT) export-po $< $@ --fallback ../locale/en.ini
diff --git a/locale/en.ini b/locale/en.ini
index f570818a..155f8f6c 100644
--- a/locale/en.ini
+++ b/locale/en.ini
@@ -60,6 +60,7 @@ c.score.good=Good service
c.score.points_par=You collected %s points
c.score.points=Points
c.score.poor=Poor service
+c.score.time_remaining=Time remaining
c.settings.apply=Save & Apply
c.settings.audio.master_volume=Master Volume
c.settings.audio.music_volume=Music Volume
diff --git a/locale/tools/src/main.rs b/locale/tools/src/main.rs
index 19f58b39..56b81f86 100644
--- a/locale/tools/src/main.rs
+++ b/locale/tools/src/main.rs
@@ -20,6 +20,12 @@ enum Args {
input: PathBuf,
output: PathBuf,
},
+ ExportJson {
+ #[arg(long)]
+ fallback: Option<PathBuf>,
+ input: PathBuf,
+ output: PathBuf,
+ },
ExportGodotCsv {
input_dir: PathBuf,
output: PathBuf,
@@ -52,32 +58,44 @@ static NATIVE_LANGUAGE_NAMES: &[(&str, &str)] = &[
("pt", "Português"),
];
+fn export_load(input: &Path, fallback: Option<PathBuf>) -> Result<BTreeMap<String, String>> {
+ let mut ini = load_ini(&input)?;
+ if let Some(fallback) = fallback {
+ let f = load_ini(&fallback)?;
+ for (k, v) in f {
+ #[allow(clippy::map_entry)]
+ if !ini.contains_key(&k) {
+ eprintln!("fallback: key {k:?} is missing");
+ ini.insert(k, v);
+ }
+ }
+ }
+ for &(code, name) in NATIVE_LANGUAGE_NAMES {
+ ini.insert(format!("c.settings.ui.language.{code}"), name.to_owned());
+ }
+ Ok(ini)
+}
+
fn main() -> Result<()> {
let args = Args::parse();
match args {
+ Args::ExportJson {
+ fallback,
+ input,
+ output,
+ } => {
+ let ini = export_load(&input, fallback)?;
+ File::create(output)?.write_all(serde_json::to_string(&ini)?.as_bytes())?;
+ Ok(())
+ }
Args::ExportPo {
remap_ids: id_map,
input,
output,
fallback,
} => {
- let mut ini = load_ini(&input)?;
+ let ini = export_load(&input, fallback)?;
let id_map = id_map.map(|path| load_ini(&path)).transpose()?;
- if let Some(fallback) = fallback {
- let f = load_ini(&fallback)?;
- for (k, v) in f {
- #[allow(clippy::map_entry)]
- if !ini.contains_key(&k) {
- eprintln!("fallback: key {k:?} is missing");
- ini.insert(k, v);
- }
- }
- }
-
- for &(code, name) in NATIVE_LANGUAGE_NAMES {
- ini.insert(format!("c.settings.ui.language.{code}"), name.to_owned());
- }
-
File::create(output)?.write_all(
format!(
r#"
diff --git a/test-client/.gitignore b/test-client/.gitignore
new file mode 100644
index 00000000..27b9b44d
--- /dev/null
+++ b/test-client/.gitignore
@@ -0,0 +1,2 @@
+/locale
+/*.js
diff --git a/test-client/locale.ts b/test-client/locale.ts
new file mode 100644
index 00000000..61d083b4
--- /dev/null
+++ b/test-client/locale.ts
@@ -0,0 +1,14 @@
+
+let TR: { [key: string]: string } = {}
+export async function init_locale(lang: string) {
+ const res = await fetch(`/locale/${encodeURIComponent(lang)}.json`, { headers: { "Accept": "application/json" } })
+ if (!res.ok) throw new Error("language pack download failed");
+ TR = await res.json()
+}
+
+export function tr(key: string, ...args: string[]): string {
+ let s = TR[key] ?? key;
+ if (args.length)
+ s = s.replace(/%(s|i)/ig, () => args.shift() ?? "[not provided]")
+ return s
+}
diff --git a/test-client/main.ts b/test-client/main.ts
index 875e420d..f48aef17 100644
--- a/test-client/main.ts
+++ b/test-client/main.ts
@@ -17,6 +17,7 @@
*/
/// <reference lib="dom" />
+import { init_locale } from "./locale.ts";
import { MovementBase, collide_player_player, update_movement } from "./movement.ts";
import { Gamedata, ItemIndex, ItemLocation, Message, MessageTimeout, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts";
import { V2, lerp_exp_v2_mut, normalize, lerp_exp } from "./util.ts";
@@ -35,7 +36,8 @@ const HANDLED_KEYS = [KEY_BOOST, KEY_CHAT, KEY_CLOSE, KEY_DOWN, KEY_UP, KEY_LEFT
export let ctx: CanvasRenderingContext2D;
export let canvas: HTMLCanvasElement;
let ws: WebSocket;
-document.addEventListener("DOMContentLoaded", () => {
+document.addEventListener("DOMContentLoaded", async () => {
+ await init_locale(navigator.language.split("-")[0] ?? "en")
const ws_uri = window.location.protocol.endsWith("s:")
? `wss://${window.location.host}/`
: `ws://${window.location.hostname}:27032/`
diff --git a/test-client/makefile b/test-client/makefile
index 2a83f5d0..72a04791 100644
--- a/test-client/makefile
+++ b/test-client/makefile
@@ -14,9 +14,20 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
.PHONY: all clean
-all: main.js
+all: main.js locales
+locales: $(patsubst ../locale/%.ini,locale/%.json,$(wildcard ../locale/*.ini))
clean:
rm main.js
+ rm -rf locale
main.js: main.ts $(wildcard *.ts)
esbuild $< --bundle --outfile=$@ --target=esnext --format=esm
+
+LT = ../target/release/localetool
+
+$(LT): $(shell find ../locale/tools -type f)
+ { cd ..; cargo build --release --bin localetool; }
+
+locale/%.json: ../locale/%.ini $(LT) ../locale/en.ini
+ @mkdir -p locale
+ $(LT) export-json $< $@ --fallback ../locale/en.ini
diff --git a/test-client/protocol.ts b/test-client/protocol.ts
index d0f5f997..4d243702 100644
--- a/test-client/protocol.ts
+++ b/test-client/protocol.ts
@@ -90,6 +90,7 @@ export type Message =
{ item: number }
| { text: string }
| { effect: string }
+ | { translation: { id: string, params: Message[] } }
export type ItemLocation =
{ player: PlayerID }
diff --git a/test-client/visual.ts b/test-client/visual.ts
index 09b6ec85..863fea41 100644
--- a/test-client/visual.ts
+++ b/test-client/visual.ts
@@ -15,6 +15,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { tr } from "./locale.ts";
import { ItemData, MessageData, PlayerData, TileData, camera, camera_scale, canvas, ctx, data, demands_completed, demands_failed, get_interact_target, global_message, interact_active_anim, interact_possible_anim, interact_target_anim, items_removed, keys_down, my_id, nametag_scale_anim, players, points, server_hints, tiles, time_remaining } from "./main.ts";
import { PLAYER_SIZE } from "./movement.ts";
import { draw_item_sprite, draw_tile_sprite, ItemName, TileName } from "./tiles.ts";
@@ -91,12 +92,12 @@ export function draw_ingame() {
ctx.textBaseline = "bottom"
ctx.font = "20px sans-serif"
if (time_remaining != undefined)
- ctx.fillText(`Time remaining: ${time_remaining?.toFixed(2)}`, 10, canvas.height - 90)
+ ctx.fillText(`${tr("c.score.time_remaining")}: ${time_remaining?.toFixed(2)}`, 10, canvas.height - 90)
ctx.font = "30px sans-serif"
- ctx.fillText(`Points: ${points}`, 10, canvas.height - 60)
+ ctx.fillText(`${tr("c.score.points")}: ${points}`, 10, canvas.height - 60)
ctx.font = "20px sans-serif"
- ctx.fillText(`Completed: ${demands_completed}`, 10, canvas.height - 30)
- ctx.fillText(`Failed: ${demands_failed}`, 10, canvas.height - 10)
+ ctx.fillText(`${tr("c.score.completed")}: ${demands_completed}`, 10, canvas.height - 30)
+ ctx.fillText(`${tr("c.score.failed")}: ${demands_failed}`, 10, canvas.height - 10)
if (keys_down.has("KeyP")) {
draw_debug()
@@ -258,6 +259,27 @@ function draw_message(m: MessageData) {
ctx.translate(0, 1)
}
+ if ("translation" in m.inner) {
+ ctx.translate(0, -1)
+
+ ctx.textAlign = "center"
+ ctx.font = "15px sans-serif"
+ ctx.scale(2 / camera_scale, 2 / camera_scale)
+
+ const text = tr(m.inner.translation.id, ...m.inner.translation.params.map(p => "text" in p ? p.text : "[not text]"));
+ const w = ctx.measureText(text).width + 30
+
+ ctx.fillStyle = "#fffa"
+ ctx.beginPath()
+ ctx.roundRect(-w / 2, -15, w, 30, 5)
+ ctx.fill()
+
+ ctx.fillStyle = "black"
+ ctx.textBaseline = "middle"
+ ctx.fillText(text, 0, 0)
+
+ ctx.translate(0, 1)
+ }
ctx.restore()
}