From 3ca666145f4de61b8a72441fd26cb8320a0dea23 Mon Sep 17 00:00:00 2001 From: Kazumasa Yokomizo Date: Tue, 24 Dec 2019 14:40:20 +0900 Subject: [PATCH 1/4] Fix sidenav --- .../SideNavigator/FolderListFragment.tsx | 22 ++++++++----- .../SideNavigator/SideNavigator.tsx | 33 ++++++++++--------- .../SideNavigator/TagListFragment.tsx | 11 ++++--- src/lib/i18n/enUS.ts | 33 +++++++++++++++++++ 4 files changed, 70 insertions(+), 29 deletions(-) diff --git a/src/components/SideNavigator/FolderListFragment.tsx b/src/components/SideNavigator/FolderListFragment.tsx index 7f4b573c70..306467754c 100644 --- a/src/components/SideNavigator/FolderListFragment.tsx +++ b/src/components/SideNavigator/FolderListFragment.tsx @@ -10,6 +10,7 @@ import ControlButton from './ControlButton' import { getFolderItemId } from '../../lib/nav' import { getTransferrableNoteData } from '../../lib/dnd' import { IconAddRound, IconBook, IconFile, IconFileOpen } from '../icons' +import { useTranslation } from 'react-i18next' interface FolderListFragmentProps { storage: NoteStorage @@ -17,6 +18,8 @@ interface FolderListFragmentProps { showPromptToRenameFolder: (folderPathname: string) => void } +const { t } = useTranslation() + const FolderListFragment = ({ storage, showPromptToCreateFolder, @@ -63,14 +66,14 @@ const FolderListFragment = ({ popup(event, [ { type: MenuTypes.Normal, - label: 'New Folder', + label: t('folder.create'), onClick: async () => { showPromptToCreateFolder(folderPathname) } }, { type: MenuTypes.Normal, - label: 'Rename Folder', + label: t('folder.rename'), enabled: folderPathname !== '/', onClick: async () => { showPromptToRenameFolder(folderPathname) @@ -78,14 +81,14 @@ const FolderListFragment = ({ }, { type: MenuTypes.Normal, - label: 'Remove Folder', + label: t('folder.remove'), enabled: folderPathname !== '/', onClick: () => { messageBox({ title: `Remove "${folderPathname}" folder`, - message: 'All notes and subfolders will be deleted.', + message: t('folder.removeMessage'), iconType: DialogIconTypes.Warning, - buttons: ['Remove Folder', 'Cancel'], + buttons: [t('folder.remove'), t('general.cancel')], defaultButtonIndex: 0, cancelButtonIndex: 1, onClose: (value: number | null) => { @@ -143,10 +146,10 @@ const FolderListFragment = ({ }) } else { messageBox({ - title: 'Move Note to Other storage', - message: 'You are trying to move a note to different storage.', + title: t('storage.moveTitle'), + message: t('storage.moveMessage'), iconType: DialogIconTypes.Info, - buttons: ['Move Note', 'Copy Note', 'Cancel'], + buttons: [t('storage.move'), t('storage.copy'), t('general.cancel')], defaultButtonIndex: 0, cancelButtonIndex: 2, onClose: async (value: number | null) => { @@ -174,12 +177,13 @@ const FolderListFragment = ({ } } } + return ( <> diff --git a/src/components/SideNavigator/SideNavigator.tsx b/src/components/SideNavigator/SideNavigator.tsx index fb517fd684..f945ca9f03 100644 --- a/src/components/SideNavigator/SideNavigator.tsx +++ b/src/components/SideNavigator/SideNavigator.tsx @@ -20,6 +20,7 @@ import TagListFragment from './TagListFragment' import TutorialsNavigator from '../Tutorials/TutorialsNavigator' import { useUsers } from '../../lib/accounts' import { useToast } from '../../lib/toast' +import { useTranslation } from 'react-i18next' import { IconAddRound, IconAdjustVertical, @@ -172,6 +173,8 @@ export default () => { const currentPathname = usePathnameWithoutNoteId() + const { t } = useTranslation() + return (
@@ -235,12 +238,11 @@ export default () => { } const showPromptToRenameFolder = (folderPathname: string) => { prompt({ - title: 'Rename the Folder', - message: - 'Enter the new folder name, every note and subfolder paths will also be updated.', + title: t('folder.rename'), + message: t('folder.renameMessage'), iconType: DialogIconTypes.Question, defaultValue: folderPathname.split('/').pop(), - submitButtonLabel: 'Rename Folder', + submitButtonLabel: t('folder.rename'), onClose: async (value: string | null) => { const folderPathSplit = folderPathname.split('/') if ( @@ -257,8 +259,8 @@ export default () => { openSideNavFolderItemRecursively(storage.id, newPathname) } catch (error) { pushMessage({ - title: 'Error', - description: 'You could not rename the folder' + title: t('general.error'), + description: t('folder.renameErrorMessage') }) } } @@ -323,14 +325,14 @@ export default () => { popup(event, [ { type: MenuTypes.Normal, - label: 'Rename Storage', + label: t('storage.rename'), onClick: async () => { prompt({ title: `Rename "${storage.name}" storage`, - message: 'Enter new storage name', + message: t('storage.renameMessage'), iconType: DialogIconTypes.Question, defaultValue: storage.name, - submitButtonLabel: 'Rename Storage', + submitButtonLabel: t('storage.rename'), onClose: async (value: string | null) => { if (value == null) return await renameStorage(storage.id, value) @@ -340,14 +342,13 @@ export default () => { }, { type: MenuTypes.Normal, - label: 'Remove Storage', + label: t('storage.remove'), onClick: async () => { messageBox({ title: `Remove "${storage.name}" storage`, - message: - 'The storage will be unlinked from this app.', + message: t('storage.removeMessage'), iconType: DialogIconTypes.Warning, - buttons: ['Remove Storage', 'Cancel'], + buttons: [t('storage.remove'), t('general.cancel')], defaultButtonIndex: 0, cancelButtonIndex: 1, onClose: (value: number | null) => { @@ -372,7 +373,7 @@ export default () => { @@ -388,7 +389,7 @@ export default () => { /> : } active={trashcanPageIsActive} onClick={() => push(trashcanPagePathname)} @@ -403,7 +404,7 @@ export default () => { ) })} {storageEntries.length === 0 && ( -
No storages
+
{t('storage.noStorage')}
)} {preferences['general.tutorials'] === 'display' && ( diff --git a/src/components/SideNavigator/TagListFragment.tsx b/src/components/SideNavigator/TagListFragment.tsx index f9fe0a1793..39a2938278 100644 --- a/src/components/SideNavigator/TagListFragment.tsx +++ b/src/components/SideNavigator/TagListFragment.tsx @@ -8,11 +8,14 @@ import { useContextMenu, MenuTypes } from '../../lib/contextMenu' import { useDialog, DialogIconTypes } from '../../lib/dialog' import { useDb } from '../../lib/db' import { IconTag, IconTags, IconTagFill } from '../icons' +import { useTranslation } from 'react-i18next' interface TagListFragmentProps { storage: NoteStorage } +const { t } = useTranslation() + const TagListFragment = ({ storage }: TagListFragmentProps) => { const { toggleSideNavOpenedItem, sideNavOpenedItemSet } = useGeneralStatus() const { id: storageId, tagMap } = storage @@ -44,13 +47,13 @@ const TagListFragment = ({ storage }: TagListFragmentProps) => { popup(event, [ { type: MenuTypes.Normal, - label: 'Remove Tag', + label: t('tag.remove'), onClick: () => { messageBox({ title: `Remove "${tagName}" tag`, - message: 'The tag will be untagged from all notes.', + message: t('tag.removeMessage'), iconType: DialogIconTypes.Warning, - buttons: ['Remove Folder', 'Cancel'], + buttons: [t('tag.removeMessage'), t('general.cancel')], defaultButtonIndex: 0, cancelButtonIndex: 1, onClose: (value: number | null) => { @@ -73,7 +76,7 @@ const TagListFragment = ({ storage }: TagListFragmentProps) => { } - label='Tags' + label={t('tag.tag')} folded={tagList.length > 0 ? tagListIsFolded : undefined} onFoldButtonClick={() => { toggleSideNavOpenedItem(tagListNavItemId) diff --git a/src/lib/i18n/enUS.ts b/src/lib/i18n/enUS.ts index 95ba6c55ca..a87bd188de 100644 --- a/src/lib/i18n/enUS.ts +++ b/src/lib/i18n/enUS.ts @@ -1,5 +1,38 @@ export default { translation: { + //General + 'general.error': 'Error', + 'general.cancel': 'Cancel', + 'general.attachments': 'Attachments', + 'general.trash': 'Trash', + 'general.allnote': 'All Notes', + + // Storage + 'storage.noStorage': 'No storages', + 'storage.rename': 'Rename Storage', + 'storage.renameMessage': 'Enter new storage name', + 'storage.remove': 'Remove Storage', + 'storage.removeMessage': 'The storage will be unlinked from this app.', + 'storage.move': 'Move Note', + 'storage.moveTitle': 'Move Note to Other storage', + 'storage.moveMessage': + 'You are trying to move a note to different storage.', + 'storage.copy': 'Copy Note', + + //Folder + 'folder.create': 'New Folder', + 'folder.rename': 'Rename Folder', + 'folder.renameMessage': + 'Enter the new folder name, every note and subfolder paths will also be updated.', + 'folder.renameErrorMessage': 'You could not rename the folder', + 'folder.remove': 'Remove Folder', + 'folder.removeMessage': 'All notes and subfolders will be deleted.', + + //Tag + 'tag.tag': 'Tags', + 'tag.remove': 'Remove Tag', + 'tag.removeMessage': 'The tag will be untagged from all notes.', + // Preferences GeneralTab 'preferences.account': 'Account', 'preferences.addAccount': 'Sign in', From af8936a6a948313f1de29bcabbb09d5c2b341567 Mon Sep 17 00:00:00 2001 From: Kazumasa Yokomizo Date: Tue, 24 Dec 2019 14:53:56 +0900 Subject: [PATCH 2/4] Add NoteList --- src/components/NotePage/NoteList/NoteItem.tsx | 13 ++++++++----- src/components/NotePage/NoteList/NoteList.tsx | 9 ++++++--- src/lib/i18n/enUS.ts | 12 ++++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/components/NotePage/NoteList/NoteItem.tsx b/src/components/NotePage/NoteList/NoteItem.tsx index c7d14fd03d..2a7a195044 100644 --- a/src/components/NotePage/NoteList/NoteItem.tsx +++ b/src/components/NotePage/NoteList/NoteItem.tsx @@ -15,6 +15,7 @@ import { scaleAndTransformFromLeft } from '../../../lib/styled' import { PopulatedNoteDoc } from '../../../lib/db/types' import { useContextMenu, MenuTypes } from '../../../lib/contextMenu' import { useDb } from '../../../lib/db' +import { useTranslation } from 'react-i18next' export const StyledNoteListItem = styled.div` margin: 0; @@ -109,6 +110,8 @@ export default ({ const { popup } = useContextMenu() const { createNote, trashNote, updateNote } = useDb() + const { t } = useTranslation() + const contextMenuCallback = useCallback( (event: React.MouseEvent) => { event.stopPropagation() @@ -116,7 +119,7 @@ export default ({ popup(event, [ { type: MenuTypes.Normal, - label: 'Duplicate', + label: t('note.duplicate'), onClick: async () => { createNote(note.storageId, { title: note.title, @@ -130,14 +133,14 @@ export default ({ }, { type: MenuTypes.Normal, - label: 'Delete', + label: t('note.delete'), onClick: async () => { trashNote(note.storageId, note._id) } }, { type: MenuTypes.Normal, - label: note.bookmarked ? 'Remove Bookmark' : 'Bookmark', + label: note.bookmarked ? t('bookmark.remove') : t('bookmark.add'), onClick: async () => { note.bookmarked = !note.bookmarked updateNote(note.storageId, note._id, note) @@ -161,13 +164,13 @@ export default ({ .shift() return contentToHighlight == null ? ( - 'Empty note' + t('note.empty') ) : ( ) } - return trimmedContent.split('\n').shift() || 'Empty note' + return trimmedContent.split('\n').shift() || t('note.empty') }, [note.content, search]) const handleDragStart = useCallback( diff --git a/src/components/NotePage/NoteList/NoteList.tsx b/src/components/NotePage/NoteList/NoteList.tsx index 15bacb07ec..0f313274c2 100644 --- a/src/components/NotePage/NoteList/NoteList.tsx +++ b/src/components/NotePage/NoteList/NoteList.tsx @@ -13,6 +13,7 @@ import { iconColor } from '../../../lib/styled/styleFunctions' import { IconEdit, IconLoupe } from '../../icons' +import { useTranslation } from 'react-i18next' export const StyledNoteListContainer = styled.div` display: flex; @@ -81,6 +82,8 @@ type NoteListProps = { lastCreatedNoteId: string } +const { t } = useTranslation() + const NoteList = ({ notes, createNote, @@ -127,7 +130,7 @@ const NoteList = ({ className='input' value={search} onChange={updateSearchInput} - placeholder='Search Notes' + placeholder={t('note.search')} />
@@ -156,9 +159,9 @@ const NoteList = ({ })} {notes.length === 0 ? ( search.trim() === '' ? ( -
  • No notes
  • +
  • {t('note.nothing')}
  • ) : ( -
  • No notes could be found.
  • +
  • {t('note.nothingMessage')}
  • ) ) : null} diff --git a/src/lib/i18n/enUS.ts b/src/lib/i18n/enUS.ts index a87bd188de..74b11b738a 100644 --- a/src/lib/i18n/enUS.ts +++ b/src/lib/i18n/enUS.ts @@ -33,6 +33,18 @@ export default { 'tag.remove': 'Remove Tag', 'tag.removeMessage': 'The tag will be untagged from all notes.', + //Note + 'note.duplicate': 'Duplicate', + 'note.delete': 'Delete', + 'note.empty': 'Empty note', + 'note.search': 'Search Notes', + 'note.nothing': 'No notes', + 'note.nothingMessage': 'No notes could be found.', + + //Bookmark + 'bookmark.remove': 'Remove Bookmark', + 'bookmark.add': 'Bookmark', + // Preferences GeneralTab 'preferences.account': 'Account', 'preferences.addAccount': 'Sign in', From 65501d0a9604c3ff9cc65cad9507d4e8d8ef26f0 Mon Sep 17 00:00:00 2001 From: Kazumasa Yokomizo Date: Tue, 24 Dec 2019 15:42:23 +0900 Subject: [PATCH 3/4] Add remaining part --- src/components/NotePage/NoteList/NoteItem.tsx | 6 +- src/components/NotePage/NotePage.tsx | 18 +++-- src/components/PreferencesModal/AboutTab.tsx | 31 ++++---- .../PreferencesModal/BillingTab.tsx | 49 +++++++----- src/components/PreferencesModal/ImportTab.tsx | 21 ++--- .../PreferencesModal/MarkdownTab.tsx | 8 +- .../PreferencesModal/PreferencesModal.tsx | 5 +- src/components/PreferencesModal/UserInfo.tsx | 5 +- src/components/Storage/StorageCreate.tsx | 10 +-- src/components/Storage/StorageEdit.tsx | 18 +++-- .../Tutorials/TutorialsNoteDetail.tsx | 5 +- .../Tutorials/TutorialsNoteList.tsx | 5 +- src/components/Tutorials/TutorialsPage.tsx | 5 +- src/lib/i18n/enUS.ts | 76 ++++++++++++++++++- 14 files changed, 182 insertions(+), 80 deletions(-) diff --git a/src/components/NotePage/NoteList/NoteItem.tsx b/src/components/NotePage/NoteList/NoteItem.tsx index 2a7a195044..7748820a3c 100644 --- a/src/components/NotePage/NoteList/NoteItem.tsx +++ b/src/components/NotePage/NoteList/NoteItem.tsx @@ -192,9 +192,11 @@ export default ({
    - {note.title.length === 0 &&
    No title
    } + {note.title.length === 0 && ( +
    {t('note.noTitle')}
    + )}
    - {formatDistanceToNow(new Date(note.updatedAt))} ago + {formatDistanceToNow(new Date(note.updatedAt))} {t('note.date')}
    {contentPreview}
    {note.tags.length > 0 && ( diff --git a/src/components/NotePage/NotePage.tsx b/src/components/NotePage/NotePage.tsx index 62a62bea39..3a701bbac9 100644 --- a/src/components/NotePage/NotePage.tsx +++ b/src/components/NotePage/NotePage.tsx @@ -23,6 +23,7 @@ import { import { useGeneralStatus, ViewModeType } from '../../lib/generalStatus' import { useDialog, DialogIconTypes } from '../../lib/dialog' import { escapeRegExp } from '../../lib/regex' +import { useTranslation } from 'react-i18next' export const StyledNoteDetailNoNote = styled.div` text-align: center; @@ -59,6 +60,8 @@ export default () => { const { push } = useRouter() const [lastCreatedNoteId, setLastCreatedNoteId] = useState('') + const { t } = useTranslation() + useEffect(() => { setLastCreatedNoteId('') }, [currentPathnameWithoutNoteId]) @@ -216,10 +219,10 @@ export default () => { const purgeNote = useCallback( (storageId: string, noteId: string) => { messageBox({ - title: 'Delete a Note', - message: 'The note will be deleted permanently', + title: t('note.delete2'), + message: t('note.deleteMessage'), iconType: DialogIconTypes.Warning, - buttons: ['Delete Note', 'Cancel'], + buttons: [t('note.delete2'), t('general.cancel')], defaultButtonIndex: 0, cancelButtonIndex: 1, onClose: (value: number | null) => { @@ -273,13 +276,14 @@ export default () => { {storageId != null ? (
    -

    Command(⌘) + N

    -

    to create a new note

    +

    {t('note.createKeyMac')}

    +

    {t('note.createKeyWinLin')}

    +

    {t('note.createkeymessage1')}

    ) : (
    -

    Select a storage

    -

    to create a new note

    +

    {t('note.createkeymessage2')}

    +

    {t('note.createkeymessage3')}

    )}
    diff --git a/src/components/PreferencesModal/AboutTab.tsx b/src/components/PreferencesModal/AboutTab.tsx index febd9df152..2f0da538b8 100644 --- a/src/components/PreferencesModal/AboutTab.tsx +++ b/src/components/PreferencesModal/AboutTab.tsx @@ -9,6 +9,7 @@ import { import { openNew } from '../../lib/utils/platform' import Image from '../atoms/Image' import AppLink from '../atoms/AppLink' +import { useTranslation } from 'react-i18next' const AboutContents = styled.div` max-width: 360px; @@ -79,6 +80,7 @@ interface PrimaryLinkProps { href: string children: string } +const { t } = useTranslation() const PrimaryLink = ({ href, children }: PrimaryLinkProps) => { const handleClick = useCallback( @@ -102,23 +104,20 @@ const AboutTab = () => {
    - About + {t('about.about')}

    Boost Note {process.env.VERSION}

    -

    - An open source note-taking app made for programmers just like - you. -

    +

    {t('about.boostnoteDescription')}

    - Official Website + {t('about.website')} - Boost Note for Team + {t('about.boostWiki')}

    @@ -130,48 +129,48 @@ const AboutTab = () => {
    - Cross-platform + {t('about.platform')}
    - Community + {t('about.community')}
    • - GitHub Repository + {t('about.github')}
    • - Bounty on IssueHunt + {t('about.bounty')}
    • - Blog + {t('about.blog')}
    • - Slack Group + {t('about.slack')}
    • - Twitter Account + {t('about.twitter')}
    • - Facebook Group + {t('about.facebook')}
    • - Reddit + {t('about.reddit')}
    diff --git a/src/components/PreferencesModal/BillingTab.tsx b/src/components/PreferencesModal/BillingTab.tsx index fa56541509..475ca031e0 100644 --- a/src/components/PreferencesModal/BillingTab.tsx +++ b/src/components/PreferencesModal/BillingTab.tsx @@ -11,6 +11,7 @@ import { usePreferences } from '../../lib/preferences' import { getSubscription, Subscription } from '../../lib/accounts' import LoginButton from '../atoms/LoginButton' import { openNew } from '../../lib/utils/platform' +import { useTranslation } from 'react-i18next' const BillingContent = styled.div` .billing-lead { @@ -66,37 +67,43 @@ const BillingTab = () => { const loggedIn = user != null const hasSubscription = subscription != null + const { t } = useTranslation() + return (
    - Billing + {t('billing.billing')} {!loggedIn && (
    -

    Please sign in to upgrade your plan.

    +

    {t('billing.message')}

    )} - Basic + {t('billing.basic')} $0 {!hasSubscription && ( - Current + {t('billing.current')} )} - Premium - $3/Month (USD) * + {t('billing.premium')} + {t('billing.price')} {!loggedIn && ( - Sign In + {t('general.signin')} )} {loggedIn && ( - openNew('https://note.boostio.co/subscription')}> + + openNew('https://note.boostio.co/subscription') + } + > {hasSubscription ? 'Manage' : 'Upgrade'} )} @@ -104,37 +111,37 @@ const BillingTab = () => { - Web App + {t('billing.browser')} 〇 〇 - Desktop App (Mac/Windows/Linux) + {t('billing.desktop')} 〇 〇 - Mobile App (Will be launched at Jan, 2020) + {t('billing.mobile')} 〇 〇 - Syncing Multiple Devices + {t('billing.sync')} 〇 〇 - Local Storage + {t('billing.local')} 〇 〇 - Cloud Storage + {t('billing.cloud')} 〇 〇 - Cloud Storage Size + {t('billing.storageSize')} 100MB 2GB @@ -142,12 +149,12 @@ const BillingTab = () => { {loggedIn && (
    -

    - * If you need more cloud storage, you can add it at any time by - paying $5 (USD) for every 5GB. Click the "Add Extra Storage" - button below. -

    - openNew('https://note.boostio.co/subscription')}>Add Extra Storage +

    {t('billing.addStorageDescription')}

    + openNew('https://note.boostio.co/subscription')} + > + {t('billing.addStorage')} +
    )}
    diff --git a/src/components/PreferencesModal/ImportTab.tsx b/src/components/PreferencesModal/ImportTab.tsx index 3a54c90364..dd45f664ba 100644 --- a/src/components/PreferencesModal/ImportTab.tsx +++ b/src/components/PreferencesModal/ImportTab.tsx @@ -22,6 +22,7 @@ import { textColor } from '../../lib/styled/styleFunctions' import { useToast } from '../../lib/toast' +import { useTranslation } from 'react-i18next' interface Success { err: false @@ -54,6 +55,8 @@ const StyledRemove = styled.span` color: ${({ theme }) => theme.primaryColor}; ` +const { t } = useTranslation() + export default () => { const { pushMessage } = useToast() const { storageMap, createNote } = useDb() @@ -168,14 +171,12 @@ export default () => { return (
    - Import -

    Import .cson files from old Boostnote.

    -

    1. Open old Boostnote folder in your PC.

    -

    2. Drag and drop .cson files to the form below.

    -

    - 3. Choose the Storage and Folder that you want to move your old data. -

    -

    4. Upload!

    + {t('preferences.import')} +

    {t('preferences.description')}

    +

    {t('preferences.importFlow1')}

    +

    {t('preferences.importFlow2')}

    +

    {t('preferences.importFlow3')}

    +

    {t('preferences.importFlow4')}

    { ? `Invalid File: ${entry.filename}` : `Ready to import: ${entry.note.title}`} importRemoveCallback(id)}> - remove + {t('preferences.importRemove')} ) @@ -226,7 +227,7 @@ export default () => { - Upload + {t('preferences.importUpload')}
    ) diff --git a/src/components/PreferencesModal/MarkdownTab.tsx b/src/components/PreferencesModal/MarkdownTab.tsx index 6175fff482..922a5cae42 100644 --- a/src/components/PreferencesModal/MarkdownTab.tsx +++ b/src/components/PreferencesModal/MarkdownTab.tsx @@ -88,10 +88,10 @@ const MarkdownTab = () => { {t('preferences.previewStyle')} - Save + {t('general.save')} - Use default style + {t('preferences.defaultTheme')} @@ -109,7 +109,7 @@ const MarkdownTab = () => { value={preferences['markdown.codeBlockTheme']} onChange={selectCodeFenceTheme} > - + {themes.map(theme => (
    - Markdown Preview + {t('preferences.markdownPreview')}
    { return null } + const { t } = useTranslation() + return ( -
    Preferences
    +
    {t('preferences.general')}
    (

    {user.name}

    signout(user)}> - Sign Out + {t('general.signOut')}
    ) diff --git a/src/components/Storage/StorageCreate.tsx b/src/components/Storage/StorageCreate.tsx index bfb8a9883d..d2745728a5 100644 --- a/src/components/Storage/StorageCreate.tsx +++ b/src/components/Storage/StorageCreate.tsx @@ -46,7 +46,7 @@ export default () => { {t('Create new storage')} - + { checked={storageType === 'cloud'} onChange={() => setStorageType('cloud')} /> - Cloud + {t('storage.typeCloud')} {(storageType === 'local' || isLoggedIn) && ( <> createStorageCallback()}> - Create Storage + {t('storage.create')} @@ -86,7 +86,7 @@ export default () => { {!isLoggedIn && storageType === 'cloud' && ( <> -

    You need to sign in to create a cloud storage.

    +

    {t('storage.needSignIn')}

    { const db = useDb() const router = useRouter() + const { t } = useTranslation() const [name, setName] = useState(storage.name) const { messageBox } = useDialog() const { pushMessage } = useToast() @@ -31,9 +33,9 @@ export default ({ storage }: StorageEditProps) => { const removeCallback = useCallback(() => { messageBox({ title: `Remove "${storage.name}" storage`, - message: 'The storage will be unlinked from this app.', + message: t('storage.removeMessage'), iconType: DialogIconTypes.Warning, - buttons: ['Remove Storage', 'Cancel'], + buttons: [t('storage.remove'), t('general.cancel')], defaultButtonIndex: 0, cancelButtonIndex: 1, onClose: async (value: number | null) => { @@ -43,7 +45,7 @@ export default ({ storage }: StorageEditProps) => { router.push('/app') } catch { pushMessage({ - title: 'Network Error', + title: t('general.networkError'), description: `An error occurred while deleting storage (id: ${storage.id})` }) } @@ -56,7 +58,7 @@ export default ({ storage }: StorageEditProps) => { () => { db.renameStorage(storage.id, name).catch(() => { pushMessage({ - title: 'Network Error', + title: t('general.networkError'), description: `An error occured while updating storage (id:${storage.id}}` }) }) @@ -68,11 +70,11 @@ export default ({ storage }: StorageEditProps) => { return (
    - Edit Storage + {t('storage.edit')}
    - Delete Storage + {t('storage.delete')}
    {isCloudStorageData(storage) && (

    - Last synced at + {t('storage.syncDate')} {new Date(storage.cloudStorage.updatedAt).toLocaleString()}

    diff --git a/src/components/Tutorials/TutorialsNoteDetail.tsx b/src/components/Tutorials/TutorialsNoteDetail.tsx index 0d7f39d41e..24093fb146 100644 --- a/src/components/Tutorials/TutorialsNoteDetail.tsx +++ b/src/components/Tutorials/TutorialsNoteDetail.tsx @@ -8,6 +8,7 @@ import { TutorialsNavigatorTreeItem } from '../../lib/tutorials' import { StyledNoteDetailContainer } from '../NotePage/NoteDetail/NoteDetail' import { ViewModeType } from '../../lib/generalStatus' import { IconEye, IconSplit, IconEdit } from '../icons' +import { useTranslation } from 'react-i18next' type TutorialsNoteDetailProps = { note: TutorialsNavigatorTreeItem @@ -79,10 +80,12 @@ export default class TutorialsNoteDetail extends React.Component< ) + const { t } = useTranslation() + return ( {note == null ? ( -

    No note is selected

    +

    {t('note.unselect')}

    ) : ( <>
    diff --git a/src/components/Tutorials/TutorialsNoteList.tsx b/src/components/Tutorials/TutorialsNoteList.tsx index 623398cf57..b552f0a632 100644 --- a/src/components/Tutorials/TutorialsNoteList.tsx +++ b/src/components/Tutorials/TutorialsNoteList.tsx @@ -2,6 +2,7 @@ import React, { useCallback, KeyboardEvent, useRef } from 'react' import { TutorialsNavigatorTreeItem } from '../../lib/tutorials' import TutorialsNoteItem from './TutorialsNoteItem' import { StyledNoteListContainer } from '../NotePage/NoteList/NoteList' +import { useTranslation } from 'react-i18next' type TutorialsNoteListProps = { currentTree: TutorialsNavigatorTreeItem @@ -47,6 +48,8 @@ const TutorialsNoteList = ({ ? [] : parentTree.children.filter(child => child.type === 'note') + const { t } = useTranslation() + return (
      @@ -65,7 +68,7 @@ const TutorialsNoteList = ({ ) })} - {notes.length === 0 &&
    • No notes
    • } + {notes.length === 0 &&
    • {t('note.nothing')}
    • }
    ) diff --git a/src/components/Tutorials/TutorialsPage.tsx b/src/components/Tutorials/TutorialsPage.tsx index acec69903d..d30ce87997 100644 --- a/src/components/Tutorials/TutorialsPage.tsx +++ b/src/components/Tutorials/TutorialsPage.tsx @@ -5,6 +5,7 @@ import { useGeneralStatus, ViewModeType } from '../../lib/generalStatus' import { useRouter } from '../../lib/router' import TutorialsNoteList from './TutorialsNoteList' import TutorialsNoteDetail from './TutorialsNoteDetail' +import { useTranslation } from 'react-i18next' interface TutorialsPageProps { pathname: string @@ -18,7 +19,7 @@ type TutoriasPagePicker = { export default ({ pathname }: TutorialsPageProps) => { const { generalStatus, setGeneralStatus } = useGeneralStatus() const router = useRouter() - + const { t } = useTranslation() const searchThroughTreeForIdenticalNode = useCallback( ( pathToSearch: string, @@ -241,7 +242,7 @@ export default ({ pathname }: TutorialsPageProps) => { } right={ selectedNote == null ? ( -
    No note selected
    +
    {t('note.unselect')}
    ) : ( Date: Tue, 24 Dec 2019 16:12:37 +0900 Subject: [PATCH 4/4] Add Japanese --- src/lib/i18n/ja.ts | 129 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 5 deletions(-) diff --git a/src/lib/i18n/ja.ts b/src/lib/i18n/ja.ts index 6993dfaa7d..381b7e05b7 100644 --- a/src/lib/i18n/ja.ts +++ b/src/lib/i18n/ja.ts @@ -1,6 +1,111 @@ export default { translation: { - 'preferences.general': '一般', + //General + 'general.error': 'エラー', + 'general.cancel': 'キャンセル', + 'general.attachments': '画像', + 'general.trash': 'ゴミ箱', + 'general.allnote': '全てのノート', + 'general.signin': 'サインイン', + 'general.signOut': 'サインアウト', + 'general.save': '保存', + 'general.default': 'デフォルト', + 'general.networkError': 'ネットワークエラー', + + // Storage + 'storage.name': 'ストレージ名', + 'storage.noStorage': 'ストレージがありません', + 'storage.create': 'ストレージ作成', + 'storage.edit': 'ストレージを編集する', + 'storage.rename': 'ストレージ名を変える', + 'storage.renameMessage': '新しいストレージ名を入力する', + 'storage.remove': 'ストレージを除去する', + 'storage.removeMessage': 'このストレージはアプリから除外されます', + 'storage.delete': 'ストレージを削除する', + 'storage.move': 'ストレージを移動する', + 'storage.moveTitle': 'ノートを新しいストレージに移動する', + 'storage.moveMessage': 'ノートを別のストレージに移動させています', + 'storage.copy': 'ノートをコピーする', + 'storage.typeLocal': 'ローカル', + 'storage.typeCloud': 'クラウド', + 'storage.needSignIn': + 'クラウドストレージを作るためにはサインインが必要です', + 'storage.syncDate': '最終更新', + + //Folder + 'folder.create': 'フォルダ作成', + 'folder.rename': 'フォルダ名変更', + 'folder.renameMessage': + 'フォルダ名を変えると、全てのノートやサブフォルダのパスも更新されます', + 'folder.renameErrorMessage': 'フォルダ名を変更できません', + 'folder.remove': 'フォルダを削除する', + 'folder.removeMessage': 'フォルダを削除すると全てのノートも削除されます', + + //Tag + 'tag.tag': 'タグ', + 'tag.remove': 'タグを削除する', + 'tag.removeMessage': '全てのノートからタグが削除されます', + + //Note + 'note.duplicate': 'コピー', + 'note.delete': '削除', + 'note.delete2': 'ノートを削除する', + 'note.deleteMessage': 'このノートは永久に削除されます', + 'note.empty': 'ノートがありません', + 'note.unselect': 'ノートが選択されていません', + 'note.search': '検索', + 'note.nothing': 'ノートがありません', + 'note.nothingMessage': 'ノートが見つかりません', + 'note.noTitle': '無題', + 'note.date': '前', + 'note.createKeyMac': 'Mac: Command(⌘) + Enter', + 'note.createKeyWinLin': 'Windows/Linux: Ctrl + Enter', + 'note.createkeymessage1': 'ノート作成', + 'note.createkeymessage2': 'ストレージを選択しましょう', + 'note.createkeymessage3': 'ノート作成', + + //Bookmark + 'bookmark.remove': 'ブックマークを削除する', + 'bookmark.add': 'ブックマーク', + + //About + 'about.about': '概要', + 'about.boostnoteDescription': + 'オープンソースの開発者のためのノートアプリ', + 'about.website': 'ウェブサイト', + 'about.boostWiki': 'チームのためのBoost Note', + 'about.platform': 'クロスプラットフォーム', + 'about.community': 'コミュニティ', + 'about.github': 'GitHubレポジトリ', + 'about.bounty': '報奨金プログラム', + 'about.blog': 'ブログ', + 'about.slack': 'スラックグループ', + 'about.twitter': 'ツイッター', + 'about.facebook': 'フェイスブックグループ', + 'about.reddit': 'レディット', + + //Billing + 'billing.billing': '課金', + 'billing.message': 'プランをアップグレードするためにはサインインしてください', + 'billing.basic': '無料', + 'billing.current': '今のプラン', + 'billing.premium': 'プレミアム', + 'billing.price': '3ドル/月 *', + 'billing.browser': 'ブラウザ', + 'billing.desktop': 'デスクトップアプリ (Mac/Windows/Linux)', + 'billing.mobile': 'モバイルアプリ (Will be launched at Jan, 2020)', + 'billing.sync': '複数デバイス間でデータ同期', + 'billing.local': 'ローカルストレージ', + 'billing.cloud': 'クラウドストレージ', + 'billing.storageSize': 'クラウドストレージ容量', + 'billing.addStorageDescription': + '* クラウドストレージ容量を増やすためには、月5ドルを払うことで5GB追加することができます。下の「ストレージ追加」ボタンを押して追加購入をお願いいたします。', + 'billing.addStorage': '容量を増やす', + + // Preferences + 'preferences.general': '設定', + + // Preferences GeneralTab 'preferences.account': 'アカウント', 'preferences.addAccount': 'ログイン', 'preferences.loginWorking': 'ログイン中...', @@ -17,10 +122,10 @@ export default { 'preferences.title': 'タイトル順', 'preferences.analytics': 'アナリティクス', 'preferences.analyticsDescription1': - 'Boost Note collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.You can see how it works on GitHub.', + 'Boost Noteは、改善のためにエンドポイント数等のみデータを取得しています。あなたのノートの中身を見たり、データを取得することは絶対にありません。Boost Noteはオープンソースであるため、どのように動いているかGitHubから確認することができます。', 'preferences.analyticsDescription2': - 'You can choose to enable or disable this option.', - 'preferences.analyticsLabel': 'Enable analytics to help improve Boostnote', + 'データ取得をオンにするかオフにするか、選ぶことができます。', + 'preferences.analyticsLabel': 'Boost Noteの改善のために、データ取得をオンにする', 'preferences.displayTutorialsLabel': 'チュートリアルを表示', // Preferences EditorTab @@ -36,6 +141,20 @@ export default { // Preferences MarkdownTab 'preferences.previewStyle': 'プレビュースタイル', - 'preferences.markdownCodeBlockTheme': 'コードブロックテーマ' + 'preferences.markdownCodeBlockTheme': 'コードブロックテーマ', + 'preferences.defaultTheme': 'Use default style', + 'preferences.markdownPreview': 'Markdown Preview', + + // Preferences ImportTab + 'preferences.import': 'データ移行', + 'preferences.description': '旧Boost Noteアプリからデータを移行する', + 'preferences.importFlow1': '1. あなたのPCで、Boost Noteのファイルが入っているフォルダを選択します', + 'preferences.importFlow2': + '2. .csonファイルを選択し、下のフォームにドラッグ&ドロップしてください', + 'preferences.importFlow3': + '3. どのストレージ・フォルダにデータを移行させるか選択してください', + 'preferences.importFlow4': '4. アップロード', + 'preferences.importRemove': '削除', + 'preferences.importUpload': 'アップロード' } }