feat: update translation

This commit is contained in:
Shusui MOYATANI
2023-07-10 20:03:11 +09:00
parent 605a87558e
commit 4ee3ba9613
23 changed files with 161 additions and 160 deletions

View File

@@ -4,8 +4,8 @@ type ColumnItemProps = {
children: JSX.Element; children: JSX.Element;
}; };
const ColumnItem: Component<ColumnItemProps> = (props) => { const ColumnItem: Component<ColumnItemProps> = (props) => (
return <div class="block shrink-0 overflow-hidden border-b p-1">{props.children}</div>; <div class="block shrink-0 overflow-hidden border-b p-1">{props.children}</div>
}; );
export default ColumnItem; export default ColumnItem;

View File

@@ -27,17 +27,15 @@ const tryEncodeNevent = (eventId: string) => {
} }
}; };
const EventLink: Component<EventLinkProps> = (props) => { const EventLink: Component<EventLinkProps> = (props) => (
return ( <button class="text-blue-500 underline">
<button class="text-blue-500 underline"> <Show
<Show when={props.kind == null || props.kind === Kind.Text}
when={props.kind == null || props.kind === Kind.Text} fallback={tryEncodeNevent(props.eventId)}
fallback={tryEncodeNevent(props.eventId)} >
> {tryEncodeNote(props.eventId)}
{tryEncodeNote(props.eventId)} </Show>
</Show> </button>
</button> );
);
};
export default EventLink; export default EventLink;

View File

@@ -260,9 +260,8 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
} }
}; };
const ensureUploaderAgreement = (): boolean => { const ensureUploaderAgreement = (): boolean => true;
return true; /*
/*
if (didAgreeToToS('nostrBuild')) return true; if (didAgreeToToS('nostrBuild')) return true;
window.alert( window.alert(
@@ -277,8 +276,6 @@ const NotePostForm: Component<NotePostFormProps> = (props) => {
return didAgree; return didAgree;
*/ */
};
const handleChangeFile: JSX.EventHandler<HTMLInputElement, Event> = (ev) => { const handleChangeFile: JSX.EventHandler<HTMLInputElement, Event> = (ev) => {
ev.preventDefault(); ev.preventDefault();
if (uploadFilesMutation.isLoading) return; if (uploadFilesMutation.isLoading) return;

View File

@@ -2,6 +2,7 @@ import { Component, JSX, Show, createSignal } from 'solid-js';
import useDetectOverflow from '@/hooks/useDetectOverflow'; import useDetectOverflow from '@/hooks/useDetectOverflow';
import useFormatDate from '@/hooks/useFormatDate'; import useFormatDate from '@/hooks/useFormatDate';
import { useTranslation } from '@/i18n/useTranslation';
import useProfile from '@/nostr/useProfile'; import useProfile from '@/nostr/useProfile';
import npubEncodeFallback from '@/utils/npubEncodeFallback'; import npubEncodeFallback from '@/utils/npubEncodeFallback';
@@ -16,6 +17,7 @@ export type PostProps = {
}; };
const Post: Component<PostProps> = (props) => { const Post: Component<PostProps> = (props) => {
const i18n = useTranslation();
const { overflow, elementRef } = useDetectOverflow(); const { overflow, elementRef } = useDetectOverflow();
const formatDate = useFormatDate(); const formatDate = useFormatDate();
@@ -98,8 +100,8 @@ const Post: Component<PostProps> = (props) => {
setShowOverflow((current) => !current); setShowOverflow((current) => !current);
}} }}
> >
<Show when={!showOverflow()} fallback="隠す"> <Show when={!showOverflow()} fallback={i18n()('post.hideOverflow')}>
{i18n()('post.showOverflow')}
</Show> </Show>
</button> </button>
</Show> </Show>

View File

@@ -5,6 +5,7 @@ import ArrowLeft from 'heroicons/24/outline/arrow-left.svg';
import TimelineContentDisplay from '@/components/timeline/TimelineContentDisplay'; import TimelineContentDisplay from '@/components/timeline/TimelineContentDisplay';
import { TimelineContext, useTimelineState } from '@/components/timeline/TimelineContext'; import { TimelineContext, useTimelineState } from '@/components/timeline/TimelineContext';
import { useHandleCommand } from '@/hooks/useCommandBus'; import { useHandleCommand } from '@/hooks/useCommandBus';
import { useTranslation } from '@/i18n/useTranslation';
export type ColumnProps = { export type ColumnProps = {
columnIndex: number; columnIndex: number;
@@ -18,6 +19,7 @@ const Column: Component<ColumnProps> = (props) => {
let columnDivRef: HTMLDivElement | undefined; let columnDivRef: HTMLDivElement | undefined;
const timelineState = useTimelineState(); const timelineState = useTimelineState();
const i18n = useTranslation();
const width = () => props.width ?? 'medium'; const width = () => props.width ?? 'medium';
@@ -71,7 +73,7 @@ const Column: Component<ColumnProps> = (props) => {
<div class="inline-block h-4 w-4"> <div class="inline-block h-4 w-4">
<ArrowLeft /> <ArrowLeft />
</div> </div>
<div></div> <div>{i18n()('column.back')}</div>
</button> </button>
</div> </div>
<ul class="flex h-full flex-col overflow-y-scroll scroll-smooth pb-8"> <ul class="flex h-full flex-col overflow-y-scroll scroll-smooth pb-8">

View File

@@ -9,19 +9,16 @@ export type LongFormContentProps = {
event: NostrEvent; event: NostrEvent;
}; };
const LongFormContent: Component<LongFormContentProps> = (props) => { const LongFormContent: Component<LongFormContentProps> = (props) => (
// const event = () => genericEvent(props.event); // const event = () => genericEvent(props.event);
return ( <button class="flex flex-col gap-1 px-1">
<button class="flex flex-col gap-1 px-1"> <div class="flex items-center gap-1">
<div class="flex items-center gap-1"> <span class="inline-block h-4 w-4 text-purple-400">
<span class="inline-block h-4 w-4 text-purple-400"> <DocumentText />
<DocumentText /> </span>
</span> <span>TODO</span>
<span>TODO</span> </div>
</div> </button>
</button> );
);
};
export default LongFormContent; export default LongFormContent;

View File

@@ -29,9 +29,7 @@ const ZapReceipt: Component<ZapReceiptProps> = (props) => {
} }
}; };
const amount = () => { const amount = () => event().findFirstTagByName('amount');
return event().findFirstTagByName('amount');
};
return ( return (
<Show when={!shouldMuteEvent(props.event)}> <Show when={!shouldMuteEvent(props.event)}>

View File

@@ -1,5 +1,6 @@
import { createSignal, type Component, type JSX, Show } from 'solid-js'; import { createSignal, type Component, type JSX, Show } from 'solid-js';
import { useTranslation } from '@/i18n/useTranslation';
import { ContentWarning } from '@/nostr/event/TextNote'; import { ContentWarning } from '@/nostr/event/TextNote';
export type ContentWarningDisplayProps = { export type ContentWarningDisplayProps = {
@@ -8,6 +9,7 @@ export type ContentWarningDisplayProps = {
}; };
const ContentWarningDisplay: Component<ContentWarningDisplayProps> = (props) => { const ContentWarningDisplay: Component<ContentWarningDisplayProps> = (props) => {
const i18n = useTranslation();
const [showContentWarning, setShowContentWarning] = createSignal(false); const [showContentWarning, setShowContentWarning] = createSignal(false);
return ( return (
@@ -18,10 +20,12 @@ const ContentWarningDisplay: Component<ContentWarningDisplayProps> = (props) =>
class="mt-2 w-full rounded border p-2 text-center text-xs text-stone-600 shadow-sm hover:shadow" class="mt-2 w-full rounded border p-2 text-center text-xs text-stone-600 shadow-sm hover:shadow"
onClick={() => setShowContentWarning(true)} onClick={() => setShowContentWarning(true)}
> >
{i18n()('post.contentWarning.show')}
<Show when={props.contentWarning.reason != null}> <Show when={props.contentWarning.reason != null}>
<br /> <br />
<span>: {props.contentWarning.reason}</span> <span>
{i18n()('post.contentWarning.reason')}: {props.contentWarning.reason}
</span>
</Show> </Show>
</button> </button>
} }

View File

@@ -1,6 +1,7 @@
import { Component, createSignal, Show } from 'solid-js'; import { Component, createSignal, Show } from 'solid-js';
import SafeLink from '@/components/utils/SafeLink'; import SafeLink from '@/components/utils/SafeLink';
import { useTranslation } from '@/i18n/useTranslation';
import { fixUrl } from '@/utils/url'; import { fixUrl } from '@/utils/url';
type ImageDisplayProps = { type ImageDisplayProps = {
@@ -10,6 +11,7 @@ type ImageDisplayProps = {
const ImageDisplay: Component<ImageDisplayProps> = (props) => { const ImageDisplay: Component<ImageDisplayProps> = (props) => {
let imageRef: HTMLImageElement | undefined; let imageRef: HTMLImageElement | undefined;
const i18n = useTranslation();
const [hidden, setHidden] = createSignal(props.initialHidden); const [hidden, setHidden] = createSignal(props.initialHidden);
return ( return (
@@ -20,7 +22,7 @@ const ImageDisplay: Component<ImageDisplayProps> = (props) => {
class="rounded bg-stone-300 p-3 text-xs text-stone-600 hover:shadow" class="rounded bg-stone-300 p-3 text-xs text-stone-600 hover:shadow"
onClick={() => setHidden(false)} onClick={() => setHidden(false)}
> >
{i18n()('post.showImage')}
</button> </button>
} }
> >

View File

@@ -11,22 +11,20 @@ export type MentionedEventDisplayProps = {
mentionedEvent: MentionedEvent; mentionedEvent: MentionedEvent;
}; };
const MentionedEventDisplay = (props: MentionedEventDisplayProps) => { const MentionedEventDisplay = (props: MentionedEventDisplayProps) => (
return ( <Show
<Show when={props.mentionedEvent.marker != null && props.mentionedEvent.marker.length > 0}
when={props.mentionedEvent.marker != null && props.mentionedEvent.marker.length > 0} fallback={<EventLink eventId={props.mentionedEvent.eventId} />}
fallback={<EventLink eventId={props.mentionedEvent.eventId} />} >
> <div class="my-1 rounded border p-1">
<div class="my-1 rounded border p-1"> <EventDisplayById
<EventDisplayById eventId={props.mentionedEvent.eventId}
eventId={props.mentionedEvent.eventId} embedding={false}
embedding={false} actions={false}
actions={false} ensureKinds={[Kind.Text]}
ensureKinds={[Kind.Text]} />
/> </div>
</div> </Show>
</Show> );
);
};
export default MentionedEventDisplay; export default MentionedEventDisplay;

View File

@@ -1,6 +1,7 @@
import { Component, createSignal, Show } from 'solid-js'; import { Component, createSignal, Show } from 'solid-js';
import SafeLink from '@/components/utils/SafeLink'; import SafeLink from '@/components/utils/SafeLink';
import { useTranslation } from '@/i18n/useTranslation';
type VideoDisplayProps = { type VideoDisplayProps = {
url: string; url: string;
@@ -9,6 +10,7 @@ type VideoDisplayProps = {
const VideoDisplay: Component<VideoDisplayProps> = (props) => { const VideoDisplay: Component<VideoDisplayProps> = (props) => {
let videoRef: HTMLVideoElement | undefined; let videoRef: HTMLVideoElement | undefined;
const i18n = useTranslation();
const [hidden, setHidden] = createSignal(props.initialHidden); const [hidden, setHidden] = createSignal(props.initialHidden);
return ( return (
@@ -19,7 +21,7 @@ const VideoDisplay: Component<VideoDisplayProps> = (props) => {
class="rounded bg-stone-300 p-3 text-xs text-stone-600 hover:shadow" class="rounded bg-stone-300 p-3 text-xs text-stone-600 hover:shadow"
onClick={() => setHidden(false)} onClick={() => setHidden(false)}
> >
{i18n()('post.showVideo')}
</button> </button>
} }
> >
@@ -31,7 +33,7 @@ const VideoDisplay: Component<VideoDisplayProps> = (props) => {
src={props.url} src={props.url}
controls controls
> >
<a href={props.url}></a> <a href={props.url}>{i18n()('post.download')}</a>
</video> </video>
</SafeLink> </SafeLink>
</Show> </Show>

View File

@@ -109,18 +109,16 @@ const About: Component<AboutProps> = (props) => {
<h2 class="my-4 text-xl font-bold">使</h2> <h2 class="my-4 text-xl font-bold">使</h2>
<For each={packageInfo()?.packages ?? []} fallback="取得中"> <For each={packageInfo()?.packages ?? []} fallback="取得中">
{(p) => { {(p) => (
return ( <>
<> <h3 class="mb-2 mt-4 font-mono">
<h3 class="mb-2 mt-4 font-mono"> {p.name}@{p.version} ({p.licenseSpdx})
{p.name}@{p.version} ({p.licenseSpdx}) </h3>
</h3> <pre class="max-h-96 overflow-scroll rounded bg-zinc-100 p-4 text-xs">
<pre class="max-h-96 overflow-scroll rounded bg-zinc-100 p-4 text-xs"> {p.licenseText}
{p.licenseText} </pre>
</pre> </>
</> )}
);
}}
</For> </For>
</div> </div>
</BasicModal> </BasicModal>

View File

@@ -10,27 +10,25 @@ export type BasicModalProps = {
children: JSX.Element; children: JSX.Element;
}; };
const BasicModal: Component<BasicModalProps> = (props) => { const BasicModal: Component<BasicModalProps> = (props) => (
return ( <Modal onClose={() => props.onClose?.()}>
<Modal onClose={() => props.onClose?.()}> <div class="w-[640px] max-w-full">
<div class="w-[640px] max-w-full"> <button
<button class="w-full pt-1 text-start text-stone-800"
class="w-full pt-1 text-start text-stone-800" aria-label="Close"
aria-label="Close" onClick={() => props.onClose?.()}
onClick={() => props.onClose?.()} >
> <span class="inline-block h-8 w-8">
<span class="inline-block h-8 w-8"> <Show when={props?.closeButton} fallback={<XMark />} keyed>
<Show when={props?.closeButton} fallback={<XMark />} keyed> {(button) => button()}
{(button) => button()} </Show>
</Show> </span>
</span> </button>
</button> <div class="flex max-h-[calc(100vh-4em)] flex-col overflow-y-scroll rounded-xl border bg-white text-stone-700 shadow-lg">
<div class="flex max-h-[calc(100vh-4em)] flex-col overflow-y-scroll rounded-xl border bg-white text-stone-700 shadow-lg"> {props.children}
{props.children}
</div>
</div> </div>
</Modal> </div>
); </Modal>
}; );
export default BasicModal; export default BasicModal;

View File

@@ -104,16 +104,14 @@ const RelayConfig = () => {
</p> </p>
<ul> <ul>
<For each={config().relayUrls}> <For each={config().relayUrls}>
{(relayUrl: string) => { {(relayUrl: string) => (
return ( <li class="flex items-center">
<li class="flex items-center"> <div class="flex-1 truncate">{relayUrl}</div>
<div class="flex-1 truncate">{relayUrl}</div> <button class="h-3 w-3 shrink-0" onClick={() => removeRelay(relayUrl)}>
<button class="h-3 w-3 shrink-0" onClick={() => removeRelay(relayUrl)}> <XMark />
<XMark /> </button>
</button> </li>
</li> )}
);
}}
</For> </For>
</ul> </ul>
<form class="flex gap-2" onSubmit={handleClickAddRelay}> <form class="flex gap-2" onSubmit={handleClickAddRelay}>
@@ -211,23 +209,21 @@ const DateFormatConfig = () => {
const ToggleButton = (props: { const ToggleButton = (props: {
value: boolean; value: boolean;
onClick: JSX.EventHandler<HTMLButtonElement, MouseEvent>; onClick: JSX.EventHandler<HTMLButtonElement, MouseEvent>;
}) => { }) => (
return ( <button
<button class="flex h-[24px] w-[48px] items-center rounded-full border border-primary px-1"
class="flex h-[24px] w-[48px] items-center rounded-full border border-primary px-1" classList={{
classList={{ 'bg-white': !props.value,
'bg-white': !props.value, 'justify-start': !props.value,
'justify-start': !props.value, 'bg-rose-300': props.value,
'bg-rose-300': props.value, 'justify-end': props.value,
'justify-end': props.value, }}
}} area-label={props.value}
area-label={props.value} onClick={(event) => props.onClick(event)}
onClick={(event) => props.onClick(event)} >
> <span class="m-[-2px] inline-block h-5 w-5 rounded-full border border-primary bg-white shadow" />
<span class="m-[-2px] inline-block h-5 w-5 rounded-full border border-primary bg-white shadow" /> </button>
</button> );
);
};
const ReactionConfig = () => { const ReactionConfig = () => {
const i18n = useTranslation(); const i18n = useTranslation();

View File

@@ -39,14 +39,12 @@ const RepliesDisplay: Component<{ event: NostrEvent }> = (props) => {
return <Timeline events={[...events()].reverse()} />; return <Timeline events={[...events()].reverse()} />;
}; };
const TimelineContentDisplay: Component<{ timelineContent: TimelineContent }> = (props) => { const TimelineContentDisplay: Component<{ timelineContent: TimelineContent }> = (props) => (
return ( <Switch>
<Switch> <Match when={props.timelineContent.type === 'Replies' && props.timelineContent} keyed>
<Match when={props.timelineContent.type === 'Replies' && props.timelineContent} keyed> {(replies) => <RepliesDisplay event={replies.event} />}
{(replies) => <RepliesDisplay event={replies.event} />} </Match>
</Match> </Switch>
</Switch> );
);
};
export default TimelineContentDisplay; export default TimelineContentDisplay;

View File

@@ -34,6 +34,6 @@ export const useTranslation = () => {
return i18nextFn; return i18nextFn;
}; };
export const I18NextProvider: Component<I18NextProviderProps> = (props) => { export const I18NextProvider: Component<I18NextProviderProps> = (props) => (
return <I18NextContext.Provider value={props.i18next}>{props.children}</I18NextContext.Provider>; <I18NextContext.Provider value={props.i18next}>{props.children}</I18NextContext.Provider>
}; );

View File

@@ -23,6 +23,7 @@ export default {
search: 'Search', search: 'Search',
myPosts: 'My posts', myPosts: 'My posts',
myReactions: 'My reactions', myReactions: 'My reactions',
back: 'Back',
config: { config: {
columnWidth: 'Column width', columnWidth: 'Column width',
widest: 'Widest', widest: 'Widest',
@@ -61,6 +62,15 @@ export default {
deletedSuccessfully: 'Deleted successfully (reload to reflect)', deletedSuccessfully: 'Deleted successfully (reload to reflect)',
failedToDeletePartially: 'Failed to delete on {{count}} relays', failedToDeletePartially: 'Failed to delete on {{count}} relays',
failedToDelete: 'Failed to delete', failedToDelete: 'Failed to delete',
showImage: 'Show image',
showVideo: 'Show video',
showOverflow: 'Read more',
hideOverflow: 'Hide',
download: 'Download',
contentWarning: {
show: 'Click to display',
reason: 'Reason',
},
}, },
notification: { notification: {
reposted: ' reposted', reposted: ' reposted',

View File

@@ -21,6 +21,7 @@ export default {
search: '検索', search: '検索',
myPosts: '自分の投稿', myPosts: '自分の投稿',
myReactions: '自分のリアクション', myReactions: '自分のリアクション',
back: '戻る',
config: { config: {
columnWidth: 'カラム幅', columnWidth: 'カラム幅',
widest: '特大', widest: '特大',
@@ -59,6 +60,15 @@ export default {
deletedSuccessfully: '削除しました(画面への反映にはリロード)', deletedSuccessfully: '削除しました(画面への反映にはリロード)',
failedToDeletePartially: '{{count}}個のリレーで削除に失敗しました', failedToDeletePartially: '{{count}}個のリレーで削除に失敗しました',
failedToDelete: 'すべてのリレーで削除に失敗しました', failedToDelete: 'すべてのリレーで削除に失敗しました',
showImage: '画像を表示する',
showVideo: '動画を表示する',
showOverflow: '続きを読む',
hideOverflow: '隠す',
download: 'ダウンロード',
contentWarning: {
show: '表示するにはクリック',
reason: '理由',
},
}, },
notification: { notification: {
reposted: 'がリポスト', reposted: 'がリポスト',

View File

@@ -3,10 +3,6 @@ import { Kind, Event as NostrEvent } from 'nostr-tools';
import GenericEvent from '@/nostr/event/GenericEvent'; import GenericEvent from '@/nostr/event/GenericEvent';
import TextNote from '@/nostr/event/TextNote'; import TextNote from '@/nostr/event/TextNote';
export const genericEvent = (event: NostrEvent): GenericEvent => { export const genericEvent = (event: NostrEvent): GenericEvent => new GenericEvent(event);
return new GenericEvent(event);
};
export const textNote = (event: NostrEvent): TextNote => { export const textNote = (event: NostrEvent): TextNote => new TextNote(event);
return new TextNote(event);
};

View File

@@ -23,8 +23,8 @@ export type PublishTextNoteParams = {
} & TagParams; } & TagParams;
// NIP-20: Command Result // NIP-20: Command Result
const waitCommandResult = (pub: Pub, relayUrl: string): Promise<void> => { const waitCommandResult = (pub: Pub, relayUrl: string): Promise<void> =>
return new Promise((resolve, reject) => { new Promise((resolve, reject) => {
pub.on('ok', () => { pub.on('ok', () => {
console.log(`${relayUrl} has accepted our event`); console.log(`${relayUrl} has accepted our event`);
resolve(); resolve();
@@ -34,7 +34,6 @@ const waitCommandResult = (pub: Pub, relayUrl: string): Promise<void> => {
reject(reason); reject(reason);
}); });
}); });
};
export const buildTags = ({ export const buildTags = ({
notifyPubkeys, notifyPubkeys,

View File

@@ -1,16 +1,14 @@
import type { Component } from 'solid-js'; import type { Component } from 'solid-js';
const NotFound: Component = () => { const NotFound: Component = () => (
return ( <div class="container mx-auto max-w-[640px] py-10">
<div class="container mx-auto max-w-[640px] py-10"> <h1 class="text-4xl font-bold text-stone-700"></h1>
<h1 class="text-4xl font-bold text-stone-700"></h1> <p class="pt-4">
<p class="pt-4"> <a class="text-blue-500 underline" href="/">
<a class="text-blue-500 underline" href="/">
</a>
</a> </p>
</p> </div>
</div> );
);
};
export default NotFound; export default NotFound;

View File

@@ -74,6 +74,5 @@ export type UploaderIds = keyof typeof uploaders;
export const uploadFiles = export const uploadFiles =
<T>(uploadFn: (file: Blob) => Promise<T>) => <T>(uploadFn: (file: Blob) => Promise<T>) =>
(files: File[]): Promise<PromiseSettledResult<Awaited<T>>[]> => { (files: File[]): Promise<PromiseSettledResult<Awaited<T>>[]> =>
return Promise.allSettled(files.map((file) => uploadFn(file))); Promise.allSettled(files.map((file) => uploadFn(file)));
};

View File

@@ -1,7 +1,6 @@
const sleep = (ms: number): Promise<void> => { const sleep = (ms: number): Promise<void> =>
return new Promise((resolve) => { new Promise((resolve) => {
setTimeout(resolve, ms); setTimeout(resolve, ms);
}); });
};
export default sleep; export default sleep;