Commit 8e4daaf7 authored by BBeretta's avatar BBeretta

feat/language-translation (small updates, card img language, modals)

parent c0b1d41c
Pipeline #27739 failed with stages
in 8 minutes and 22 seconds
...@@ -7,6 +7,7 @@ import { proxy, useSnapshot } from "valtio"; ...@@ -7,6 +7,7 @@ import { proxy, useSnapshot } from "valtio";
import { sendSelectPositionResponse, ygopro } from "@/api"; import { sendSelectPositionResponse, ygopro } from "@/api";
import { NeosModal } from "../NeosModal"; import { NeosModal } from "../NeosModal";
import { useTranslation } from "react-i18next";
interface PositionModalProps { interface PositionModalProps {
isOpen: boolean; isOpen: boolean;
...@@ -16,15 +17,19 @@ const defaultProps = { isOpen: false, positions: [] }; ...@@ -16,15 +17,19 @@ const defaultProps = { isOpen: false, positions: [] };
const localStore = proxy<PositionModalProps>(defaultProps); const localStore = proxy<PositionModalProps>(defaultProps);
const language = localStorage.getItem('language');
const title = language != 'cn' ? 'Please select a position' : '请选择表示形式';
export const PositionModal = () => { export const PositionModal = () => {
const { isOpen, positions } = useSnapshot(localStore); const { isOpen, positions } = useSnapshot(localStore);
const [selected, setSelected] = useState<ygopro.CardPosition | undefined>( const [selected, setSelected] = useState<ygopro.CardPosition | undefined>(
undefined, undefined,
); );
return ( return (
<NeosModal <NeosModal
title="请选择表示形式" title={title}
open={isOpen} open={isOpen}
footer={ footer={
<Button <Button
...@@ -51,7 +56,7 @@ export const PositionModal = () => { ...@@ -51,7 +56,7 @@ export const PositionModal = () => {
{positions.map((position, idx) => ( {positions.map((position, idx) => (
<CheckCard <CheckCard
key={idx} key={idx}
title={cardPositionToChinese(position)} title={cardPosition(position)}
value={position} value={position}
/> />
))} ))}
...@@ -60,20 +65,24 @@ export const PositionModal = () => { ...@@ -60,20 +65,24 @@ export const PositionModal = () => {
); );
}; };
function cardPositionToChinese(position: ygopro.CardPosition): string { function cardPosition(position: ygopro.CardPosition): string {
const faceUpAtk = language != 'cn' ? 'Face-Up Attack' : "正面攻击形式";
const faceUpDef = language != 'cn' ? 'Face-Up Defense' : "正面防守形式";
const faceDownAtk = language != 'cn' ? 'Face-Down Attack' : "背面攻击形式";
const faceDownDef = language != 'cn' ? 'Face-Down Defense' : "背面防守形式";
switch (position) { switch (position) {
// TODO: i18n
case ygopro.CardPosition.FACEUP_ATTACK: { case ygopro.CardPosition.FACEUP_ATTACK: {
return "正面攻击形式"; return faceUpAtk;
} }
case ygopro.CardPosition.FACEUP_DEFENSE: { case ygopro.CardPosition.FACEUP_DEFENSE: {
return "正面防守形式"; return faceUpDef;
} }
case ygopro.CardPosition.FACEDOWN_ATTACK: { case ygopro.CardPosition.FACEDOWN_ATTACK: {
return "背面攻击形式"; return faceDownAtk;
} }
case ygopro.CardPosition.FACEDOWN_DEFENSE: { case ygopro.CardPosition.FACEDOWN_DEFENSE: {
return "背面防守形式"; return faceDownDef;
} }
default: { default: {
return "[?]"; return "[?]";
......
...@@ -13,6 +13,7 @@ import { groupBy } from "../../utils"; ...@@ -13,6 +13,7 @@ import { groupBy } from "../../utils";
import { showCardModal } from "../CardModal"; import { showCardModal } from "../CardModal";
import { NeosModal } from "../NeosModal"; import { NeosModal } from "../NeosModal";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import { useTranslation } from "react-i18next";
export interface SelectCardsModalProps { export interface SelectCardsModalProps {
isOpen: boolean; isOpen: boolean;
...@@ -57,6 +58,8 @@ export const SelectCardsModal: React.FC<SelectCardsModalProps> = ({ ...@@ -57,6 +58,8 @@ export const SelectCardsModal: React.FC<SelectCardsModalProps> = ({
const minMaxText = min === max ? min : `${min}-${max}`; const minMaxText = min === max ? min : `${min}-${max}`;
const { t: i18n } = useTranslation("SelectCardModal");
useEffect(() => { useEffect(() => {
const initial: [ygopro.CardZone, Option[]][] = grouped.map(([zone, _]) => [ const initial: [ygopro.CardZone, Option[]][] = grouped.map(([zone, _]) => [
zone, zone,
...@@ -107,8 +110,8 @@ export const SelectCardsModal: React.FC<SelectCardsModalProps> = ({ ...@@ -107,8 +110,8 @@ export const SelectCardsModal: React.FC<SelectCardsModalProps> = ({
<> <>
<span>{preHintMsg}</span> <span>{preHintMsg}</span>
<span>{selectHintMsg}</span> <span>{selectHintMsg}</span>
<span>(请选择 {minMaxText} 张卡)</span> <span>({i18n("PleaseSelect")} {minMaxText} {i18n("Cards")})</span>
<span>{single ? "每次选择一张" : ""}</span> <span>{single ? i18n("SelectOneCardAtTime") : ""}</span>
</> </>
} // TODO: 这里可以再细化一些 } // TODO: 这里可以再细化一些
width={"38.25rem"} width={"38.25rem"}
......
...@@ -38,6 +38,19 @@ import { useTranslation } from "react-i18next"; ...@@ -38,6 +38,19 @@ import { useTranslation } from "react-i18next";
const { useToken } = theme; const { useToken } = theme;
const FINISH_CANCEL_RESPONSE = -1; const FINISH_CANCEL_RESPONSE = -1;
const language = localStorage.getItem('language');
const drawPhase = language != 'cn' ? 'Draw' : '抽卡阶段';
const standbyPhase = language != 'cn' ? 'Standhy Phase' : '准备阶段';
const mainPhase1 = language != 'cn' ? 'Main Phase 1' : '主要阶段 1';
const battlePhase = language != 'cn' ? 'Battle Phase' : '战斗阶段';
const battleStart = language != 'cn' ? 'Battle Start' : '战斗开始';
const battleStep = language != 'cn' ? 'Battle Step' : '战斗步骤';
const damage = language != 'cn' ? 'Damage Step' : '伤害步骤';
const damageCalc = language != 'cn' ? 'Damage Step (Damage Calculation)' : '伤害步骤(伤害计算)';
const mainPhase2 = language != 'cn' ? 'Main Phase 2' : '主要阶段 2';
const endPhase = language != 'cn' ? 'End Phase' : '结束阶段';
const unknown = language != 'cn' ? 'Unknown' : '未知阶段';
// PhaseType, 中文, response, 是否显示,是否禁用 // PhaseType, 中文, response, 是否显示,是否禁用
const initialPhaseBind: [ const initialPhaseBind: [
...@@ -47,17 +60,17 @@ const initialPhaseBind: [ ...@@ -47,17 +60,17 @@ const initialPhaseBind: [
show: boolean, show: boolean,
disabled: boolean, disabled: boolean,
][] = [ ][] = [
[PhaseType.DRAW, "抽卡阶段", -1, true, true], [PhaseType.DRAW, drawPhase, -1, true, true],
[PhaseType.STANDBY, "准备阶段", -1, true, true], [PhaseType.STANDBY, standbyPhase, -1, true, true],
[PhaseType.MAIN1, "主要阶段 1", -1, true, true], [PhaseType.MAIN1, mainPhase1, -1, true, true],
[PhaseType.BATTLE, "战斗阶段", 6, true, false], [PhaseType.BATTLE, battlePhase, 6, true, false],
[PhaseType.BATTLE_START, "战斗开始", 3, false, true], [PhaseType.BATTLE_START, battleStart, 3, false, true],
[PhaseType.BATTLE_STEP, "战斗步骤", 3, false, true], [PhaseType.BATTLE_STEP, battleStep, 3, false, true],
[PhaseType.DAMAGE, "伤害步骤", 3, false, true], [PhaseType.DAMAGE, damage, 3, false, true],
[PhaseType.DAMAGE_GAL, "伤害步骤(伤害计算)", 3, false, true], [PhaseType.DAMAGE_GAL, damageCalc, 3, false, true],
[PhaseType.MAIN2, "主要阶段 2", 2, true, false], [PhaseType.MAIN2, mainPhase2, 2, true, false],
[PhaseType.END, "结束阶段", 7, true, false], [PhaseType.END, endPhase, 7, true, false],
[PhaseType.UNKNOWN, "未知阶段", -1, false, true], [PhaseType.UNKNOWN, unknown, -1, false, true],
]; ];
export const Menu = () => { export const Menu = () => {
...@@ -123,10 +136,14 @@ export const Menu = () => { ...@@ -123,10 +136,14 @@ export const Menu = () => {
setPhaseSwitchItems(newPhaseSwitchItems); setPhaseSwitchItems(newPhaseSwitchItems);
}, [phaseBind]); }, [phaseBind]);
const allChain = language != 'cn' ? 'All Chain' : '';
const ignoreChain = language != 'cn' ? 'Ignore Chain' : '';
const smartChain = language != 'cn' ? 'Smart Chain' : '';
const chainSettingTexts = [ const chainSettingTexts = [
[ChainSetting.CHAIN_ALL, "全部连锁"], [ChainSetting.CHAIN_ALL, allChain],
[ChainSetting.CHAIN_IGNORE, "忽略连锁"], [ChainSetting.CHAIN_IGNORE, ignoreChain],
[ChainSetting.CHAIN_SMART, "智能连锁"], [ChainSetting.CHAIN_SMART, smartChain],
] as const; ] as const;
const chainSettingItems: MenuProps["items"] = chainSettingTexts.map( const chainSettingItems: MenuProps["items"] = chainSettingTexts.map(
([key, text]) => ({ ([key, text]) => ({
...@@ -155,7 +172,7 @@ export const Menu = () => { ...@@ -155,7 +172,7 @@ export const Menu = () => {
<div className={styles["menu-container"]}> <div className={styles["menu-container"]}>
<SelectManager /> <SelectManager />
<DropdownWithTitle <DropdownWithTitle
title="请选择要进入的阶段" title={i18n("SelectPhase")}
menu={{ items: phaseSwitchItems }} menu={{ items: phaseSwitchItems }}
disabled={globalDisable} disabled={globalDisable}
> >
...@@ -177,7 +194,7 @@ export const Menu = () => { ...@@ -177,7 +194,7 @@ export const Menu = () => {
type="text" type="text"
></Button> ></Button>
</DropdownWithTitle> </DropdownWithTitle>
<Tooltip title="聊天室"> <Tooltip title={i18n("ChatRoom")}>
<Button <Button
icon={<MessageFilled />} icon={<MessageFilled />}
onClick={openChatBox} onClick={openChatBox}
...@@ -247,6 +264,7 @@ const ChainIcon: React.FC<{ chainSetting: ChainSetting }> = ({ ...@@ -247,6 +264,7 @@ const ChainIcon: React.FC<{ chainSetting: ChainSetting }> = ({
}; };
const SelectManager: React.FC = () => { const SelectManager: React.FC = () => {
const { t: i18n } = useTranslation("Menu");
const { finishable, cancelable } = useSnapshot(matStore.selectUnselectInfo); const { finishable, cancelable } = useSnapshot(matStore.selectUnselectInfo);
const onFinishOrCancel = () => { const onFinishOrCancel = () => {
sendSelectSingleResponse(FINISH_CANCEL_RESPONSE); sendSelectSingleResponse(FINISH_CANCEL_RESPONSE);
...@@ -259,7 +277,7 @@ const SelectManager: React.FC = () => { ...@@ -259,7 +277,7 @@ const SelectManager: React.FC = () => {
disabled={!cancelable && !finishable} disabled={!cancelable && !finishable}
onClick={onFinishOrCancel} onClick={onFinishOrCancel}
> >
{finishable ? "完成选择" : "取消选择"} {finishable ? i18n("SelectionComplete") : i18n("Deselect")}
</Button> </Button>
</div> </div>
); );
......
...@@ -6,15 +6,15 @@ import CardPosition = ygopro.CardPosition; ...@@ -6,15 +6,15 @@ import CardPosition = ygopro.CardPosition;
const language = localStorage.getItem('language'); const language = localStorage.getItem('language');
const sSet = language === 'en' ? 'Set' : '后场放置';
const summon = language === 'en' ? 'Normal Summon' : '普通召唤';
const spSummon = language === 'en' ? 'Special Summon' : '特殊召唤';
const posChange = language === 'en' ? 'Change Position' : '改变表示形式';
const mSet = language === 'en' ? 'Set' : '前场放置';
const activate = language === 'en' ? 'Activate' : '发动效果';
const attack = language === 'en' ? 'Attack' : '攻击';
export function interactTypeToString(t: InteractType): string { export function interactTypeToString(t: InteractType): string {
const sSet = language != 'cn' ? 'Set' : '后场放置';
const summon = language != 'cn' ? 'Normal Summon' : '普通召唤';
const spSummon = language != 'cn' ? 'Special Summon' : '特殊召唤';
const posChange = language != 'cn' ? 'Change Position' : '改变表示形式';
const mSet = language != 'cn' ? 'Set' : '前场放置';
const activate = language != 'cn' ? 'Activate' : '发动效果';
const attack = language != 'cn' ? 'Attack' : '攻击';
switch (t) { switch (t) {
case InteractType.SUMMON: case InteractType.SUMMON:
return summon; return summon;
......
...@@ -177,6 +177,15 @@ ...@@ -177,6 +177,15 @@
"Menu": { "Menu": {
"DoYouSurrunder": "是否投降?", "DoYouSurrunder": "是否投降?",
"Cancel": "取消", "Cancel": "取消",
"Confirm": "确定" "Confirm": "确定",
"SelectPhase": "请选择要进入的阶段",
"Deselect": "取消选择",
"SelectionComplete": "完成选择",
"ChatRoom": "聊天室"
},
"SelectCardModal": {
"PleaseSelect": "请选择",
"Cards": "张卡",
"SelectOneCardAtTime": "每次选择一张"
} }
} }
\ No newline at end of file
...@@ -177,6 +177,15 @@ ...@@ -177,6 +177,15 @@
"Menu": { "Menu": {
"DoYouSurrunder": "Do you surrender?", "DoYouSurrunder": "Do you surrender?",
"Cancel": "Cancel", "Cancel": "Cancel",
"Confirm": "Confirm" "Confirm": "Confirm",
"SelectPhase": "Please select the phase",
"Deselect": "Deselect",
"SelectionComplete": "Selection complete",
"ChatRoom": "Chat Room"
},
"SelectCardModal": {
"PleaseSelect": "Please select",
"Cards": "Cards",
"SelectOneCardAtTime": "Select one card at a time"
} }
} }
\ No newline at end of file
...@@ -30,6 +30,7 @@ const resources = { ...@@ -30,6 +30,7 @@ const resources = {
ReplayModal: translationChinese.ReplayModal, ReplayModal: translationChinese.ReplayModal,
Popover: translationChinese.Popover, Popover: translationChinese.Popover,
Menu: translationChinese.Menu, Menu: translationChinese.Menu,
SelectCardModal: translationChinese.SelectCardModal,
}, },
en: { en: {
Header: translationEnglish.Header, Header: translationEnglish.Header,
...@@ -47,6 +48,7 @@ const resources = { ...@@ -47,6 +48,7 @@ const resources = {
ReplayModal: translationEnglish.ReplayModal, ReplayModal: translationEnglish.ReplayModal,
Popover: translationEnglish.Popover, Popover: translationEnglish.Popover,
Menu: translationEnglish.Menu, Menu: translationEnglish.Menu,
SelectCardModal: translationEnglish.SelectCardModal,
}, },
es: { es: {
Header: translationSpanish.Header, Header: translationSpanish.Header,
......
...@@ -66,6 +66,18 @@ export function getCardImgUrl(code: number, back = false) { ...@@ -66,6 +66,18 @@ export function getCardImgUrl(code: number, back = false) {
if (isSuperReleaseCard(code)) { if (isSuperReleaseCard(code)) {
return `${NeosConfig.preReleaseImgUrl}/${code}.jpg`; return `${NeosConfig.preReleaseImgUrl}/${code}.jpg`;
} else { } else {
const language = localStorage.getItem("language");
if (
language === "en" ||
language === "br" ||
language === "pt" ||
language === "fr"
) {
NeosConfig.releaseImgUrl = NeosConfig.releaseImgUrl.replace(
"zh-CN",
"en-US",
);
}
return `${NeosConfig.releaseImgUrl}/${code}.jpg`; return `${NeosConfig.releaseImgUrl}/${code}.jpg`;
} }
} }
...@@ -37,7 +37,6 @@ import { Chat } from "./Chat"; ...@@ -37,7 +37,6 @@ import { Chat } from "./Chat";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import { Mora, MoraPopover, Tp, TpPopover } from "./Popover"; import { Mora, MoraPopover, Tp, TpPopover } from "./Popover";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { I18NSelector } from "../I18N";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
...@@ -262,7 +261,6 @@ const Controller: React.FC<{ onDeckChange: (deckName: string) => void }> = ({ ...@@ -262,7 +261,6 @@ const Controller: React.FC<{ onDeckChange: (deckName: string) => void }> = ({
const snapRoom = useSnapshot(roomStore); const snapRoom = useSnapshot(roomStore);
return ( return (
<Space> <Space>
<I18NSelector />
<Select <Select
title={ i18n("Deck") } title={ i18n("Deck") }
showSearch showSearch
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment