From 230e952c8454dd18d3ae41628ee72cf88ea3fcbc Mon Sep 17 00:00:00 2001 From: Xeltica Date: Tue, 14 Sep 2021 14:28:40 +0900 Subject: [PATCH] wip --- package.json | 2 + src/frontend/App.tsx | 5 +- src/frontend/Modal.tsx | 2 +- src/frontend/components/DeveloperInfo.tsx | 6 +- src/frontend/components/HashtagTimeline.tsx | 6 +- src/frontend/components/Header.tsx | 10 +-- src/frontend/components/LoginForm.tsx | 7 +- src/frontend/components/Ranking.tsx | 20 +++-- src/frontend/components/SessionDataPage.tsx | 32 +++---- src/frontend/components/SettingPage.tsx | 75 ++++++---------- src/frontend/langs/en_US.json5 | 98 ++++++++++++++++++++- src/frontend/langs/ja_JP.json5 | 98 ++++++++++++++++++++- src/frontend/misc/theme.ts | 14 ++- src/frontend/pages/index.session.tsx | 10 ++- src/frontend/pages/index.welcome.tsx | 11 ++- src/frontend/pages/ranking.tsx | 14 +-- src/frontend/pages/term.tsx | 1 + src/frontend/style.scss | 6 +- yarn.lock | 10 +++ 19 files changed, 312 insertions(+), 115 deletions(-) diff --git a/package.json b/package.json index dd023c9..347a4fc 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "dependencies": { "@babel/preset-react": "^7.14.5", "@reduxjs/toolkit": "^1.6.1", + "@types/insert-text-at-cursor": "^0.3.0", "@types/koa-bodyparser": "^4.3.0", "@types/koa-multer": "^1.0.0", "@types/koa-send": "^4.1.3", @@ -45,6 +46,7 @@ "fibers": "^5.0.0", "i18next": "^20.6.1", "i18next-browser-languagedetector": "^6.1.2", + "insert-text-at-cursor": "^0.3.0", "json5-loader": "^4.0.1", "koa": "^2.13.0", "koa-bodyparser": "^4.3.0", diff --git a/src/frontend/App.tsx b/src/frontend/App.tsx index 3846ebe..2e96e98 100644 --- a/src/frontend/App.tsx +++ b/src/frontend/App.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { BrowserRouter, Link, Route, Switch, useLocation } from 'react-router-dom'; import { Provider } from 'react-redux'; +import { useTranslation } from 'react-i18next'; import { IndexPage } from './pages'; import { RankingPage } from './pages/ranking'; @@ -46,6 +47,8 @@ const AppInner : React.VFC = () => { }; }, [osTheme, setOsTheme]); + const {t} = useTranslation(); + return ( <>
@@ -57,7 +60,7 @@ const AppInner : React.VFC = () => {

(C)2020-2021 Xeltica

-

利用規約

+

{t('termsOfService')}

diff --git a/src/frontend/Modal.tsx b/src/frontend/Modal.tsx index 98d1284..b84b395 100644 --- a/src/frontend/Modal.tsx +++ b/src/frontend/Modal.tsx @@ -73,7 +73,7 @@ export const ModalComponent: React.VFC = () => { if (!shown || !modal) return null; return ( -
dispatch(hideModal())}> +
dispatch(hideModal())}>
e.stopPropagation()}> { ModalInner(modal) }
diff --git a/src/frontend/components/DeveloperInfo.tsx b/src/frontend/components/DeveloperInfo.tsx index a81dd5e..8ee3ffb 100644 --- a/src/frontend/components/DeveloperInfo.tsx +++ b/src/frontend/components/DeveloperInfo.tsx @@ -1,10 +1,12 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; export const DeveloperInfo: React.VFC = () => { + const {t} = useTranslation(); return ( <> -

開発者

-

何か困ったことがあったら、以下のアカウントにメッセージを送ってください。

+

{t('_developerInfo.title')}

+

{t('_developerInfo.description')}

  • @ebi@misskey.io
  • @X@groundpolis.app
  • diff --git a/src/frontend/components/HashtagTimeline.tsx b/src/frontend/components/HashtagTimeline.tsx index d5fc06e..8596cb7 100644 --- a/src/frontend/components/HashtagTimeline.tsx +++ b/src/frontend/components/HashtagTimeline.tsx @@ -1,14 +1,16 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; export type HashtagTimelineProps = { hashtag: string; }; export const HashtagTimeline: React.VFC = ({hashtag}) => { + const {t} = useTranslation(); return ( <> -

    タイムライン

    -

    #{hashtag} タグを含む最新ノートを表示します。

    +

    {t('_timeline.title')}

    +

    {t('_timeline.description', { hashtag })}

    WIP

    ); diff --git a/src/frontend/components/Header.tsx b/src/frontend/components/Header.tsx index 8bdbef6..618b7bb 100644 --- a/src/frontend/components/Header.tsx +++ b/src/frontend/components/Header.tsx @@ -8,19 +8,17 @@ export type HeaderProps = { hasTopLink?: boolean; }; +const messageNumber = Math.floor(Math.random() * 6) + 1; + export const Header: React.FC = ({hasTopLink, children}) => { const { t } = useTranslation(); - - const message = React.useMemo( - () => welcomeMessage[Math.floor(Math.random() * welcomeMessage.length)] , []); - return ( -
    +

    {hasTopLink ? {t('title')} : t('title')}

    -

    {message}

    +

    {t(`_welcomeMessage.pattern${messageNumber}`)}

    {children}
    diff --git a/src/frontend/components/LoginForm.tsx b/src/frontend/components/LoginForm.tsx index 9bdfdd5..5638e8c 100644 --- a/src/frontend/components/LoginForm.tsx +++ b/src/frontend/components/LoginForm.tsx @@ -1,18 +1,19 @@ import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; export const LoginForm: React.VFC = () => { const [host, setHost] = useState(''); + const {t} = useTranslation(); return ( diff --git a/src/frontend/components/Ranking.tsx b/src/frontend/components/Ranking.tsx index cc0de76..f8e25b1 100644 --- a/src/frontend/components/Ranking.tsx +++ b/src/frontend/components/Ranking.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; interface RankingResponse { isCalculating: boolean; @@ -21,6 +22,7 @@ export const Ranking: React.VFC = ({limit}) => { const [response, setResponse] = useState(null); const [isFetching, setIsFetching] = useState(true); const [isError, setIsError] = useState(false); + const {t} = useTranslation(); // APIコール useEffect(() => { @@ -39,27 +41,27 @@ export const Ranking: React.VFC = ({limit}) => { return ( isFetching ? ( -

    取得中…

    +

    {t('fetching')}

    ) : isError ? ( -
    取得エラー
    +
    {t('failedToFetch')}
    ) : response ? ( <> - + {response.isCalculating ? ( -

    現在算出中です。後ほどご確認ください!

    +

    {t('isCalculating')}

    ) : ( - +
    - - - + + + {response.ranking.map((r, i) => ( - + diff --git a/src/frontend/components/SessionDataPage.tsx b/src/frontend/components/SessionDataPage.tsx index 32ff76d..2c894db 100644 --- a/src/frontend/components/SessionDataPage.tsx +++ b/src/frontend/components/SessionDataPage.tsx @@ -1,4 +1,5 @@ import React, { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { LOCALSTORAGE_KEY_TOKEN } from '../const'; import { useGetScoreQuery, useGetSessionQuery } from '../services/session'; import { Skeleton } from './Skeleton'; @@ -6,6 +7,7 @@ import { Skeleton } from './Skeleton'; export const SessionDataPage: React.VFC = () => { const session = useGetSessionQuery(undefined); const score = useGetScoreQuery(undefined); + const {t} = useTranslation(); /** * Session APIのエラーハンドリング @@ -30,20 +32,10 @@ export const SessionDataPage: React.VFC = () => {
    {session.data && (
    -

    - おかえりなさい、 - - @{session.data.username}@{session.data.host} - - さん。 -

    +

    {t('welcomeBack', {acct: `@${session.data.username}@${session.data.host}`})}

    - みす廃レート: + {t('_missHai.rating')}: {session.data.rating}

    @@ -51,28 +43,28 @@ export const SessionDataPage: React.VFC = () => { )} {score.data && (
    -

    みす廃データ

    -
    順位名前レート{t('_missHai.order')}{t('name')}{t('_missHai.rating')}
    {i + 1}位{i + 1} {r.username}@{r.host}
    +

    {t('_missHai.data')}

    +
    - - - + + + - + - + - + diff --git a/src/frontend/components/SettingPage.tsx b/src/frontend/components/SettingPage.tsx index 82e12c8..83d5c9c 100644 --- a/src/frontend/components/SettingPage.tsx +++ b/src/frontend/components/SettingPage.tsx @@ -5,12 +5,13 @@ import { Visibility } from '../../common/types/visibility'; import { useGetSessionQuery } from '../services/session'; import { defaultTemplate } from '../../common/default-template'; import { Card } from './Card'; -import { Theme } from '../misc/theme'; -import { API_ENDPOINT, LOCALSTORAGE_KEY_LANG, LOCALSTORAGE_KEY_TOKEN } from '../const'; +import { Theme, themes } from '../misc/theme'; +import { API_ENDPOINT, LOCALSTORAGE_KEY_TOKEN } from '../const'; import { useDispatch } from 'react-redux'; import { changeLang, changeTheme, showModal } from '../store/slices/screen'; import { useSelector } from '../store'; import { languageName } from '../langs'; +import { useTranslation } from 'react-i18next'; type SettingDraftType = Partial { const dispatch = useDispatch(); const data = session.data; + const {t} = useTranslation(); const [draft, dispatchDraft] = useReducer((state, action) => { return { ...state, ...action }; @@ -38,23 +40,8 @@ export const SettingPage: React.VFC = () => { template: data?.template ?? null, }); - const themes: Array<{ theme: Theme, name: string }> = [ - { - theme: 'light', - name: 'ライトテーマ' - }, - { - theme: 'dark', - name: 'ダークテーマ' - }, - { - theme: 'system', - name: 'システム設定に準じる' - }, - ]; - const currentTheme = useSelector(state => state.screen.theme); - const currentLang = useSelector(state => state.screen.lang); + const currentLang = useSelector(state => state.screen.language); const availableVisibilities: Visibility[] = [ 'public', @@ -150,7 +137,7 @@ export const SettingPage: React.VFC = () => { ) : (
    -

    アラート送信方法

    +

    {t('alertMode')}

    { alertModes.map((mode) => ( @@ -158,27 +145,27 @@ export const SettingPage: React.VFC = () => { { updateSetting({ alertMode: mode }); }} /> - {mode} + {t(`_alertMode.${mode}`)} )) } {draft.alertMode === 'notification' && (
    - 「Misskey に通知」オプションは古いMisskeyでは動作しません。 + {t('_alertMode.notificationWarning')}
    )}
    { draft.alertMode === 'note' && (
    - + { availableVisibilities.map((visibility) => ( )) } @@ -186,26 +173,26 @@ export const SettingPage: React.VFC = () => { { updateSetting({ localOnly: e.target.checked }); }} /> - ローカル限定 + {t('localOnly')}
    )}
    -

    表示設定

    -

    テーマ

    +

    {t('appearance')}

    +

    {t('theme')}

    { - themes.map(({ theme, name }) => ( + themes.map(theme => ( )) }
    -

    言語設定

    +

    {t('language')}

    内容スコア前日比{t('_missHai.dataScore')}{t('_missHai.dataDelta')}
    ノート{t('notes')} {score.data.notesCount} {score.data.notesDelta}
    フォロー{t('following')} {score.data.followingCount} {score.data.followingDelta}
    フォロワー{t('followers')} {score.data.followersCount} {score.data.followersDelta}