diff --git a/src/app/auth/components/AuthNavButtons.tsx b/src/app/auth/components/AuthNavButtons.tsx index 6e58d01..f3161f4 100644 --- a/src/app/auth/components/AuthNavButtons.tsx +++ b/src/app/auth/components/AuthNavButtons.tsx @@ -1,8 +1,10 @@ import { useUser } from '../../user/user.ts' import NavButton from '../../../components/buttons/NavButton.tsx' import { useLocation } from 'react-router-dom' +import { useTranslations } from '../../i18n/useTranslations.ts' export default function AuthNavButtons() { + const { t } = useTranslations() const user = useUser() const { pathname } = useLocation() @@ -15,15 +17,15 @@ export default function AuthNavButtons() { if (loggedIn) { return ( <> - logout + {t('nav.logout')} ) } else { const search = redirectQuery.toString() return ( <> - login - register + {t('nav.login')} + {t('nav.register')} ) } diff --git a/src/app/auth/pages/LoginPage.tsx b/src/app/auth/pages/LoginPage.tsx index 1432f32..215d8da 100644 --- a/src/app/auth/pages/LoginPage.tsx +++ b/src/app/auth/pages/LoginPage.tsx @@ -8,12 +8,15 @@ import { useUser } from '../../user/user.ts' import NavBar from '../../../components/NavBar.tsx' import NavButton from '../../../components/buttons/NavButton.tsx' import LinkButton from '../../../components/buttons/LinkButton.tsx' +import { useTranslations } from '../../i18n/useTranslations.ts' interface LoginPageProps { authService: AuthService } export default function LoginPage({ authService }: LoginPageProps) { + const { t } = useTranslations() + const [isSubmitting, setIsSubmitting] = useState(false) const [username, setUsername] = useState('') const [password, setPassword] = useState('') @@ -62,7 +65,7 @@ export default function LoginPage({ authService }: LoginPageProps) { - home + {t('nav.home')} } > @@ -71,7 +74,7 @@ export default function LoginPage({ authService }: LoginPageProps) {
- register instead? + {t('auth.login.register_instead')} {error} diff --git a/src/app/auth/pages/SignupPage.tsx b/src/app/auth/pages/SignupPage.tsx index ab6b376..ec3adba 100644 --- a/src/app/auth/pages/SignupPage.tsx +++ b/src/app/auth/pages/SignupPage.tsx @@ -3,12 +3,12 @@ import { useEffect, useRef, useState, FormEvent, useCallback, Ref } from 'react' import SingleColumnLayout from '../../../layouts/SingleColumnLayout.tsx' import TextInput from '../../../components/inputs/TextInput.tsx' import Button from '../../../components/buttons/Button.tsx' -import AnchorButton from '../../../components/buttons/AnchorButton.tsx' import { invalid, valid, Validation } from '../../../utils/validation.ts' import { AuthService } from '../authService.ts' import LinkButton from '../../../components/buttons/LinkButton.tsx' import NavBar from '../../../components/NavBar.tsx' import NavButton from '../../../components/buttons/NavButton.tsx' +import { useTranslations } from '../../i18n/useTranslations.ts' const SignupCodeKey = 'signupCode' @@ -17,6 +17,7 @@ interface SignupPageProps { } export default function SignupPage({ authService }: SignupPageProps) { + const { t } = useTranslations() const { code } = useParams() const [signupCode, setSignupCode] = useState(null) const [isSubmitting, setIsSubmitting] = useState(false) @@ -31,8 +32,6 @@ export default function SignupPage({ authService }: SignupPageProps) { const userNameInputRef = useRef(null) const passwordInputRef = useRef(null) - const dialogRef = useRef(null) - const navigate = useNavigate() useEffect(() => { @@ -47,10 +46,6 @@ export default function SignupPage({ authService }: SignupPageProps) { theSignupCode = localStorage.getItem(SignupCodeKey) setSignupCode(theSignupCode) } - - if (!theSignupCode) { - dialogRef.current?.showModal() - } }, [code, signupCode]) useEffect(() => {}, [signupCode]) @@ -94,7 +89,7 @@ export default function SignupPage({ authService }: SignupPageProps) { - home + {t('nav.home')} } > @@ -103,6 +98,7 @@ export default function SignupPage({ authService }: SignupPageProps) { -
+
- login instead? + {t('auth.register.login_instead')} {error}
- - -
-

STOP !!!

-

You need an invitation to sign up

-

- I'm surprised you even found your way here without one and honestly I'd prefer it if you - would leave -

-

- If you do want to create an account, you should know who - to contact -

- - I'm sorry I'll go somewhere else :( - -
-
) } interface FormInputProps { id: string + label: string value: string onInput: (value: string) => void error: string | null @@ -179,11 +155,11 @@ interface FormInputProps { ref: Ref } -function FormInput({ id, value, onInput, error, type = 'text', ref }: FormInputProps) { +function FormInput({ id, label, value, onInput, error, type = 'text', ref }: FormInputProps) { return (
{error}
diff --git a/src/app/i18n/en.json b/src/app/i18n/en.json new file mode 100644 index 0000000..6cc6cb5 --- /dev/null +++ b/src/app/i18n/en.json @@ -0,0 +1,19 @@ +{ + "nav.home": "home", + "nav.login": "login", + "nav.register": "register", + "nav.admin": "admin", + "auth.login.cta": "login", + "auth.login.register_instead": "register instead?", + "auth.register.cta": "signup", + "auth.register.login_instead": "login instead?", + "auth.username.label": "username", + "auth.password.label": "password", + "auth.remember_me.label": "stay logged in", + "misc.loading": "wait...", + "nav.logout": "logout", + "post.add_media.cta": "+ add media", + "post.public.label": "public", + "post.submit.cta": "post", + "post.editor.placeholder": "write something..." +} \ No newline at end of file diff --git a/src/app/i18n/translationKeys.ts b/src/app/i18n/translationKeys.ts new file mode 100644 index 0000000..de1c52a --- /dev/null +++ b/src/app/i18n/translationKeys.ts @@ -0,0 +1,24 @@ +export interface Translations { + 'auth.login.cta': string + 'auth.login.register_instead': string + 'auth.password.label': string + 'auth.register.cta': string + 'auth.register.login_instead': string + 'auth.remember_me.label': string + 'auth.username.label': string + + 'misc.loading': string + + 'nav.admin': string + 'nav.home': string + 'nav.login': string + 'nav.logout': string + 'nav.register': string + + 'post.add_media.cta': string + 'post.editor.placeholder': string + 'post.public.label': string + 'post.submit.cta': string +} + +export type TranslationKey = keyof Translations diff --git a/src/app/i18n/useTranslations.ts b/src/app/i18n/useTranslations.ts new file mode 100644 index 0000000..c403be1 --- /dev/null +++ b/src/app/i18n/useTranslations.ts @@ -0,0 +1,13 @@ +import { TranslationKey, Translations } from './translationKeys.ts' +import en from './en.json' assert { type: 'json' } + +export function useTranslations() { + // TODO somehow handle other languages (reactively) + const texts = en as Translations + + function getText(key: K): Translations[K] { + return texts[key] ?? key + } + + return { t: getText } +} diff --git a/src/components/NewPostWidget.tsx b/src/components/NewPostWidget.tsx index ea3496a..d7b4828 100644 --- a/src/components/NewPostWidget.tsx +++ b/src/components/NewPostWidget.tsx @@ -3,6 +3,7 @@ import FancyTextEditor, { TextInputKeyDownEvent } from './inputs/FancyTextEditor import Button from './buttons/Button.tsx' import { openFileDialog } from '../utils/openFileDialog.ts' import makePica from 'pica' +import { useTranslations } from '../app/i18n/useTranslations.ts' interface NewPostWidgetProps { onSubmit: ( @@ -22,6 +23,7 @@ interface Attachment { } export default function NewPostWidget({ onSubmit, isSubmitting = false }: NewPostWidgetProps) { + const { t } = useTranslations() const [content, setContent] = useState('') const [attachments, setAttachments] = useState([]) const [isPublic, setIsPublic] = useState(false) @@ -72,7 +74,7 @@ export default function NewPostWidget({ onSubmit, isSubmitting = false }: NewPos onInput={onContentInput} onKeyDown={onInputKeyDown} className="mb-3" - placeholder="write something..." + placeholder={t('post.editor.placeholder')} /> {attachments.length > 0 && ( @@ -93,7 +95,7 @@ export default function NewPostWidget({ onSubmit, isSubmitting = false }: NewPos