Add translation for battlesuit list page

This commit is contained in:
Sakura Knoll
2022-01-03 15:18:47 +09:00 Unverified
parent d5610fc964
commit ac143a81c0
20 changed files with 331 additions and 87 deletions
+10
View File
@@ -1,9 +1,19 @@
{
"nav": {
"honkai-3rd": "Honkai 3rd",
"versions": "Versions",
"battlesuits": "Battlesuits",
"weapons": "Weapons",
"stigmata": "Stigmata",
"elfs": "ELFs"
},
"breadcrumb": {
"honkai-3rd": "Honkai 3rd",
"battlesuits": "Battlesuits"
},
"battlesuits-list": {
"heading": "Battlesuits",
"filter-by-features": "Filter by Features",
"filter-by-valkyries": "Filter by Valkyries"
}
}
+9
View File
@@ -6,5 +6,14 @@
"weapons": "무기",
"stigmata": "성흔",
"elfs": "무장인형"
},
"breadcrumb": {
"honkai-3rd": "붕괴 3rd",
"battlesuits": "발키리"
},
"battlesuits-list": {
"heading": "발키리",
"filter-by-features": "특성 필터",
"filter-by-valkyries": "발키리 필터"
}
}
@@ -1,6 +1,8 @@
/** @jsxImportSource theme-ui */
import { Flex, Text } from '@theme-ui/components'
import { useRouter } from 'next/router'
import { battlesuitFeatures } from '../../lib/honkai3rd/battlesuits'
import { translate } from '../../lib/i18n'
import SquareImageBox from './SquareImageBox'
interface BattlesuitFeatureLabelProps {
@@ -8,24 +10,29 @@ interface BattlesuitFeatureLabelProps {
}
const BattlesuitFeatureLabel = ({ feature }: BattlesuitFeatureLabelProps) => {
const { locale } = useRouter()
const featureData = battlesuitFeatures.find(
(aFeature) => aFeature.value === feature
)
if (featureData == null) {
return <Text>{feature}</Text>
}
const { label, icon } = featureData
const { label, icon, krLabel } = featureData
const translatedLabel = translate(locale, { 'ko-KR': krLabel }, label)
return (
<Flex sx={{ alignItems: 'center' }}>
{featureData != null && (
<SquareImageBox
size={30}
src={`/assets/honkai3rd/${icon}.png`}
alt={label}
alt={translatedLabel}
mr={1}
/>
)}
<Text>{label}</Text>
<Text>{translatedLabel}</Text>
</Flex>
)
}
+14 -1
View File
@@ -1,5 +1,8 @@
/** @jsxImportSource theme-ui */
import { Flex, Text } from '@theme-ui/components'
import { useRouter } from 'next/router'
import { battlesuitTypes } from '../../lib/honkai3rd/battlesuits'
import { translate } from '../../lib/i18n'
import { capitalize } from '../../lib/string'
import SquareImageBox from './SquareImageBox'
@@ -8,7 +11,17 @@ interface TypeLabelProps {
}
const TypeLabel = ({ type }: TypeLabelProps) => {
const label = capitalize(type)
const battlesuitType = battlesuitTypes.find((aType) => aType.value === type)
const { locale } = useRouter()
const label =
battlesuitType != null
? translate(
locale,
{ 'ko-KR': battlesuitType.krLabel },
battlesuitType.label
)
: capitalize(type)
return (
<Flex sx={{ alignItems: 'center' }}>
+9 -4
View File
@@ -1,6 +1,8 @@
/** @jsxImportSource theme-ui */
import { Flex, Text } from '@theme-ui/components'
import { useRouter } from 'next/router'
import { valkyries } from '../../lib/honkai3rd/battlesuits'
import { translate } from '../../lib/i18n'
import SquareImageBox from './SquareImageBox'
interface ValkyrieLabelProps {
@@ -8,9 +10,12 @@ interface ValkyrieLabelProps {
}
const ValkyrieLabel = ({ valkyrie }: ValkyrieLabelProps) => {
const { icon, label } = valkyries.find(
const { icon, label, krLabel } = valkyries.find(
(aValkyrie) => aValkyrie.value === valkyrie
) || { label: valkyrie }
) || { label: valkyrie, krLabel: valkyrie }
const { locale } = useRouter()
const translatedLabel = translate(locale, { 'ko-KR': krLabel }, label)
return (
<Flex sx={{ alignItems: 'center' }}>
@@ -18,11 +23,11 @@ const ValkyrieLabel = ({ valkyrie }: ValkyrieLabelProps) => {
<SquareImageBox
size={30}
src={`/assets/honkai3rd/${icon}.png`}
alt={label}
alt={translatedLabel}
mr={1}
/>
)}
<Text>{label}</Text>
<Text>{translatedLabel}</Text>
</Flex>
)
}
@@ -2,7 +2,7 @@
import { NavLink, Heading, Flex } from '@theme-ui/components'
import NextLink from 'next/link'
import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next'
import { useTranslation } from '../../lib/i18n'
const Honkai3rdNavigator = () => {
const router = useRouter()
+210 -38
View File
@@ -25,58 +25,230 @@ export interface BattlesuitData {
}
export const battlesuitFeatures = [
{ icon: 'feature-icons/physical', value: 'physical', label: 'Physical' },
{ icon: 'feature-icons/fire-dmg', value: 'fire-dmg', label: 'Fire DMG' },
{ icon: 'feature-icons/ice-dmg', value: 'ice-dmg', label: 'Ice DMG' },
{
icon: 'feature-icons/physical',
value: 'physical',
label: 'Physical',
krLabel: '물리',
},
{
icon: 'feature-icons/fire-dmg',
value: 'fire-dmg',
label: 'Fire DMG',
krLabel: '화염 대미지',
},
{
icon: 'feature-icons/ice-dmg',
value: 'ice-dmg',
label: 'Ice DMG',
krLabel: '빙결 대미지',
},
{
icon: 'feature-icons/lightning-dmg',
value: 'lightning-dmg',
label: 'Lightning DMG',
krLabel: '뇌전 대미지',
},
{
icon: 'feature-icons/freeze',
value: 'freeze',
label: 'Freeze',
krLabel: '빙결',
},
{
icon: 'feature-icons/paralyze',
value: 'paralyze',
label: 'Paralyze',
krLabel: '마비',
},
{ icon: 'feature-icons/stun', value: 'stun', label: 'Stun', krLabel: '기절' },
{
icon: 'feature-icons/ignite',
value: 'ignite',
label: 'Ignite',
krLabel: '점화',
},
{
icon: 'feature-icons/bleed',
value: 'bleed',
label: 'Bleed',
krLabel: '출혈',
},
{
icon: 'feature-icons/heavy-atk',
value: 'heavy-atk',
label: 'Heavy ATK',
krLabel: '강타',
},
{
icon: 'feature-icons/weaken',
value: 'weaken',
label: 'Weaken',
krLabel: '허약',
},
{
icon: 'feature-icons/impair',
value: 'impair',
label: 'Impair',
krLabel: '취약',
},
{ icon: 'feature-icons/freeze', value: 'freeze', label: 'Freeze' },
{ icon: 'feature-icons/paralyze', value: 'paralyze', label: 'Paralyze' },
{ icon: 'feature-icons/stun', value: 'stun', label: 'Stun' },
{ icon: 'feature-icons/ignite', value: 'ignite', label: 'Ignite' },
{ icon: 'feature-icons/bleed', value: 'bleed', label: 'Bleed' },
{ icon: 'feature-icons/heavy-atk', value: 'heavy-atk', label: 'Heavy ATK' },
{ icon: 'feature-icons/weaken', value: 'weaken', label: 'Weaken' },
{ icon: 'feature-icons/impair', value: 'impair', label: 'Impair' },
{
icon: 'feature-icons/time-mastery',
value: 'time mastery',
label: 'Time Mastery',
krLabel: '시공',
},
{
icon: 'feature-icons/gather',
value: 'gather',
label: 'Gather',
krLabel: '흡인',
},
{ icon: 'feature-icons/heal', value: 'heal', label: 'Heal', krLabel: '치료' },
{
icon: 'feature-icons/fast-atk',
value: 'fast atk',
label: 'Fast ATK',
krLabel: '높은 빈도',
},
{
icon: 'feature-icons/burst',
value: 'burst',
label: 'Burst',
krLabel: '폭발, 버스트',
},
{
icon: 'feature-icons/aerial',
value: 'aerial',
label: 'Aerial',
krLabel: '대공',
},
{ icon: 'feature-icons/gather', value: 'gather', label: 'Gather' },
{ icon: 'feature-icons/heal', value: 'heal', label: 'Heal' },
{ icon: 'feature-icons/fast-atk', value: 'fast atk', label: 'Fast ATK' },
{ icon: 'feature-icons/burst', value: 'burst', label: 'Burst' },
{ icon: 'feature-icons/aerial', value: 'aerial', label: 'Aerial' },
]
export const battlesuitTypes = [
{ value: 'mecha', icon: 'type-icons/mecha', label: 'Mecha' },
{ value: 'biologic', icon: 'type-icons/biologic', label: 'Biologic' },
{ value: 'psychic', icon: 'type-icons/psychic', label: 'Psychic' },
{ value: 'quantum', icon: 'type-icons/quantum', label: 'Quantum' },
{ value: 'imaginary', icon: 'type-icons/imaginary', label: 'Imaginary' },
{ value: 'mecha', icon: 'type-icons/mecha', label: 'Mecha', krLabel: '기계' },
{
value: 'biologic',
icon: 'type-icons/biologic',
label: 'Biologic',
krLabel: '생물',
},
{
value: 'psychic',
icon: 'type-icons/psychic',
label: 'Psychic',
krLabel: '이능',
},
{
value: 'quantum',
icon: 'type-icons/quantum',
label: 'Quantum',
krLabel: '양자',
},
{
value: 'imaginary',
icon: 'type-icons/imaginary',
label: 'Imaginary',
krLabel: '허수',
},
]
export const valkyries = [
{ value: 'kiana', icon: 'valkyrie-icons/kiana', label: 'Kiana' },
{ value: 'mei', icon: 'valkyrie-icons/mei', label: 'Mei' },
{ value: 'bronya', icon: 'valkyrie-icons/bronya', label: 'Bronya' },
{ value: 'himeko', icon: 'valkyrie-icons/himeko', label: 'Himeko' },
{ value: 'theresa', icon: 'valkyrie-icons/theresa', label: 'Theresa' },
{ value: 'fuhua', icon: 'valkyrie-icons/fuhua', label: 'Fu Hua' },
{ value: 'rita', icon: 'valkyrie-icons/rita', label: 'Rita' },
{ value: 'sakura', icon: 'valkyrie-icons/sakura', label: 'Sakura' },
{ value: 'kallen', icon: 'valkyrie-icons/kallen', label: 'Kallen' },
{ value: 'olenyevas', icon: 'valkyrie-icons/olenyevas', label: 'Olenyevas' },
{ value: 'seele', icon: 'valkyrie-icons/seele', label: 'Seele' },
{ value: 'durandal', icon: 'valkyrie-icons/durandal', label: 'Durandal' },
{ value: 'fischl', icon: 'valkyrie-icons/fischl', label: 'Fischl' },
{ value: 'elysia', icon: 'valkyrie-icons/elysia', label: 'Elysia' },
{ value: 'mobius', icon: 'valkyrie-icons/mobius', label: 'Mobius' },
{ value: 'raven', icon: 'valkyrie-icons/raven', label: 'Raven' },
{ value: 'carole', icon: 'valkyrie-icons/carole', label: 'Carole' },
{
value: 'kiana',
icon: 'valkyrie-icons/kiana',
label: 'Kiana',
krLabel: '키아나',
},
{ value: 'mei', icon: 'valkyrie-icons/mei', label: 'Mei', krLabel: '메이' },
{
value: 'bronya',
icon: 'valkyrie-icons/bronya',
label: 'Bronya',
krLabel: '브로냐',
},
{
value: 'himeko',
icon: 'valkyrie-icons/himeko',
label: 'Himeko',
krLabel: '히메코',
},
{
value: 'theresa',
icon: 'valkyrie-icons/theresa',
label: 'Theresa',
krLabel: '테레사',
},
{
value: 'fuhua',
icon: 'valkyrie-icons/fuhua',
label: 'Fu Hua',
krLabel: '후카',
},
{
value: 'rita',
icon: 'valkyrie-icons/rita',
label: 'Rita',
krLabel: '리타',
},
{
value: 'sakura',
icon: 'valkyrie-icons/sakura',
label: 'Sakura',
krLabel: '야에 사쿠라',
},
{
value: 'kallen',
icon: 'valkyrie-icons/kallen',
label: 'Kallen',
krLabel: '카렌',
},
{
value: 'olenyevas',
icon: 'valkyrie-icons/olenyevas',
label: 'Olenyevas',
krLabel: '아린 자매',
},
{
value: 'seele',
icon: 'valkyrie-icons/seele',
label: 'Seele',
krLabel: '제레',
},
{
value: 'durandal',
icon: 'valkyrie-icons/durandal',
label: 'Durandal',
krLabel: '듀란달',
},
{
value: 'fischl',
icon: 'valkyrie-icons/fischl',
label: 'Fischl',
krLabel: '피슬',
},
{
value: 'elysia',
icon: 'valkyrie-icons/elysia',
label: 'Elysia',
krLabel: '엘리시아',
},
{
value: 'mobius',
icon: 'valkyrie-icons/mobius',
label: 'Mobius',
krLabel: '뫼비우스',
},
{
value: 'raven',
icon: 'valkyrie-icons/raven',
label: 'Raven',
krLabel: '레이븐',
},
{
value: 'carole',
icon: 'valkyrie-icons/carole',
label: 'Carole',
krLabel: '캐롤',
},
]
+8 -14
View File
@@ -1,17 +1,11 @@
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useTranslation } from 'next-i18next'
export function getI18NProps(
locale: string = 'en-US',
nameSpaces: string[] = []
) {
return serverSideTranslations(locale, ['common', ...nameSpaces])
export function translate(
targetLocale: string = 'en_US',
localeMap: { [key: string]: string | undefined },
fallback: string
): string {
return localeMap[targetLocale] != null ? localeMap[targetLocale]! : fallback
}
export function generateI18NPaths(paths: { params: any; locale?: string }[]) {
return paths.reduce<{ params: any; locale?: string }[]>((newPaths, path) => {
newPaths.push(path)
newPaths.push({ ...path, locale: 'ko-KR' })
return newPaths
}, [])
}
export { useTranslation }
@@ -15,12 +15,12 @@ import {
BattlesuitData,
BattlesuitSkillGroup,
} from '../../../lib/honkai3rd/battlesuits'
import { generateI18NPaths, getI18NProps } from '../../../lib/i18n'
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
import {
getBattlesuitById,
listBattlesuits,
} from '../../../server/data/honkai3rd/battlesuits'
import { useTranslation } from 'next-i18next'
import { useTranslation } from '../../../lib/i18n'
interface BattlesuitShowPageProps {
battlesuit: BattlesuitData
+32 -15
View File
@@ -15,7 +15,8 @@ import {
import BattlesuitCard from '../../../components/molecules/BattlesuitCard'
import { useRouter } from 'next/router'
import { NextPageContext } from 'next'
import { getI18NProps } from '../../../lib/i18n'
import { getI18NProps } from '../../../server/i18n'
import { translate, useTranslation } from '../../../lib/i18n'
type BattlesuitListItemData = Pick<
BattlesuitData,
@@ -26,14 +27,27 @@ interface BattlesuitListPageProps {
battlesuits: BattlesuitListItemData[]
}
const featureFilterOptions: { value: string; label: string; icon?: string }[] =
[{ value: 'all', label: 'All' }, ...battlesuitFeatures]
const featureFilterOptions: {
value: string
label: string
icon?: string
krLabel?: string
}[] = [{ value: 'all', label: 'All', krLabel: '전체' }, ...battlesuitFeatures]
const valkyrieFilterOptions: { value: string; label: string; icon?: string }[] =
[{ value: 'all', label: 'All' }, ...battlesuitTypes, ...valkyries]
const valkyrieFilterOptions: {
value: string
label: string
icon?: string
krLabel?: string
}[] = [
{ value: 'all', label: 'All', krLabel: '전체' },
...battlesuitTypes,
...valkyries,
]
const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
const { query } = useRouter()
const { query, locale } = useRouter()
const { t } = useTranslation()
const filter = useMemo(() => {
if (query.filter == null) {
@@ -63,23 +77,26 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
<Box p={3}>
<Breadcrumb
items={[
{ href: '/honkai3rd', label: 'Honkai 3rd' },
{ href: '/honkai3rd/battlesuits', label: 'Battlesuits' },
{ href: '/honkai3rd', label: t('breadcrumb.honkai-3rd') },
{
href: '/honkai3rd/battlesuits',
label: t('breadcrumb.battlesuits'),
},
]}
/>
<Heading as='h1'>Battlesuits</Heading>
<Heading as='h1'>{t('battlesuits-list.heading')}</Heading>
<Box>
<Heading as='h3'>Filter by Features</Heading>
<Heading as='h3'>{t('battlesuits-list.filter-by-features')}</Heading>
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
{featureFilterOptions.map(({ value, label, icon }) => {
{featureFilterOptions.map(({ value, label, icon, krLabel }) => {
return (
<FilterButton
key={value}
active={value === filter}
value={value}
label={label}
label={translate(locale, { 'ko-KR': krLabel }, label)}
icon={icon}
m={1}
/>
@@ -87,15 +104,15 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
})}
</Flex>
<Heading as='h3'>Filter by Valkyries</Heading>
<Heading as='h3'>{t('battlesuits-list.filter-by-valkyries')}</Heading>
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
{valkyrieFilterOptions.map(({ value, label, icon }) => {
{valkyrieFilterOptions.map(({ value, label, icon, krLabel }) => {
return (
<FilterButton
key={value}
active={value === filter}
value={value}
label={label}
label={translate(locale, { 'ko-KR': krLabel }, label)}
icon={icon}
m={1}
/>
+1 -1
View File
@@ -8,9 +8,9 @@ import SecondaryLabel from '../../../components/atoms/SecondaryLabel'
import Breadcrumb from '../../../components/organisms/Breadcrumb'
import Honkai3rdNavigator from '../../../components/organisms/Honkai3rdNavigator'
import { ElfData } from '../../../lib/honkai3rd/elfs'
import { generateI18NPaths, getI18NProps } from '../../../lib/i18n'
import { capitalize } from '../../../lib/string'
import { getElfById, listElfs } from '../../../server/data/honkai3rd/elfs'
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
interface ElfShowPageProps {
elf: ElfData
+1 -1
View File
@@ -6,7 +6,7 @@ import ElfCard from '../../../components/molecules/ElfCard'
import Breadcrumb from '../../../components/organisms/Breadcrumb'
import Honkai3rdNavigator from '../../../components/organisms/Honkai3rdNavigator'
import { ElfData } from '../../../lib/honkai3rd/elfs'
import { getI18NProps } from '../../../lib/i18n'
import { getI18NProps } from '../../../server/i18n'
import { listElfs } from '../../../server/data/honkai3rd/elfs'
interface ElfListPageProps {
+1 -1
View File
@@ -5,7 +5,7 @@ import NextLink from 'next/link'
import Breadcrumb from '../../components/organisms/Breadcrumb'
import Honkai3rdNavigator from '../../components/organisms/Honkai3rdNavigator'
import { NextPageContext } from 'next'
import { getI18NProps } from '../../lib/i18n'
import { getI18NProps } from '../../server/i18n'
const updateNotes = [
['v5.3', 'https://honkaiimpact3.mihoyo.com/global/en-us/news/17390'],
@@ -6,7 +6,7 @@ import SingleStigmataPage, {
import StigmataSetPage, {
StigmataSetProps,
} from '../../../components/pages/StigmataSetPage'
import { generateI18NPaths, getI18NProps } from '../../../lib/i18n'
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
import {
listStigmata,
getStigmataById,
+1 -1
View File
@@ -10,7 +10,7 @@ import StigmataSetCard from '../../../components/molecules/StigmataSetCard'
import Breadcrumb from '../../../components/organisms/Breadcrumb'
import Honkai3rdNavigator from '../../../components/organisms/Honkai3rdNavigator'
import { StigmataData, StigmataSet } from '../../../lib/honkai3rd/stigmata'
import { getI18NProps } from '../../../lib/i18n'
import { getI18NProps } from '../../../server/i18n'
import {
listStigmata,
listStigmataSet,
+1 -1
View File
@@ -20,7 +20,7 @@ import { BattlesuitData } from '../../../lib/honkai3rd/battlesuits'
import { WeaponData } from '../../../lib/honkai3rd/weapons'
import { SupplyEventData } from '../../../lib/honkai3rd/supplyEvents'
import { VersionData } from '../../../lib/honkai3rd/versions'
import { generateI18NPaths, getI18NProps } from '../../../lib/i18n'
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
interface VersionShowPageProps {
versionData: VersionData
+1 -1
View File
@@ -19,7 +19,7 @@ import { BattlesuitData } from '../../../lib/honkai3rd/battlesuits'
import { WeaponData } from '../../../lib/honkai3rd/weapons'
import { VersionData } from '../../../lib/honkai3rd/versions'
import { SupplyEventData } from '../../../lib/honkai3rd/supplyEvents'
import { getI18NProps } from '../../../lib/i18n'
import { getI18NProps } from '../../../server/i18n'
import { NextPageContext } from 'next'
interface VersionIndexPageProps {
+1 -1
View File
@@ -5,7 +5,7 @@ import SquareImageBox from '../../../components/atoms/SquareImageBox'
import Breadcrumb from '../../../components/organisms/Breadcrumb'
import Honkai3rdNavigator from '../../../components/organisms/Honkai3rdNavigator'
import { WeaponData } from '../../../lib/honkai3rd/weapons'
import { generateI18NPaths, getI18NProps } from '../../../lib/i18n'
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
import { capitalize } from '../../../lib/string'
import {
getWeaponById,
+1 -1
View File
@@ -9,7 +9,7 @@ import FilterButton from '../../../components/atoms/FilterButton'
import { useRouter } from 'next/router'
import { WeaponData } from '../../../lib/honkai3rd/weapons'
import WeaponCard from '../../../components/molecules/WeaponCard'
import { getI18NProps } from '../../../lib/i18n'
import { getI18NProps } from '../../../server/i18n'
import { NextPageContext } from 'next'
type WeaponListItemData = Pick<
+17
View File
@@ -0,0 +1,17 @@
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
export function getI18NProps(
locale: string = 'en-US',
nameSpaces: string[] = []
) {
return serverSideTranslations(locale, ['common', ...nameSpaces])
}
export function generateI18NPaths(paths: { params: any; locale?: string }[]) {
return paths.reduce<{ params: any; locale?: string }[]>((newPaths, path) => {
newPaths.push(path)
newPaths.push({ ...path, locale: 'ko-KR' })
return newPaths
}, [])
}