latest dev + i18n
This commit is contained in:
parent
e3b58a0d56
commit
7e987ad470
@ -1,6 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
||||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
|
import { i18nJson } from "../../i18n/locales";
|
||||||
|
|
||||||
|
|
||||||
function onClick(callback: () => void) {
|
function onClick(callback: () => void) {
|
||||||
callback();
|
callback();
|
||||||
@ -8,20 +10,7 @@
|
|||||||
|
|
||||||
function i18n(text: string | number | boolean | undefined): string {
|
function i18n(text: string | number | boolean | undefined): string {
|
||||||
if (typeof text === "string") {
|
if (typeof text === "string") {
|
||||||
if (text.trim().startsWith("{")) {
|
return i18nJson(text);
|
||||||
try {
|
|
||||||
let textObject = JSON.parse(text);
|
|
||||||
if (textObject[$locale]) {
|
|
||||||
return textObject[$locale];
|
|
||||||
} else if (Object.keys(textObject).length > 0) {
|
|
||||||
// fallback to first value
|
|
||||||
return textObject[Object.keys(textObject)[0]];
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -34,5 +34,5 @@
|
|||||||
<SoundMeterWidget {stream} />
|
<SoundMeterWidget {stream} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="is-silent" class:hide={isSilent}>{$LL.camera.my.silentZone()}</div>
|
<div class="nes-container is-dark is-silent" class:hide={isSilent}>{$LL.camera.my.silentZone()}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,6 +17,9 @@ import { isRegisterData } from "../Messages/JsonMessages/RegisterData";
|
|||||||
import { isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
|
import { isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
|
||||||
import { limitMapStore } from "../Stores/GameStore";
|
import { limitMapStore } from "../Stores/GameStore";
|
||||||
import { showLimitRoomModalStore } from "../Stores/ModalStore";
|
import { showLimitRoomModalStore } from "../Stores/ModalStore";
|
||||||
|
import { locales } from "../i18n/i18n-util";
|
||||||
|
import type { Locales } from "../i18n/i18n-types";
|
||||||
|
import { setCurrentLocale } from "../i18n/locales";
|
||||||
|
|
||||||
class ConnectionManager {
|
class ConnectionManager {
|
||||||
private localUser!: LocalUser;
|
private localUser!: LocalUser;
|
||||||
@ -343,9 +346,12 @@ class ConnectionManager {
|
|||||||
throw new Error("No Auth code provided");
|
throw new Error("No Auth code provided");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { authToken, userUuid, textures, email, username } = await Axios.get(`${PUSHER_URL}/login-callback`, {
|
const { authToken, userUuid, textures, email, username, locale } = await Axios.get(
|
||||||
params: { code, nonce, token, playUri: this.currentRoom?.key },
|
`${PUSHER_URL}/login-callback`,
|
||||||
}).then((res) => {
|
{
|
||||||
|
params: { code, nonce, token, playUri: this.currentRoom?.key },
|
||||||
|
}
|
||||||
|
).then((res) => {
|
||||||
return res.data;
|
return res.data;
|
||||||
});
|
});
|
||||||
localUserStore.setAuthToken(authToken);
|
localUserStore.setAuthToken(authToken);
|
||||||
@ -355,6 +361,25 @@ class ConnectionManager {
|
|||||||
if (username) {
|
if (username) {
|
||||||
gameManager.setPlayerName(username);
|
gameManager.setPlayerName(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (locale) {
|
||||||
|
try {
|
||||||
|
if (locales.indexOf(locale) == -1) {
|
||||||
|
locales.forEach((l) => {
|
||||||
|
if (l.startsWith(locale.split("-")[0])) {
|
||||||
|
setCurrentLocale(l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setCurrentLocale(locale as Locales);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("Could not set locale", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("no locale", locale);
|
||||||
|
}
|
||||||
//user connected, set connected store for menu at true
|
//user connected, set connected store for menu at true
|
||||||
userIsConnected.set(true);
|
userIsConnected.set(true);
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,7 @@ import { followUsersColorStore } from "../../Stores/FollowStore";
|
|||||||
import Camera = Phaser.Cameras.Scene2D.Camera;
|
import Camera = Phaser.Cameras.Scene2D.Camera;
|
||||||
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
|
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
|
||||||
import { locale } from "../../i18n/i18n-svelte";
|
import { locale } from "../../i18n/i18n-svelte";
|
||||||
|
import { i18nJson } from "../../i18n/locales";
|
||||||
|
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
@ -1066,7 +1067,7 @@ export class GameScene extends DirtyScene {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const escapedMessage = HtmlUtils.sanitize(openPopupEvent.message);
|
const escapedMessage = HtmlUtils.sanitize(i18nJson(openPopupEvent.message));
|
||||||
let html = `<div id="container" hidden><div class="nes-container with-title is-centered">`;
|
let html = `<div id="container" hidden><div class="nes-container with-title is-centered">`;
|
||||||
html += escapedMessage;
|
html += escapedMessage;
|
||||||
if (openPopupEvent.input) {
|
if (openPopupEvent.input) {
|
||||||
@ -1080,7 +1081,9 @@ export class GameScene extends DirtyScene {
|
|||||||
for (const button of openPopupEvent.buttons) {
|
for (const button of openPopupEvent.buttons) {
|
||||||
html += `<button type="button" class="nes-btn is-${HtmlUtils.escapeHtml(
|
html += `<button type="button" class="nes-btn is-${HtmlUtils.escapeHtml(
|
||||||
button.className ?? ""
|
button.className ?? ""
|
||||||
)}" id="popup-${openPopupEvent.popupId}-${id}">${HtmlUtils.escapeHtml(button.label)}</button>`;
|
)}" id="popup-${openPopupEvent.popupId}-${id}">${HtmlUtils.escapeHtml(
|
||||||
|
i18nJson(button.label)
|
||||||
|
)}</button>`;
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
html += "</div>";
|
html += "</div>";
|
||||||
|
@ -28,7 +28,7 @@ const de_DE: Translation = {
|
|||||||
menu,
|
menu,
|
||||||
report,
|
report,
|
||||||
warning,
|
warning,
|
||||||
emiji,
|
emoji,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default de_DE;
|
export default de_DE;
|
||||||
|
@ -114,6 +114,7 @@ const menu: NonNullable<Translation["menu"]> = {
|
|||||||
},
|
},
|
||||||
sub: {
|
sub: {
|
||||||
profile: "Profil",
|
profile: "Profil",
|
||||||
|
worlds: "Welt",
|
||||||
settings: "Einstellungen",
|
settings: "Einstellungen",
|
||||||
invite: "Einladung",
|
invite: "Einladung",
|
||||||
credit: "Über die Karte",
|
credit: "Über die Karte",
|
||||||
|
@ -113,6 +113,7 @@ const menu: BaseTranslation = {
|
|||||||
},
|
},
|
||||||
sub: {
|
sub: {
|
||||||
profile: "Profile",
|
profile: "Profile",
|
||||||
|
worlds: "Worlds",
|
||||||
settings: "Settings",
|
settings: "Settings",
|
||||||
invite: "Invite",
|
invite: "Invite",
|
||||||
credit: "Credit",
|
credit: "Credit",
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { detectLocale, navigatorDetector, initLocalStorageDetector } from "typesafe-i18n/detectors";
|
import { detectLocale, navigatorDetector, initLocalStorageDetector } from "typesafe-i18n/detectors";
|
||||||
import { FALLBACK_LOCALE } from "../Enum/EnvironmentVariable";
|
import { FALLBACK_LOCALE } from "../Enum/EnvironmentVariable";
|
||||||
import { initI18n, setLocale } from "./i18n-svelte";
|
import { initI18n, setLocale, locale } from "./i18n-svelte";
|
||||||
import type { Locales, Translation } from "./i18n-types";
|
import type { Locales, Translation } from "./i18n-types";
|
||||||
import { baseLocale, getTranslationForLocale, locales } from "./i18n-util";
|
import { baseLocale, getTranslationForLocale, locales } from "./i18n-util";
|
||||||
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
const fallbackLocale = FALLBACK_LOCALE || baseLocale;
|
const fallbackLocale = FALLBACK_LOCALE || baseLocale;
|
||||||
const localStorageProperty = "language";
|
const localStorageProperty = "language";
|
||||||
@ -50,3 +51,20 @@ function getDisplayableLocales() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const displayableLocales = getDisplayableLocales();
|
export const displayableLocales = getDisplayableLocales();
|
||||||
|
|
||||||
|
export const i18nJson = (text: string): string => {
|
||||||
|
if (text.trim().startsWith("{")) {
|
||||||
|
try {
|
||||||
|
const textObject = JSON.parse(text);
|
||||||
|
if (textObject[get(locale)]) {
|
||||||
|
return textObject[get(locale)];
|
||||||
|
} else if (Object.keys(textObject).length > 0) {
|
||||||
|
// fallback to first value
|
||||||
|
return textObject[Object.keys(textObject)[0]];
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
};
|
||||||
|
@ -1047,15 +1047,12 @@ div.action.danger p.action-body{
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.is-silent {
|
div.is-silent {
|
||||||
position: absolute;
|
position: absolute !important;
|
||||||
bottom: 40px;
|
bottom: 40px;
|
||||||
border-radius: 15px 15px 15px 15px;
|
|
||||||
max-height: 20%;
|
max-height: 20%;
|
||||||
transition: right 350ms;
|
transition: right 350ms;
|
||||||
right: -300px;
|
right: -1000px;
|
||||||
background-color: black;
|
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
color: white;
|
|
||||||
padding: 30px 20px;
|
padding: 30px 20px;
|
||||||
}
|
}
|
||||||
div.is-silent.hide {
|
div.is-silent.hide {
|
||||||
|
@ -91,7 +91,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
const resCheckTokenAuth = await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
const resCheckTokenAuth = await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
||||||
res.writeStatus("200");
|
res.writeStatus("200");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
return res.end(JSON.stringify({ ...resCheckTokenAuth, ...resUserData, username: authTokenData.username, authToken: token }));
|
return res.end(JSON.stringify({ ...resCheckTokenAuth, ...resUserData, username: authTokenData.username, locale: authTokenData.locale, authToken: token }));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.info("User was not connected", err);
|
console.info("User was not connected", err);
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
if (!sub) {
|
if (!sub) {
|
||||||
throw new Error("No sub in the response");
|
throw new Error("No sub in the response");
|
||||||
}
|
}
|
||||||
const authToken = jwtTokenManager.createAuthToken(sub, userInfo?.access_token, userInfo?.username);
|
const authToken = jwtTokenManager.createAuthToken(sub, userInfo?.access_token, userInfo?.username, userInfo.locale);
|
||||||
|
|
||||||
//Get user data from Admin Back Office
|
//Get user data from Admin Back Office
|
||||||
//This is very important to create User Local in LocalStorage in WorkAdventure
|
//This is very important to create User Local in LocalStorage in WorkAdventure
|
||||||
@ -121,7 +121,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
|
|
||||||
res.writeStatus("200");
|
res.writeStatus("200");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
return res.end(JSON.stringify({ ...data, authToken, username: userInfo.username, userUuid : sub }));
|
return res.end(JSON.stringify({ ...data, authToken, username: userInfo.username, locale: userInfo.locale, userUuid : sub }));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("openIDCallback => ERROR", e);
|
console.error("openIDCallback => ERROR", e);
|
||||||
return this.errorToResponse(e, res);
|
return this.errorToResponse(e, res);
|
||||||
|
@ -6,6 +6,7 @@ export interface AuthTokenData {
|
|||||||
identifier: string; //will be a sub (id) if logged in or an uuid if anonymous
|
identifier: string; //will be a sub (id) if logged in or an uuid if anonymous
|
||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
|
locale?: string;
|
||||||
}
|
}
|
||||||
export interface AdminSocketTokenData {
|
export interface AdminSocketTokenData {
|
||||||
authorizedRoomIds: string[]; //the list of rooms the client is authorized to read from.
|
authorizedRoomIds: string[]; //the list of rooms the client is authorized to read from.
|
||||||
@ -17,8 +18,8 @@ class JWTTokenManager {
|
|||||||
return Jwt.verify(token, ADMIN_SOCKETS_TOKEN) as AdminSocketTokenData;
|
return Jwt.verify(token, ADMIN_SOCKETS_TOKEN) as AdminSocketTokenData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createAuthToken(identifier: string, accessToken?: string, username?: string) {
|
public createAuthToken(identifier: string, accessToken?: string, username?: string, locale?: string) {
|
||||||
return Jwt.sign({ identifier, accessToken, username }, SECRET_KEY, { expiresIn: "30d" });
|
return Jwt.sign({ identifier, accessToken, username, locale }, SECRET_KEY, { expiresIn: "30d" });
|
||||||
}
|
}
|
||||||
|
|
||||||
public verifyJWTToken(token: string, ignoreExpiration: boolean = false): AuthTokenData {
|
public verifyJWTToken(token: string, ignoreExpiration: boolean = false): AuthTokenData {
|
||||||
|
@ -26,7 +26,7 @@ class OpenIDClient {
|
|||||||
public authorizationUrl(state: string, nonce: string, playUri?: string, redirect?: string) {
|
public authorizationUrl(state: string, nonce: string, playUri?: string, redirect?: string) {
|
||||||
return this.initClient().then((client) => {
|
return this.initClient().then((client) => {
|
||||||
return client.authorizationUrl({
|
return client.authorizationUrl({
|
||||||
scope: "openid email",
|
scope: "openid profile email",
|
||||||
prompt: "login",
|
prompt: "login",
|
||||||
state: state,
|
state: state,
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
@ -36,7 +36,7 @@ class OpenIDClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string; username: string }> {
|
public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string; username: string, locale: string }> {
|
||||||
return this.initClient().then((client) => {
|
return this.initClient().then((client) => {
|
||||||
return client.callback(OPID_CLIENT_REDIRECT_URL, { code }, { nonce }).then((tokenSet) => {
|
return client.callback(OPID_CLIENT_REDIRECT_URL, { code }, { nonce }).then((tokenSet) => {
|
||||||
return client.userinfo(tokenSet).then((res) => {
|
return client.userinfo(tokenSet).then((res) => {
|
||||||
@ -46,6 +46,7 @@ class OpenIDClient {
|
|||||||
sub: res.sub,
|
sub: res.sub,
|
||||||
access_token: tokenSet.access_token as string,
|
access_token: tokenSet.access_token as string,
|
||||||
username: (res.preferred_username || res.username || res.nickname || res.name || res.email) as string,
|
username: (res.preferred_username || res.username || res.nickname || res.name || res.email) as string,
|
||||||
|
locale: res.locale as string,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user