Skip to content

Commit

Permalink
start of i18n support
Browse files Browse the repository at this point in the history
  • Loading branch information
Adammatthiesen committed Nov 13, 2024
1 parent d0e965c commit ac18724
Show file tree
Hide file tree
Showing 18 changed files with 1,039 additions and 203 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
---
import { getLangFromUrl, useTranslations } from 'studiocms:i18n';
import { Divider } from '@studiocms/ui/components';
import OAuthButton from './OAuthButton.astro';
import { providerData, showOAuth } from './oAuthButtonProviders';
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang, '@studiocms/auth:oauth-stack');
const shouldShowOAuth = showOAuth && providerData.some(({ enabled }) => enabled);
---
{ shouldShowOAuth && (
<Divider>or log in using</Divider>
<Divider>{t('or-login-with')}</Divider>
<div class="button-stack">
{
providerData.map(({enabled, ...props}) => enabled && <OAuthButton {...props} />)
Expand Down
33 changes: 33 additions & 0 deletions packages/studiocms_auth/src/components/StaticAuthCheck.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
import { getUserData } from 'studiocms:auth/lib/user';
import { StudioCMSRoutes } from 'studiocms:helpers/routemap';
import { getLangFromUrl, useTranslatedPath } from 'studiocms:i18n';
const { isLoggedIn } = await getUserData(Astro);
// Get the language and translations
const referer = Astro.request.headers.get('referer');
if (!referer) {
throw new Error('No referer found');
}
const lang = getLangFromUrl(new URL(referer));
const translatePath = useTranslatedPath(lang);
const {
mainLinks: { dashboardIndex },
} = StudioCMSRoutes;
---
<div
id="login-check"
style="display: none;"
data-isloggedin={`${isLoggedIn}`}
data-redirectroute={translatePath(dashboardIndex)}
></div>

<script is:inline>
const loginCheck = document.getElementById('login-check');

if (loginCheck.dataset.isloggedin === 'true') {
window.location.href = loginCheck.dataset.redirectroute;
}
</script>
8 changes: 7 additions & 1 deletion packages/studiocms_auth/src/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export default defineIntegration({
},
experimental: {
directRenderScript: true,
serverIslands: true,
},
vite: {
optimizeDeps: {
Expand Down Expand Up @@ -112,6 +113,11 @@ export default defineIntegration({
entrypoint: resolve('./routes/api/login.ts'),
enabled: usernameAndPasswordAPI,
},
{
pattern: 'logout',
entrypoint: resolve('./routes/api/logout.ts'),
enabled: dashboardEnabled && !options.dbStartPage,
},
{
pattern: 'register',
entrypoint: resolve('./routes/api/register.ts'),
Expand Down Expand Up @@ -170,7 +176,7 @@ export default defineIntegration({
},
{
pattern: 'logout/',
entrypoint: resolve('./routes/logout.ts'),
entrypoint: resolve('./routes/logout.astro'),
enabled: dashboardEnabled && !options.dbStartPage,
},
{
Expand Down
14 changes: 8 additions & 6 deletions packages/studiocms_auth/src/layouts/AuthLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ const {
interface Props {
title: string;
description: string;
lang?: string;
lang: string;
disableScreen?: boolean;
}
const { title, description, lang = 'en' } = Astro.props;
const { title, description, lang, disableScreen } = Astro.props;
// Get the site config
const siteConfig = await db
Expand All @@ -37,9 +38,10 @@ const siteConfig = await db
const loginPageBackground = siteConfig?.loginPageBackground;
const loginPageCustomImage = siteConfig?.loginPageCustomImage;
const fallbackImageSrc = loginPageBackground === 'custom'
? loginPageCustomImage
: validImages.find((x) => x.name !== 'custom' && x.name === loginPageBackground)?.dark; // TODO: Adapt to theme
const fallbackImageSrc =
loginPageBackground === 'custom'
? loginPageCustomImage
: validImages.find((x) => x.name !== 'custom' && x.name === loginPageBackground)?.dark; // TODO: Adapt to theme
---
<!doctype html>
<html lang={lang} data-theme="dark">
Expand Down Expand Up @@ -87,7 +89,7 @@ const fallbackImageSrc = loginPageBackground === 'custom'

<slot />

<OAuthButtonStack />
{ !disableScreen && <OAuthButtonStack /> }

<div class="form-footer">
<slot name="footer" />
Expand Down
43 changes: 24 additions & 19 deletions packages/studiocms_auth/src/routes/login.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
---
import { getUserData } from 'studiocms:auth/lib/user';
import { authEnvCheck } from 'studiocms:auth/utils/authEnvCheck';
import { StudioCMSRoutes } from 'studiocms:helpers/routemap';
import { getLangFromUrl, staticPaths, useTranslatedPath, useTranslations } from 'studiocms:i18n';
import Config from 'virtual:studiocms/config';
import { Button, Input } from '@studiocms/ui/components';
import type { GetStaticPaths } from 'astro';
import StaticAuthCheck from '../components/StaticAuthCheck.astro';
import AuthLayout from '../layouts/AuthLayout.astro';
import { hashPassword } from '../lib/password';
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang, '@studiocms/auth:login');
const tPath = useTranslatedPath(lang);
export const getStaticPaths = (() => {
const paths = staticPaths();
return paths;
}) satisfies GetStaticPaths;
const {
dashboardConfig: {
Expand All @@ -21,50 +31,45 @@ const {
const {
authLinks: { loginAPI, signupURL },
mainLinks: { dashboardIndex },
} = StudioCMSRoutes;
const { SHOW_OAUTH } = await authEnvCheck(providers);
let paragraph: string;
if (usernameAndPassword && SHOW_OAUTH) {
paragraph = 'Enter your username & password or log in using one of the options below.';
paragraph = t('sub-header-usernamepasswordoauth');
} else if (usernameAndPassword && !SHOW_OAUTH) {
paragraph = 'Enter your username & password.';
paragraph = t('sub-header-usernamepassword');
} else if (!usernameAndPassword && SHOW_OAUTH) {
paragraph = 'Log in using one of the options below.';
paragraph = t('sub-header-oauth');
} else {
paragraph = 'No Login provider configured. Please contact your administrator.';
}
const user = await getUserData(Astro);
if (user.isLoggedIn) {
return Astro.redirect(dashboardIndex);
paragraph = t('sub-header-noprovider');
}
---
<AuthLayout title="Login Page" description="Login Page">
<AuthLayout title={t('title')} description={t('description')} lang={lang}>

<div slot="header" class="form-header">
<h1>Login</h1>
<h1>{t('header')}</h1>
<p>{paragraph}</p>
</div>

{ usernameAndPassword && (
<form class="form" id="login-form" method="post" action={loginAPI}>

<Input label="Username" name="username" type="text" />
<Input label="Password" name="password" type='password' />
<Input label={t('username-label')} name="username" type="text" />
<Input label={t('password-label')} name="password" type='password' />

<Button as="button" type="submit" color='primary' size='md' variant='solid'><span>Log In</span></Button>
<Button as="button" type="submit" color='primary' size='md' variant='solid'><span>{t('login-button')}</span></Button>
</form>
)}

{ allowUserRegistration && (
<p slot="footer">Don't have an account? <a href={signupURL}>Register here!</a></p>
<p slot="footer">{t('allow-registration-noaccount')} <a href={tPath(signupURL)}>{t('allow-registration-register')}</a></p>
)}

<StaticAuthCheck server:defer />

</AuthLayout>

<script>
Expand Down
33 changes: 33 additions & 0 deletions packages/studiocms_auth/src/routes/logout.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
import { StudioCMSRoutes } from 'studiocms:helpers/routemap';
import { getLangFromUrl, staticPaths, useTranslations } from 'studiocms:i18n';
import type { GetStaticPaths } from 'astro';
import AuthLayout from '../layouts/AuthLayout.astro';
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang, '@studiocms/auth:logout');
export const getStaticPaths = (() => {
const paths = staticPaths();
return paths;
}) satisfies GetStaticPaths;
const {
authLinks: { logoutAPI },
} = StudioCMSRoutes;
---
<AuthLayout title={t('title')} description={t('description')} lang={lang} disableScreen>

</AuthLayout>

<div style="display: none;" id="redirect-to-logout" data-redirect={logoutAPI}></div>

<script>

const redirectElement = document.getElementById('redirect-to-logout') as HTMLDivElement;
const redirect = redirectElement.getAttribute('data-redirect') as string;

setTimeout(() => {
window.location.href = redirect;
}, 500);
</script>
48 changes: 27 additions & 21 deletions packages/studiocms_auth/src/routes/signup.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
---
import { getUserData } from 'studiocms:auth/lib/user';
import { authEnvCheck } from 'studiocms:auth/utils/authEnvCheck';
import { StudioCMSRoutes } from 'studiocms:helpers/routemap';
import { getLangFromUrl, staticPaths, useTranslatedPath, useTranslations } from 'studiocms:i18n';
import Config from 'virtual:studiocms/config';
import { Button, Input } from '@studiocms/ui/components';
import type { GetStaticPaths } from 'astro';
import StaticAuthCheck from '../components/StaticAuthCheck.astro';
import AuthLayout from '../layouts/AuthLayout.astro';
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang, '@studiocms/auth:signup');
const tPath = useTranslatedPath(lang);
export const getStaticPaths = (() => {
const paths = staticPaths();
return paths;
}) satisfies GetStaticPaths;
const {
dashboardConfig: {
AuthConfig: {
Expand All @@ -20,53 +31,48 @@ const {
const {
authLinks: { loginAPI, loginURL },
mainLinks: { dashboardIndex },
} = StudioCMSRoutes;
const { SHOW_OAUTH } = await authEnvCheck(providers);
let paragraph: string;
if (usernameAndPassword && SHOW_OAUTH) {
paragraph = 'Create an account or log in using one of the options below.';
paragraph = t('sub-header-usernamepasswordoauth');
} else if (usernameAndPassword && !SHOW_OAUTH) {
paragraph = 'Create an account using the form below.';
paragraph = t('sub-header-usernamepassword');
} else if (!usernameAndPassword && SHOW_OAUTH) {
paragraph = 'Log in using one of the options below.';
paragraph = t('sub-header-oauth');
} else {
paragraph = 'No Login provider configured. Please contact your administrator.';
}
const user = await getUserData(Astro);
if (user.isLoggedIn) {
return Astro.redirect(dashboardIndex);
paragraph = t('sub-header-noprovider');
}
---
<AuthLayout title="Signup Page" description="Signup Page">
<AuthLayout title={t('title')} description={t('description')} lang={lang}>

<div slot="header" class="form-header">
<h1>Sign up</h1>
<h1>{t('header')}</h1>
<p>{paragraph}</p>
</div>

{ usernameAndPassword && (
<form class="form" id="signup-form" method="post" action={loginAPI}>

<Input label="Username" name="username" type="text" />
<Input label="Email" name="email" type="email" />
<Input label="Display Name" name="displayname" type="text" />
<Input label="Password" name="password" type="password" />
<Input label="Confirm Password" name="confirm-password" type="password" />
<Input label={t('username-label')} name="username" type="text" />
<Input label={t('email-label')} name="email" type="email" />
<Input label={t('displayname-label')} name="displayname" type="text" />
<Input label={t('password-label')} name="password" type="password" />
<Input label={t('confirm-password-label')} name="confirm-password" type="password" />

<Button type="submit" as="button" type="submit" color='primary' variant='solid'>Create Account</Button>
<Button type="submit" as="button" type="submit" color='primary' variant='solid'>{t('create-account-button')}</Button>
</form>
)}

{ allowUserRegistration && (
<p slot="footer">Already have an account? <a href={loginURL}>Sign in!</a></p>
<p slot="footer">{t('allow-login-haveaccount')} <a href={tPath(loginURL)}>{t('allow-login-login')}</a></p>
)}

<StaticAuthCheck server:defer />

</AuthLayout>

<script>
Expand Down
4 changes: 2 additions & 2 deletions packages/studiocms_auth/src/utils/routeBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const makeDashboardRoute = (route: string, options: StudioCMSAuthOptions)
? removeLeadingTrailingSlashes(dashboardRouteOverride)
: 'dashboard';

return `${defaultDashboardRoute}/${route}`;
return `[...locale]/${defaultDashboardRoute}/${route}`;
};

export const injectAuthAPIRoutes = defineUtility('astro:config:setup')(
Expand Down Expand Up @@ -149,7 +149,7 @@ export const injectAuthPageRoutes = defineUtility('astro:config:setup')(
injectRoute({
pattern: makeDashboardRoute(pattern, options),
entrypoint,
prerender: false, // TODO: Change this to true once hybrid mode is ready
prerender: true,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/studiocms_core/src/helpers/routemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const StudioCMSRoutes = {
logoutURL: await makeDashboardRoute('logout'),
signupURL: await makeDashboardRoute('signup'),
loginAPI: await makeStudioCMSAPIRoute('auth/login'), // /studiocms_api/auth/login
logoutAPI: await makeStudioCMSAPIRoute('auth/logout'), // /studiocms_api/auth/logout
registerAPI: await makeStudioCMSAPIRoute('auth/register'), // /studiocms_api/auth/register
githubIndex: await makeStudioCMSAPIRoute('auth/github'), // /studiocms_api/auth/github
githubCallback: await makeStudioCMSAPIRoute('auth/github/callback'), // /studiocms_api/auth/github/callback
Expand Down
Loading

0 comments on commit ac18724

Please sign in to comment.