Add localization for header menus/some modals
This commit is contained in:
parent
5ea57f0e07
commit
b91d84028f
7 changed files with 170 additions and 26 deletions
|
|
@ -1,21 +1,24 @@
|
|||
import React from 'react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import * as Dialog from '@radix-ui/react-dialog'
|
||||
|
||||
import CrossIcon from '~public/icons/Cross.svg'
|
||||
import './index.scss'
|
||||
|
||||
const AboutModal = () => {
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
return (
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger asChild>
|
||||
<li className="MenuItem">
|
||||
<span>About</span>
|
||||
<span>{t('modals.about.title')}</span>
|
||||
</li>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Content className="About Dialog" onOpenAutoFocus={ (event) => event.preventDefault() }>
|
||||
<div className="DialogHeader">
|
||||
<Dialog.Title className="DialogTitle">About</Dialog.Title>
|
||||
<Dialog.Title className="DialogTitle">{t('menu.about')}</Dialog.Title>
|
||||
<Dialog.Close className="DialogClose" asChild>
|
||||
<span>
|
||||
<CrossIcon />
|
||||
|
|
|
|||
|
|
@ -98,6 +98,10 @@
|
|||
font-size: $font-small;
|
||||
line-height: 1.1;
|
||||
max-width: 300px;
|
||||
|
||||
&.jp {
|
||||
max-width: 270px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useCookies } from 'react-cookie'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
import * as Dialog from '@radix-ui/react-dialog'
|
||||
import * as Switch from '@radix-ui/react-switch'
|
||||
|
|
@ -15,8 +17,13 @@ import CrossIcon from '~public/icons/Cross.svg'
|
|||
import './index.scss'
|
||||
|
||||
const AccountModal = () => {
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
const { account } = useSnapshot(accountState)
|
||||
|
||||
const router = useRouter()
|
||||
const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en'
|
||||
|
||||
// Cookies
|
||||
const [accountCookies] = useCookies(['account'])
|
||||
const [userCookies, setUserCookies] = useCookies(['user'])
|
||||
|
|
@ -46,7 +53,7 @@ const AccountModal = () => {
|
|||
const pictureOptions = (
|
||||
pictureData.sort((a, b) => (a.name.en > b.name.en) ? 1 : -1).map((item, i) => {
|
||||
return (
|
||||
<option key={`picture-${i}`} value={item.filename}>{item.name.en}</option>
|
||||
<option key={`picture-${i}`} value={item.filename}>{item.name[locale]}</option>
|
||||
)
|
||||
})
|
||||
)
|
||||
|
|
@ -109,14 +116,14 @@ const AccountModal = () => {
|
|||
<Dialog.Root open={open} onOpenChange={openChange}>
|
||||
<Dialog.Trigger asChild>
|
||||
<li className="MenuItem">
|
||||
<span>Settings</span>
|
||||
<span>{t('menu.settings')}</span>
|
||||
</li>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Content className="Account Dialog" onOpenAutoFocus={ (event) => event.preventDefault() }>
|
||||
<div className="DialogHeader">
|
||||
<div className="DialogTop">
|
||||
<Dialog.Title className="SubTitle">Account Settings</Dialog.Title>
|
||||
<Dialog.Title className="SubTitle">{t('modals.settings.title')}</Dialog.Title>
|
||||
<Dialog.Title className="DialogTitle">@{account.user?.username}</Dialog.Title>
|
||||
</div>
|
||||
<Dialog.Close className="DialogClose" asChild>
|
||||
|
|
@ -129,7 +136,7 @@ const AccountModal = () => {
|
|||
<form onSubmit={update}>
|
||||
<div className="field">
|
||||
<div className="left">
|
||||
<label>Picture</label>
|
||||
<label>{t('modals.settings.labels.picture')}</label>
|
||||
</div>
|
||||
|
||||
<div className={`preview ${pictureData.find(i => i.filename === picture)?.element}`}>
|
||||
|
|
@ -147,18 +154,18 @@ const AccountModal = () => {
|
|||
</div>
|
||||
<div className="field">
|
||||
<div className="left">
|
||||
<label>Language</label>
|
||||
<label>{t('modals.settings.labels.language')}</label>
|
||||
</div>
|
||||
|
||||
<select name="language" onChange={handleLanguageChange} value={language} ref={languageSelect}>
|
||||
<option key="en" value="en">English</option>
|
||||
<option key="jp" value="jp">Japanese</option>
|
||||
<option key="en" value="en">{t('modals.settings.language.english')}</option>
|
||||
<option key="jp" value="jp">{t('modals.settings.language.japanese')}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="left">
|
||||
<label>Private</label>
|
||||
<p>Hide your profile and prevent your grids from showing up in collections</p>
|
||||
<label>{t('modals.settings.labels.private')}</label>
|
||||
<p className={locale}>{t('modals.settings.descriptions.private')}</p>
|
||||
</div>
|
||||
|
||||
<Switch.Root className="Switch" onCheckedChange={handlePrivateChange} checked={privateProfile}>
|
||||
|
|
@ -166,7 +173,7 @@ const AccountModal = () => {
|
|||
</Switch.Root>
|
||||
</div>
|
||||
|
||||
<Button>Save settings</Button>
|
||||
<Button>{t('modals.settings.buttons.confirm')}</Button>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
<Dialog.Overlay className="Overlay" />
|
||||
|
|
|
|||
|
|
@ -90,14 +90,14 @@ const BottomHeader = () => {
|
|||
<AlertDialog.Overlay className="Overlay" />
|
||||
<AlertDialog.Content className="Dialog">
|
||||
<AlertDialog.Title className="DialogTitle">
|
||||
{t('delete_team.title')}
|
||||
{t('modals.delete_team.title')}
|
||||
</AlertDialog.Title>
|
||||
<AlertDialog.Description className="DialogDescription">
|
||||
{t('delete_team.description')}
|
||||
{t('modals.delete_team.description')}
|
||||
</AlertDialog.Description>
|
||||
<div className="actions">
|
||||
<AlertDialog.Cancel className="Button modal">{t('delete_team.buttons.cancel')}</AlertDialog.Cancel>
|
||||
<AlertDialog.Action className="Button modal destructive" onClick={(e) => deleteTeam(e)}>{t('delete_team.buttons.confirm')}</AlertDialog.Action>
|
||||
<AlertDialog.Cancel className="Button modal">{t('modals.delete_team.buttons.cancel')}</AlertDialog.Cancel>
|
||||
<AlertDialog.Action className="Button modal destructive" onClick={(e) => deleteTeam(e)}>{t('modals.delete_team.buttons.confirm')}</AlertDialog.Action>
|
||||
</div>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Portal>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useCookies } from 'react-cookie'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
import AboutModal from '~components/AboutModal'
|
||||
import AccountModal from '~components/AccountModal'
|
||||
|
|
@ -16,6 +17,8 @@ interface Props {
|
|||
}
|
||||
|
||||
const HeaderMenu = (props: Props) => {
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
const [accountCookies] = useCookies(['account'])
|
||||
const [userCookies] = useCookies(['user'])
|
||||
|
||||
|
|
@ -35,22 +38,22 @@ const HeaderMenu = (props: Props) => {
|
|||
/profile/${userCookies.user.picture}@2x.png 2x`}
|
||||
src={`/profile/${userCookies.user.picture}.png`}
|
||||
/>
|
||||
</div
|
||||
></Link>
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="MenuItem">
|
||||
<Link href={`/saved` || ''}>Saved</Link>
|
||||
<Link href={`/saved` || ''}>{t('menu.saved')}</Link>
|
||||
</li>
|
||||
</div>
|
||||
<div className="MenuGroup">
|
||||
<li className="MenuItem">
|
||||
<Link href='/teams'>Teams</Link>
|
||||
<Link href='/teams'>{t('menu.teams')}</Link>
|
||||
</li>
|
||||
|
||||
<li className="MenuItem disabled">
|
||||
<div>
|
||||
<span>Guides</span>
|
||||
<i className="tag">Coming Soon</i>
|
||||
<span>{t('menu.guides')}</span>
|
||||
<i className="tag">{t('coming_soon')}</i>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
|
|
@ -58,7 +61,7 @@ const HeaderMenu = (props: Props) => {
|
|||
<AboutModal />
|
||||
<AccountModal />
|
||||
<li className="MenuItem" onClick={props.logout}>
|
||||
<span>Logout</span>
|
||||
<span>{t('menu.logout')}</span>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
|
|
@ -74,13 +77,13 @@ const HeaderMenu = (props: Props) => {
|
|||
</div>
|
||||
<div className="MenuGroup">
|
||||
<li className="MenuItem">
|
||||
<Link href='/teams'>Teams</Link>
|
||||
<Link href='/teams'>{t('menu.teams')}</Link>
|
||||
</li>
|
||||
|
||||
<li className="MenuItem disabled">
|
||||
<div>
|
||||
<span>Guides</span>
|
||||
<i className="tag">Coming Soon</i>
|
||||
<span>{t('menu.guides')}</span>
|
||||
<i className="tag">{t('menu.logout')}</i>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
|
|
|
|||
63
public/locales/en/common.json
Normal file
63
public/locales/en/common.json
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"buttons": {
|
||||
"copy": "Copy link",
|
||||
"delete": "Delete team",
|
||||
"edit_info": "Edit info",
|
||||
"hide_info": "Hide info",
|
||||
"menu": "Menu",
|
||||
"new": "New"
|
||||
},
|
||||
"modals": {
|
||||
"about": {
|
||||
"title": "About"
|
||||
},
|
||||
"delete_team": {
|
||||
"title": "Delete team",
|
||||
"description": "Are you sure you want to permanently delete this team?",
|
||||
"buttons": {
|
||||
"confirm": "Yes, delete",
|
||||
"cancel": "Nevermind"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Account Settings",
|
||||
"labels": {
|
||||
"picture": "Picture",
|
||||
"language": "Language",
|
||||
"private": "Private"
|
||||
},
|
||||
"descriptions": {
|
||||
"private": "Hide your profile and prevent your grids from showing up in collections"
|
||||
},
|
||||
"language": {
|
||||
"english": "English",
|
||||
"japanese": "Japanese"
|
||||
},
|
||||
"buttons": {
|
||||
"confirm": "Save settings"
|
||||
}
|
||||
}
|
||||
},
|
||||
"menu": {
|
||||
"about": "About",
|
||||
"guides": "Guides",
|
||||
"saved": "Saved",
|
||||
"settings": "Settings",
|
||||
"teams": "Teams",
|
||||
"logout": "Logout"
|
||||
},
|
||||
"party": {
|
||||
"segmented_control": {
|
||||
"class": "Class",
|
||||
"characters": "Characters",
|
||||
"weapons": "Weapons",
|
||||
"summons": "Summons"
|
||||
}
|
||||
},
|
||||
"teams": {
|
||||
"title": "Discover Teams",
|
||||
"loading": "Loading teams...",
|
||||
"not_found": "No teams found"
|
||||
},
|
||||
"coming_soon": "Coming Soon"
|
||||
}
|
||||
64
public/locales/ja/common.json
Normal file
64
public/locales/ja/common.json
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"buttons": {
|
||||
"copy": "リンクをコピー",
|
||||
"delete": "編成を削除",
|
||||
"show_info": "詳細を編集",
|
||||
"hide_info": "詳細を非表示",
|
||||
"menu": "メニュー",
|
||||
"new": "作成"
|
||||
},
|
||||
"modals": {
|
||||
"about": {
|
||||
"title": "このサイトについて"
|
||||
},
|
||||
"delete_team": {
|
||||
"title": "編成を削除しますか",
|
||||
"description": "編成を削除する操作は取り消せません。",
|
||||
"buttons": {
|
||||
"confirm": "削除",
|
||||
"cancel": "キャンセル"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "アカウント設定",
|
||||
"labels": {
|
||||
"picture": "プロフィール画像",
|
||||
"language": "言語",
|
||||
"private": "プライベート"
|
||||
},
|
||||
"descriptions": {
|
||||
"private": "プロフィールを隠し、編成をコレクションに表示されないようにします"
|
||||
},
|
||||
"language": {
|
||||
"english": "英語",
|
||||
"japanese": "日本語"
|
||||
},
|
||||
"buttons": {
|
||||
"confirm": "設定を保存する"
|
||||
}
|
||||
}
|
||||
},
|
||||
"menu": {
|
||||
"about": "このサイトについて",
|
||||
"guides": "攻略",
|
||||
"saved": "保存した編成",
|
||||
"settings": "アカウント設定",
|
||||
"teams": "編成一覧",
|
||||
"logout": "ログアウト"
|
||||
},
|
||||
"party": {
|
||||
"segmented_control": {
|
||||
"class": "ジョブ",
|
||||
"characters": "キャラ",
|
||||
"weapons": "武器",
|
||||
"summons": "召喚石"
|
||||
}
|
||||
},
|
||||
"teams": {
|
||||
"title": "編成一覧",
|
||||
"loading": "ロード中...",
|
||||
"not_found": "編成は見つかりませんでした"
|
||||
},
|
||||
"coming_soon": "開発中"
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue