Add Japanese language.

This commit is contained in:
yukirij 2024-08-27 14:13:55 -07:00
parent 309d995541
commit 564db3f433
5 changed files with 168 additions and 85 deletions

View File

@ -31,11 +31,29 @@ async fn service_http(mut request:hyper::Request<hyper::body::Incoming>, args:Ht
// Serve cached files and upgrade websocket connections. // Serve cached files and upgrade websocket connections.
// //
{ {
use hyper::{Response, body::Bytes, header::{CONTENT_TYPE, CACHE_CONTROL}}; use hyper::{Response, body::Bytes, header::{CONTENT_TYPE, CACHE_CONTROL, ACCEPT_LANGUAGE}};
use http_body_util::Full; use http_body_util::Full;
println!("Serving: {}", request.uri().path()); println!("Serving: {}", request.uri().path());
let mut language_code = 0;
if let Some(languages) = request.headers().get(ACCEPT_LANGUAGE) {
if let Ok(languages) = languages.to_str() {
for decl in languages.split(",") {
let decl = decl.trim().to_lowercase();
if decl.len() >= 2 {
let code = &decl[..2];
language_code = match code {
"en" => 0,
"ja" => 1,
_ => { continue; }
}; break;
}
}
}
}
if hyper_tungstenite::is_upgrade_request(&request) { if hyper_tungstenite::is_upgrade_request(&request) {
if let Ok((response, websocket)) = hyper_tungstenite::upgrade(&mut request, None) { if let Ok((response, websocket)) = hyper_tungstenite::upgrade(&mut request, None) {
tokio::task::spawn(async move { tokio::task::spawn(async move {
@ -54,10 +72,23 @@ async fn service_http(mut request:hyper::Request<hyper::body::Incoming>, args:Ht
} }
} else { } else {
match args.cache.fetch(request.uri().path()) { match args.cache.fetch(request.uri().path()) {
Some(data) => Ok(Response::builder() Some(data) => {
let mut output = data.data;
match request.uri().path() {
"/.js" => {
output = [
format!("let CONFIG_LANGUAGE = {};", language_code).as_bytes().to_vec(),
output,
].concat();
}
_ => { }
}
Ok(Response::builder()
.header(CONTENT_TYPE, &data.mime) .header(CONTENT_TYPE, &data.mime)
.header(CACHE_CONTROL, "no-cache") .header(CACHE_CONTROL, "no-cache")
.body(Full::new(Bytes::from(data.data))).unwrap()), .body(Full::new(Bytes::from(output))).unwrap())
}
None => Ok(Response::builder() None => Ok(Response::builder()
.header(CONTENT_TYPE, "text/html") .header(CONTENT_TYPE, "text/html")
.header(CACHE_CONTROL, "no-cache") .header(CACHE_CONTROL, "no-cache")

View File

@ -559,7 +559,7 @@ const INTERFACE = {
let piece_id = GAME_DATA.board.tiles[INTERFACE_DATA.hover.tile].piece; let piece_id = GAME_DATA.board.tiles[INTERFACE_DATA.hover.tile].piece;
if(piece_id !== null) { if(piece_id !== null) {
let piece = GAME_DATA.board.pieces[piece_id]; let piece = GAME_DATA.board.pieces[piece_id];
text += " " + GAME.Const.Piece[piece.piece].name; text += " " + LANG(GAME.Const.Piece[piece.piece].name);
if(piece.promoted) { text += "+"; } if(piece.promoted) { text += "+"; }
} }
} else { } else {
@ -591,13 +591,13 @@ const INTERFACE = {
if(GAME_DATA.state.code == GAME.Const.State.Resign) { if(GAME_DATA.state.code == GAME.Const.State.Resign) {
ctx.fillStyle = INTERFACE.Color.HintCheck; ctx.fillStyle = INTERFACE.Color.HintCheck;
message = "Resign"; message = LANG("resign");
} else if(GAME_DATA.state.check != 0) { } else if(GAME_DATA.state.check != 0) {
ctx.fillStyle = INTERFACE.Color.HintCheck; ctx.fillStyle = INTERFACE.Color.HintCheck;
if(GAME_DATA.state.checkmate) { if(GAME_DATA.state.checkmate) {
message = "Checkmate"; message = LANG("checkmate");
} else { } else {
message = "Check"; message = LANG("check");
} }
} }

View File

@ -1,5 +1,8 @@
const LANGUAGE = { }; const LANGUAGE = { };
const LANG_ENGLISH = 0;
const LANG_JAPANESE = 1;
LANGUAGE.Term = class { LANGUAGE.Term = class {
constructor(en, jp) { constructor(en, jp) {
this.data = [ en, jp ]; this.data = [ en, jp ];
@ -7,15 +10,74 @@ LANGUAGE.Term = class {
}; };
LANGUAGE.Terms = { LANGUAGE.Terms = {
Dawn: new LANGUAGE.Term( "Dawn", "暁" ), dawn: new LANGUAGE.Term( "Dawn", "暁" ),
Dusk: new LANGUAGE.Term( "Dusk", "黄昏" ), dusk: new LANGUAGE.Term( "Dusk", "黄昏" ),
Handle: new LANGUAGE.Term( "Handle", "" ), handle: new LANGUAGE.Term( "Handle", "ハンドル" ),
Secret: new LANGUAGE.Term( "Secret", "" ), secret: new LANGUAGE.Term( "Secret", "秘文" ),
invitation: new LANGUAGE.Term( "Invitation", "招待" ),
Browse: new LANGUAGE.Term( "Browse", "" ), reconnect: new LANGUAGE.Term( "Reconnect", "再接続" ),
Resume: new LANGUAGE.Term( "Resume", "" ), register: new LANGUAGE.Term( "Register", "登録" ),
login: new LANGUAGE.Term( "Log In", "ログイン" ),
Check: new LANGUAGE.Term( "Check", "王手" ), challenge: new LANGUAGE.Term( "Challenge", "挑戦" ),
Checkmate: new LANGUAGE.Term( "Checkmate", "詰み" ),
browse: new LANGUAGE.Term( "Browse", "対局列挙" ),
resume: new LANGUAGE.Term( "Resume", "続く" ),
live: new LANGUAGE.Term( "Live", "今頃" ),
history: new LANGUAGE.Term( "History", "再生" ),
practice: new LANGUAGE.Term( "Practice", "練習" ),
guide: new LANGUAGE.Term( "Guide", "ガイド" ),
about: new LANGUAGE.Term( "About", "概要" ),
turn: new LANGUAGE.Term( "Turn", "手番数" ),
viewers: new LANGUAGE.Term( "Viewers", "観戦者" ),
review: new LANGUAGE.Term( "Review", "再生" ),
view: new LANGUAGE.Term( "View", "観戦" ),
refresh: new LANGUAGE.Term( "Refresh", "改まる" ),
rotate: new LANGUAGE.Term( "Rotate", "回る" ),
mirror: new LANGUAGE.Term( "Mirror", "鏡像" ),
back: new LANGUAGE.Term( "Back", "戻る" ),
resign: new LANGUAGE.Term( "Resign", "投了" ),
confirm: new LANGUAGE.Term( "Confirm", "確認" ),
reset: new LANGUAGE.Term( "Reset", "リセット" ),
auto: new LANGUAGE.Term( "Auto", "自動" ),
users: new LANGUAGE.Term( "Users", "ユーザー" ),
requests: new LANGUAGE.Term( "Requests", "挑戦状" ),
accept: new LANGUAGE.Term( "Accept", "受け入れ" ),
decline: new LANGUAGE.Term( "Decline", "断る" ),
check: new LANGUAGE.Term( "Check", "王手" ),
checkmate: new LANGUAGE.Term( "Checkmate", "詰み" ),
Militia: new LANGUAGE.Term( "Militia", "士" ),
Lance: new LANGUAGE.Term( "Lance", "槍" ),
Knight: new LANGUAGE.Term( "Knight", "騎" ),
Tower: new LANGUAGE.Term( "Tower", "塔" ),
Castle: new LANGUAGE.Term( "Castle", "城" ),
Dragon: new LANGUAGE.Term( "Dragon", "竜" ),
Behemoth: new LANGUAGE.Term( "Behemoth", "獣" ),
Omen: new LANGUAGE.Term( "Omen", "兆" ),
//: new LANGUAGE.Term( "", "" ),
}; };
function LANG(term)
{
return LANGUAGE.Terms[term].data[CONFIG_LANGUAGE];
}
function LANG_PAGEOF(min, max, total)
{
switch(CONFIG_LANGUAGE) {
case LANG_ENGLISH: return min + " - " + max + " of " + total;
case LANG_JAPANESE: return min + " - " + max + " 件中 " + total + " 件";
}
}

View File

@ -10,7 +10,7 @@ const SCENES = {
Offline:{ Offline:{
load() { load() {
UI.nav([ UI.nav([
UI.button("Reconnect", () => { RECONNECT(); }), UI.button(LANG("reconnect"), () => { RECONNECT(); }),
], []); ], []);
return true; return true;
}, },
@ -28,12 +28,12 @@ const SCENES = {
let container = document.createElement("section"); let container = document.createElement("section");
let form = document.createElement("div"); let form = document.createElement("div");
form.appendChild(UI.table(null, [ form.appendChild(UI.table(null, [
[ UI.label("Handle", "handle"), UI.textbox("handle", "") ], [ UI.label(LANG("handle"), "handle"), UI.textbox("handle", "") ],
[ UI.label("Secret", "secret"), UI.password("secret") ], [ UI.label(LANG("secret"), "secret"), UI.password("secret") ],
[ UI.label("Invite Code", "code"), UI.password("code") ], [ UI.label(LANG("invitation"), "code"), UI.password("code") ],
])); ]));
let button = UI.button("Register", (event) => { let button = UI.button(LANG("register"), (event) => {
let handle = document.getElementById("handle"); let handle = document.getElementById("handle");
let secret = document.getElementById("secret"); let secret = document.getElementById("secret");
let code = document.getElementById("code"); let code = document.getElementById("code");
@ -123,11 +123,11 @@ const SCENES = {
let container = document.createElement("section"); let container = document.createElement("section");
let form = document.createElement("div"); let form = document.createElement("div");
form.appendChild(UI.table(null, [ form.appendChild(UI.table(null, [
[ UI.label("Handle", "handle"), UI.textbox("handle", "") ], [ UI.label(LANG("handle"), "handle"), UI.textbox("handle", "") ],
[ UI.label("Secret", "secret"), UI.password("secret") ], [ UI.label(LANG("secret"), "secret"), UI.password("secret") ],
])); ]));
let button = UI.button("Login", (event) => { let button = UI.button(LANG("login"), (event) => {
let handle = document.getElementById("handle"); let handle = document.getElementById("handle");
let secret = document.getElementById("secret"); let secret = document.getElementById("secret");
@ -198,10 +198,10 @@ const SCENES = {
UI.mainnav( UI.mainnav(
[ ], [ ],
[ [
UI.div([UI.text("0 - 0 of 0")]), UI.div([UI.text(LANG_PAGEOF(0, 0, 0))]),
UI.button("◀", null), UI.button("◀", null),
UI.button("▶", null), UI.button("▶", null),
UI.button("Refresh", null), UI.button(LANG("refresh"), null),
], ],
{ auth:true, session:true } { auth:true, session:true }
); );
@ -249,10 +249,10 @@ const SCENES = {
UI.mainnav( UI.mainnav(
[ ], [ ],
[ [
UI.div([UI.text("0 - 0 of 0")]), UI.div([UI.text(LANG_PAGEOF(0, 0, 0))]),
UI.button("◀", null), UI.button("◀", null),
UI.button("▶", null), UI.button("▶", null),
UI.button("Refresh", null), UI.button(LANG("refresh"), null),
], ],
{ auth:true, session:true } { auth:true, session:true }
); );
@ -354,10 +354,10 @@ const SCENES = {
UI.mainnav( UI.mainnav(
[ ], [ ],
[ [
UI.div([UI.text("0 - 0 of 0")]), UI.div([UI.text(LANG_PAGEOF(0, 0, 0))]),
UI.button("◀", null), UI.button("◀", null),
UI.button("▶", null), UI.button("▶", null),
UI.button("Refresh", null), UI.button(LANG("refresh"), null),
], ],
{ auth:true, session:true } { auth:true, session:true }
); );
@ -403,10 +403,10 @@ const SCENES = {
UI.mainnav( UI.mainnav(
[ ], [ ],
[ [
UI.div([UI.text("0 - 0 of 0")]), UI.div([UI.text(LANG_PAGEOF(0, 0, 0))]),
UI.button("◀", null), UI.button("◀", null),
UI.button("▶", null), UI.button("▶", null),
UI.button("Refresh", null), UI.button(LANG("refresh"), null),
], ],
{ auth:true } { auth:true }
); );
@ -503,15 +503,15 @@ const SCENES = {
load(data) { load(data) {
let buttons_bottom = [ ]; let buttons_bottom = [ ];
if(data.mode != INTERFACE.Mode.Review) { if(data.mode != INTERFACE.Mode.Review) {
let button_resign = UI.button("Resign", () => { INTERFACE.resign(); }); let button_resign = UI.button(LANG("resign"), () => { INTERFACE.resign(); });
button_resign.setAttribute("id", "button-resign"); button_resign.setAttribute("id", "button-resign");
buttons_bottom.push(button_resign); buttons_bottom.push(button_resign);
} }
buttons_bottom.push(UI.button("Back", () => { LOAD(SCENES.Browse) })); buttons_bottom.push(UI.button(LANG("back"), () => { LOAD(SCENES.Browse) }));
UI.nav([ UI.nav([
UI.button("Rotate", () => { INTERFACE.rotate(); }), UI.button(LANG("rotate"), () => { INTERFACE.rotate(); }),
UI.button("Mirror", () => { INTERFACE.mirror(); }), UI.button(LANG("mirror"), () => { INTERFACE.mirror(); }),
], buttons_bottom); ], buttons_bottom);
if(data.mode == INTERFACE.Mode.Review) { if(data.mode == INTERFACE.Mode.Review) {
@ -566,13 +566,13 @@ const SCENES = {
GamePractice:{ GamePractice:{
load(data) { load(data) {
let buttons_bottom = [ ]; let buttons_bottom = [ ];
buttons_bottom.push(UI.button("Reset", () => { INTERFACE.reset(); })); buttons_bottom.push(UI.button(LANG("reset"), () => { INTERFACE.reset(); }));
buttons_bottom.push(UI.button("Back", () => { LOAD(SCENES.Browse) })); buttons_bottom.push(UI.button(LANG("back"), () => { LOAD(SCENES.Browse) }));
UI.nav([ UI.nav([
UI.button("Rotate", () => { INTERFACE.rotate(); }), UI.button(LANG("rotate"), () => { INTERFACE.rotate(); }),
UI.button("Mirror", () => { INTERFACE.mirror(); }), UI.button(LANG("mirror"), () => { INTERFACE.mirror(); }),
UI.button("Auto", () => { INTERFACE.auto(); }), UI.button(LANG("auto"), () => { INTERFACE.auto(); }),
], buttons_bottom); ], buttons_bottom);
let canvas = document.createElement("canvas"); let canvas = document.createElement("canvas");
@ -589,7 +589,7 @@ const SCENES = {
}, },
}, },
Await:{ /*Await:{
load() { load() {
if(sessionStorage.getItem("auth") === null) return false; if(sessionStorage.getItem("auth") === null) return false;
UI.mainmenu("await"); UI.mainmenu("await");
@ -629,7 +629,7 @@ const SCENES = {
disconnect() { disconnect() {
LOAD(SCENES.Offline); LOAD(SCENES.Offline);
}, },
}, },*/
Challenge:{ Challenge:{
load() { load() {
@ -643,14 +643,14 @@ const SCENES = {
UI.mainmenu("browse"); UI.mainmenu("browse");
UI.mainnav( UI.mainnav(
[ [
UI.button("Users", () => { LOAD(SCENES.Challenge); }), UI.button(LANG("users"), () => { LOAD(SCENES.Challenge); }),
UI.button("Requests", () => { LOAD(SCENES.ChallengeList); }), UI.button(LANG("requests"), () => { LOAD(SCENES.ChallengeList); }),
], ],
[ [
UI.div([UI.text("0 - 0 of 0")]), UI.div([UI.text(LANG_PAGEOF(0, 0, 0))]),
UI.button("◀", null), UI.button("◀", null),
UI.button("▶", null), UI.button("▶", null),
UI.button("Refresh", null), UI.button(LANG("refresh"), null),
] ]
); );
@ -685,7 +685,7 @@ const SCENES = {
MESSAGE_CHALLENGE(this.handle); MESSAGE_CHALLENGE(this.handle);
}; };
callback = callback.bind({handle: data.users[r].handle}); callback = callback.bind({handle: data.users[r].handle});
buttons.push(UI.button("Challenge", callback)); buttons.push(UI.button(LANG("challenge"), callback));
rows.push([ rows.push([
UI.text(data.users[r].handle), UI.text(data.users[r].handle),
@ -694,7 +694,7 @@ const SCENES = {
} }
let tbody = UI.table_content( let tbody = UI.table_content(
[ "User", "" ], null,
rows, rows,
); );
@ -720,14 +720,14 @@ const SCENES = {
UI.mainmenu("browse"); UI.mainmenu("browse");
UI.mainnav( UI.mainnav(
[ [
UI.button("Users", () => { LOAD(SCENES.Challenge); }), UI.button(LANG("users"), () => { LOAD(SCENES.Challenge); }),
UI.button("Requests", () => { LOAD(SCENES.ChallengeList); }), UI.button(LANG("requests"), () => { LOAD(SCENES.ChallengeList); }),
], ],
[ [
UI.div([UI.text("0 - 0 of 0")]), UI.div([UI.text(LANG_PAGEOF(0, 0, 0))]),
UI.button("◀", null), UI.button("◀", null),
UI.button("▶", null), UI.button("▶", null),
UI.button("Refresh", null), UI.button(LANG("refresh"), null),
] ]
); );
@ -762,13 +762,13 @@ const SCENES = {
MESSAGE_CHALLENGE_ANSWER(this.handle, true); MESSAGE_CHALLENGE_ANSWER(this.handle, true);
}; };
callback_accept = callback_accept.bind({handle: data.challenges[r].handle}); callback_accept = callback_accept.bind({handle: data.challenges[r].handle});
buttons.push(UI.button("Accept", callback_accept)); buttons.push(UI.button(LANG("accept"), callback_accept));
let callback_reject = function() { let callback_decline = function() {
MESSAGE_CHALLENGE_ANSWER(this.handle, false); MESSAGE_CHALLENGE_ANSWER(this.handle, false);
}; };
callback_reject = callback_reject.bind({handle: data.challenges[r].handle}); callback_decline = callback_decline.bind({handle: data.challenges[r].handle});
buttons.push(UI.button("Reject", callback_reject)); buttons.push(UI.button(LANG("decline"), callback_decline));
rows.push([ rows.push([
UI.text(data.challenges[r].handle), UI.text(data.challenges[r].handle),
@ -777,7 +777,7 @@ const SCENES = {
} }
let tbody = UI.table_content( let tbody = UI.table_content(
[ "User", "" ], null,
rows, rows,
); );

View File

@ -105,13 +105,13 @@ const UI = {
if(sessionStorage.getItem("auth") === null) { if(sessionStorage.getItem("auth") === null) {
if(features.auth === true) { if(features.auth === true) {
left.appendChild(UI.button("Register", () => { LOAD(SCENES.Register); })); left.appendChild(UI.button(LANG("register"), () => { LOAD(SCENES.Register); }));
left.appendChild(UI.button("Log In", () => { LOAD(SCENES.Authenticate); })); left.appendChild(UI.button(LANG("login"), () => { LOAD(SCENES.Authenticate); }));
} }
} else { } else {
if(features.session === true) { if(features.session === true) {
//left.appendChild(UI.button("Await", () => { })); //left.appendChild(UI.button("Await", () => { }));
left.appendChild(UI.button("Challenge", () => { LOAD(SCENES.Challenge); })); left.appendChild(UI.button(LANG("challenge"), () => { LOAD(SCENES.Challenge); }));
} }
} }
@ -141,16 +141,16 @@ const UI = {
let top = [ ]; let top = [ ];
let bottom = [ ]; let bottom = [ ];
top.push(UI.button("Browse", () => { LOAD(SCENES.Browse); }, page == "browse")); top.push(UI.button(LANG("browse"), () => { LOAD(SCENES.Browse); }, page == "browse"));
if(sessionStorage.getItem("auth") !== null) { if(sessionStorage.getItem("auth") !== null) {
top.push(UI.button("Continue", () => { LOAD(SCENES.Continue); }, page == "continue")); top.push(UI.button(LANG("resume"), () => { LOAD(SCENES.Continue); }, page == "continue"));
//top.push(UI.button("Join", () => { LOAD(SCENES.Join); }, page == "join")); //top.push(UI.button("Join", () => { LOAD(SCENES.Join); }, page == "join"));
} }
top.push(UI.button("Live", () => { LOAD(SCENES.Live); }, page == "live")); top.push(UI.button(LANG("live"), () => { LOAD(SCENES.Live); }, page == "live"));
top.push(UI.button("History", () => { LOAD(SCENES.History); }, page == "history")); top.push(UI.button(LANG("history"), () => { LOAD(SCENES.History); }, page == "history"));
top.push(UI.button("Practice", () => { LOAD(SCENES.GamePractice); }, page == "practice")); top.push(UI.button(LANG("practice"), () => { LOAD(SCENES.GamePractice); }, page == "practice"));
top.push(UI.button("Guide", () => { LOAD(SCENES.Guide); }, page == "guide")); top.push(UI.button(LANG("guide"), () => { LOAD(SCENES.Guide); }, page == "guide"));
top.push(UI.button("About", () => { LOAD(SCENES.About); }, page == "about")); top.push(UI.button(LANG("about"), () => { LOAD(SCENES.About); }, page == "about"));
if(sessionStorage.getItem("auth") !== null) { if(sessionStorage.getItem("auth") !== null) {
bottom.push(UI.button("Logout", () => { bottom.push(UI.button("Logout", () => {
@ -190,26 +190,19 @@ const UI = {
spectate_callback = spectate_callback.bind({token: records[r].token}); spectate_callback = spectate_callback.bind({token: records[r].token});
if(records[r].is_player) { if(records[r].is_player) {
let button_resume = UI.button("Resume", join_callback); let button_resume = UI.button(LANG("resume"), join_callback);
if(records[r].is_turn) { if(records[r].is_turn) {
console.log("HERE");
button_resume.setAttribute("class", "highlight"); button_resume.setAttribute("class", "highlight");
} }
buttons.push(button_resume); buttons.push(button_resume);
buttons.push(UI.button("Review", spectate_callback)); buttons.push(UI.button(LANG("review"), spectate_callback));
} else { } else {
if(sessionStorage.getItem("auth") !== null && (records[r].dawn == "" || records[r].dusk == "")) { buttons.push(UI.button(LANG("view"), spectate_callback));
buttons.push(UI.button("Join", join_callback));
}
buttons.push(UI.button("View", spectate_callback));
} }
let dawn = UI.text(records[r].dawn); let dawn = UI.text(records[r].dawn);
if(records[r].dawn == "") { dawn = UI.span([UI.text("Vacant")], "text-system"); }
let dusk = UI.text(records[r].dusk); let dusk = UI.text(records[r].dusk);
if(records[r].dusk == "") { dusk = UI.span([UI.text("Vacant")], "text-system"); }
rows.push([ rows.push([
dawn, dawn,
@ -221,7 +214,7 @@ const UI = {
} }
let tbody = UI.table_content( let tbody = UI.table_content(
[ "Dawn", "Dusk", "Turn", "Spectators", "" ], [ LANG("dawn"), LANG("dusk"), LANG("turn"), LANG("viewers"), "" ],
rows, rows,
); );
@ -279,13 +272,10 @@ const UI = {
}; };
view_callback = view_callback.bind({token: records[r].token}); view_callback = view_callback.bind({token: records[r].token});
buttons.push(UI.button("View", view_callback)); buttons.push(UI.button(LANG("review"), view_callback));
let dawn = UI.text(records[r].dawn); let dawn = UI.text(records[r].dawn);
if(records[r].dawn == "") { dawn = UI.span([UI.text("Vacant")], "text-system"); }
let dusk = UI.text(records[r].dusk); let dusk = UI.text(records[r].dusk);
if(records[r].dusk == "") { dusk = UI.span([UI.text("Vacant")], "text-system"); }
rows.push([ rows.push([
dawn, dawn,
@ -296,7 +286,7 @@ const UI = {
} }
let tbody = UI.table_content( let tbody = UI.table_content(
[ "Dawn", "Dusk", "Turns", "" ], [ LANG("dawn"), LANG("dusk"), LANG("turns"), "" ],
rows, rows,
); );