i18n done?

Signed-off-by: Filipe Medeiros <hello@filipesm.eu>
This commit is contained in:
Filipe Medeiros 2023-04-15 15:12:27 +01:00
parent 098e00e5e0
commit 0973cfe428
Signed by: filipe
GPG key ID: 9533BD5467CC1E78
12 changed files with 393 additions and 31 deletions

View file

@ -3,14 +3,17 @@ import InlineLink from '../components/InlineLink.astro';
export interface Props {
title: string;
ptUrl: string;
enUrl: string;
lang: string;
}
const { title } = Astro.props;
const { title, ptUrl, enUrl, lang } = Astro.props;
const { footer } = Astro.slots;
const hasFooter = !!footer;
---
<html lang="en">
<html lang={lang}>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
@ -22,23 +25,38 @@ const hasFooter = !!footer;
<main class:list={['px-6 pt-4 md:px-20 md:pt-6', hasFooter && 'mb-32']}>
<slot />
</main>
{
hasFooter && (
<footer class="fixed bottom-0 p-4 pb-0 flex flex-col w-full gap-2">
<slot name="footer" />
<div class="flex gap-3 justify-end bg-orange-50 pb-2">
<footer class="fixed bottom-0 p-4 pb-0 flex flex-col w-full gap-2">
<slot name="footer" />
<div
class="flex justify-between max-xs:flex-col-reverse max-xs:items-center bg-orange-50 pb-2"
>
<ul class="flex gap-3">
<li>
<InlineLink href={ptUrl}>PT</InlineLink>
</li>
<li>
<InlineLink href={enUrl}>EN</InlineLink>
</li>
</ul>
<ul class="flex gap-3">
<li>
<InlineLink href="https://mastodon.green/@filipesm">
Mastodon
</InlineLink>
</li>
<li>
<InlineLink href="https://codeberg.org/filipesm">
Codeberg
</InlineLink>
</li>
<li>
<InlineLink href="https://bandcamp.com/filipesm">
Bandcamp
</InlineLink>
</div>
</footer>
)
}
</li>
</ul>
</div>
</footer>
</body>
</html>

View file

@ -2,7 +2,7 @@ import getMostRecentRevisions from '../getMostRecentRevisions';
import groq from 'groq';
export const forBlogPostPage = groq`
${getMostRecentRevisions(groq`_type == "blogPost"`)}
${getMostRecentRevisions(groq`_type == "blogPost" && __i18n_lang == $lang`)}
{
"slug": slug.current,
title,
@ -24,9 +24,7 @@ export const forBlogPostPage = groq`
}`;
export const forBlogPage = groq`
${getMostRecentRevisions(
groq`_type == "blogPost" && __i18n_lang == $locale`,
)}
${getMostRecentRevisions(groq`_type == "blogPost" && __i18n_lang == $lang`)}
{
title,
summary,

View file

@ -3,7 +3,7 @@ import groq from 'groq';
export const forLibraryPage = groq`
${getMostRecentRevisions(
groq`_type == "libraryItem" && __i18n_lang == $locale`,
groq`_type == "libraryItem" && __i18n_lang == $lang`,
)}
{
title,

View file

@ -13,10 +13,16 @@ const libraryItems: {
title: string;
}[] = await client.fetch(forLibraryPage, {
live: !import.meta.env.DEV,
lang: 'pt_PT',
});
---
<Layout title="Biblioteca - Filipe Medeiros">
<Layout
title="Biblioteca - Filipe Medeiros"
ptUrl="/biblioteca"
enUrl="/library"
lang="pt_PT"
>
<header class="mb-10">
<PageTitle class="mb-3">Biblioteca</PageTitle>
<h2>
@ -42,7 +48,7 @@ const libraryItems: {
<Fragment slot="footer">
<nav class="flex gap-4">
<ButtonLink
href="/blog"
href="/blogue"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Blog

View file

@ -23,7 +23,10 @@ export interface Props {
export async function getStaticPaths() {
const posts: (Props & {
slug: string;
})[] = await client.fetch(forBlogPostPage, { live: !import.meta.env.DEV });
})[] = await client.fetch(forBlogPostPage, {
live: !import.meta.env.DEV,
lang: 'en_EN',
});
return posts.map(({ slug, ...blogPost }) => {
return {
@ -43,9 +46,16 @@ const {
linkPreviewDescription,
linkPreviewImage,
} = Astro.props;
const { slug } = Astro.params;
---
<Layout title={`${title} - Filipe Medeiros`}>
<Layout
title={`${title} - Filipe Medeiros`}
ptUrl={`/blogue/${slug}`}
enUrl={`/blog/${slug}`}
lang="en_EN"
>
<BlogPostMetadata
slot="metadata"
title={title}
@ -69,10 +79,10 @@ const {
Blog
</ButtonLink>
<ButtonLink
href="/biblioteca"
href="/library"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Biblioteca
Library
</ButtonLink>
</nav>
</Fragment>

View file

@ -12,10 +12,18 @@ const posts: {
publishDate: string;
summary: string;
slug: string;
}[] = await client.fetch(forBlogPage, { live: !import.meta.env.DEV });
}[] = await client.fetch(forBlogPage, {
live: !import.meta.env.DEV,
lang: 'en_EN',
});
---
<Layout title="Blog - Filipe Medeiros">
<Layout
title="Blog - Filipe Medeiros"
ptUrl="/blogue"
enUrl="/blog"
lang="en_EN"
>
<header class="mb-10">
<PageTitle class="mb-3">Blog</PageTitle>
<h2>Uma coleção de artigos que vou escrevendo. Sobretudo por diversão.</h2>
@ -40,16 +48,16 @@ const posts: {
<Fragment slot="footer">
<nav class="flex gap-4">
<ButtonLink
href="/"
href="/home"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Início
Home
</ButtonLink>
<ButtonLink
href="/biblioteca"
href="/library"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Biblioteca
Library
</ButtonLink>
</nav>
</Fragment>

View file

@ -0,0 +1,89 @@
---
import type { PortableTextBlock } from '@portabletext/types';
import client from '../../../lib/cms/client';
import { forBlogPostPage } from '../../../lib/cms/queries/blogPosts';
import BlogPostContent from '../../../components/portableText/BlogPostContent.astro';
import ButtonLink from '../../../components/ButtonLink.astro';
import PageTitle from '../../../components/PageTitle.astro';
import Layout from '../../../layouts/Layout.astro';
import BlogPostMetadata from '../../../components/BlogPostMetadata.astro';
import type { ImageObject } from '../../../lib/cms/types';
export interface Props {
title: string;
content: PortableTextBlock[];
publishDate: string;
headerImage: ImageObject;
summary: string;
twitterCardType: 'summary' | 'summary_large_image' | 'player' | 'app';
linkPreviewDescription: string;
linkPreviewImage: ImageObject;
}
export async function getStaticPaths() {
const posts: (Props & {
slug: string;
})[] = await client.fetch(forBlogPostPage, {
live: !import.meta.env.DEV,
lang: 'pt_PT',
});
return posts.map(({ slug, ...blogPost }) => {
return {
params: { slug },
props: blogPost,
};
});
}
const {
title,
content,
publishDate,
headerImage,
summary,
twitterCardType,
linkPreviewDescription,
linkPreviewImage,
} = Astro.props;
const { slug } = Astro.params;
---
<Layout
title={`${title} - Filipe Medeiros`}
ptUrl={`/blogue/${slug}`}
enUrl={`/blog/${slug}`}
lang="pt_PT"
>
<BlogPostMetadata
slot="metadata"
title={title}
description={linkPreviewDescription ?? summary}
image={linkPreviewImage ?? headerImage}
twitterCardType={twitterCardType}
/>
<article class="max-w-prose m-auto">
<header class="mb-5">
<PageTitle class="mb-2 break-words">{title}</PageTitle>
<time datetime={publishDate} class="text-xl">{publishDate}</time>
</header>
<BlogPostContent content={content} />
</article>
<Fragment slot="footer">
<nav class="flex gap-4">
<ButtonLink
href="/blogue"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Blog
</ButtonLink>
<ButtonLink
href="/biblioteca"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Biblioteca
</ButtonLink>
</nav>
</Fragment>
</Layout>

View file

@ -0,0 +1,63 @@
---
import client from '../../lib/cms/client';
import { forBlogPage } from '../../lib/cms/queries/blogPosts';
import ButtonLink from '../../components/ButtonLink.astro';
import CardLink from '../../components/CardLink.astro';
import PageTitle from '../../components/PageTitle.astro';
import Layout from '../../layouts/Layout.astro';
const posts: {
title: string;
publishDate: string;
summary: string;
slug: string;
}[] = await client.fetch(forBlogPage, {
live: !import.meta.env.DEV,
lang: 'pt_PT',
});
---
<Layout
title="Blog - Filipe Medeiros"
ptUrl="/blogue"
enUrl="/blog"
lang="pt_PT"
>
<header class="mb-10">
<PageTitle class="mb-3">Blogue</PageTitle>
<h2>Uma coleção de artigos que vou escrevendo. Sobretudo por diversão.</h2>
</header>
<ol>
{
posts.map(({ title, slug, publishDate, summary }) => (
<CardLink link={`/blog/${slug}`}>
<article class="flex flex-col">
<span class="text-lg md:text-xl font-medium break-words text-primary-700">
{title}
</span>
<time datetime={publishDate} class="text-sm text-primary-800">
{publishDate}
</time>
<span>{summary}</span>
</article>
</CardLink>
))
}
</ol>
<Fragment slot="footer">
<nav class="flex gap-4">
<ButtonLink
href="/"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Início
</ButtonLink>
<ButtonLink
href="/biblioteca"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Biblioteca
</ButtonLink>
</nav>
</Fragment>
</Layout>

View file

@ -0,0 +1,93 @@
---
import ButtonLink from '../components/ButtonLink.astro';
import InlineLink from '../components/InlineLink.astro';
import PageTitle from '../components/PageTitle.astro';
import Layout from '../layouts/Layout.astro';
---
<Layout
title="Home page - Filipe Medeiros"
ptUrl="/"
enUrl="/home"
lang="en_EN"
>
<PageTitle class="mb-10">
Filipe<br />Medeiros
</PageTitle>
<div class="max-w-[60ch]">
<p class="mb-3">
Sou um engenheiro de <InlineLink
href="https://www.usability.gov/what-and-why/user-experience.html"
class="italic"
>
UX
</InlineLink> (não me perguntem o que é, que nem eu sei bem).
</p>
<p class="mb-3">
Gosto de programar interfaces e aplicações web, mas também de política, de
ler sobre economia e de animais. Não gosto de cozinhar (ainda) nem de
vento frio.
</p>
<p class="mb-3">
Estou a tentar trazer à superfície o potencial da humanidade. Sou a favor
de <InlineLink href="https://www.w3.org/standards/faq#std" class="italic">
standards
</InlineLink>, software de código aberto (<InlineLink
href="https://codeberg.org/filipesm/personal-website"
>
como é este site!
</InlineLink>), <InlineLink href="https://pt.wikipedia.org/wiki/Copyleft">
licenças <span class="italic">copyleft</span>
</InlineLink>
e de
<InlineLink
href="https://www.ica.coop/en/cooperatives/what-is-a-cooperative"
>
cooperativas
</InlineLink> em vez de monopólios.
</p>
<p class="mb-3">
Sou apaixonado pela <InlineLink
href="https://doughnuteconomics.org/about-doughnut-economics"
class="italic"
>
Economia do Donut
</InlineLink> e por economia social e ambiental. Gostava de, um dia, ser economista
em vez de programador. Quem sabe, para a União Europeia.
</p>
<p class="mb-3">
Moro em <InlineLink href="https://www.oeiras.pt">
Oeiras, Lisboa, Portugal
</InlineLink>.
</p>
<p class="mb-3">
Se quiseres ver, tens <InlineLink href="/me.jpeg">aqui</InlineLink> uma foto
minha!
</p>
<p>
Este site tenta ser o mais sustentável possível: poupamos energia no teu
dispositivo e em servidores. Teve muita inspiração da{' '}
<InlineLink href="https://solar.lowtechmagazine.com">
versão solar da Low Tech Magazine
</InlineLink>.
</p>
</div>
<Fragment slot="footer">
<nav class="flex gap-4">
<ButtonLink
href="/blog"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Blog
</ButtonLink>
<ButtonLink
href="/library"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Library
</ButtonLink>
</nav>
</Fragment>
</Layout>

View file

@ -5,7 +5,12 @@ import PageTitle from '../components/PageTitle.astro';
import Layout from '../layouts/Layout.astro';
---
<Layout title="Página inicial - Filipe Medeiros">
<Layout
title="Página inicial - Filipe Medeiros"
ptUrl="/"
enUrl="/home"
lang="pt_PT"
>
<PageTitle class="mb-10">
Filipe<br />Medeiros
</PageTitle>
@ -72,10 +77,10 @@ import Layout from '../layouts/Layout.astro';
<Fragment slot="footer">
<nav class="flex gap-4">
<ButtonLink
href="/blog"
href="/blogue"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Blog
Blogue
</ButtonLink>
<ButtonLink
href="/biblioteca"

View file

@ -0,0 +1,64 @@
---
import client from '../../lib/cms/client';
import { forLibraryPage } from '../../lib/cms/queries/libraryItems';
import ButtonLink from '../../components/ButtonLink.astro';
import CardLink from '../../components/CardLink.astro';
import PageTitle from '../../components/PageTitle.astro';
import Layout from '../../layouts/Layout.astro';
const libraryItems: {
description: string;
checkedOut: boolean;
link: string;
title: string;
}[] = await client.fetch(forLibraryPage, {
live: !import.meta.env.DEV,
lang: 'en_EN',
});
---
<Layout
title="Biblioteca - Filipe Medeiros"
ptUrl="/biblioteca"
enUrl="/library"
lang="en_EN"
>
<header class="mb-10">
<PageTitle class="mb-3">Library</PageTitle>
<h2>
Livros, artigos, <span class="italic">etc.</span> que já li e que recomendo
ou que quero ler num futuro próximo. Se um item tiver uma marca "<span
class="text-primary-700">✓</span
>", siginifca que eu já li, vi, etc.
</h2>
</header>
<ol>
{
libraryItems.map(({ title, description, link, checkedOut }) => (
<CardLink link={link}>
<span class="text-lg md:text-xl font-medium break-words text-primary-700 block mb-3">
{title}
</span>
<p class="mb-5">{description}</p>
{checkedOut && <span class="text-primary-700 text-3xl">✓</span>}
</CardLink>
))
}
</ol>
<Fragment slot="footer">
<nav class="flex gap-4">
<ButtonLink
href="/blog"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Blog
</ButtonLink>
<ButtonLink
href="/home"
class="text-3xl flex-1 py-2 flex justify-center px-2"
>
Home
</ButtonLink>
</nav>
</Fragment>
</Layout>

View file

@ -18,6 +18,14 @@ export default {
},
},
},
screens: {
xs: '420px',
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1536px',
},
},
plugins: [],
};