translate a better way for consuming content post

This commit is contained in:
Juan Carlos Manzanero Domínguez 2024-10-07 19:55:57 -06:00
parent ad33d51489
commit 9ba7c8416d
9 changed files with 359 additions and 236 deletions

View File

@ -2,6 +2,19 @@ import { Code, RssIcon } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import formatDate from "@/utils/format-date"; import formatDate from "@/utils/format-date";
const locales = {
en: {
developed_by: "Developed by",
build_handcrafted: "Built handcrafted with",
last_build: "Last build",
},
es: {
developed_by: "Desarrollado por",
build_handcrafted: "Construido a mano con",
last_build: "Última build",
},
};
type Props = { type Props = {
lang: "en" | "es"; lang: "en" | "es";
}; };
@ -11,11 +24,11 @@ export default function Footer(props: Props) {
<footer className="border-t border-secondary px-4 py-12 text-center text-sm md:px-16 prose prose-invert min-w-full"> <footer className="border-t border-secondary px-4 py-12 text-center text-sm md:px-16 prose prose-invert min-w-full">
<section> <section>
<p> <p>
Developed by{" "} {locales[props.lang].developed_by}{" "}
<strong className="font-bold text-primary">juancmandev</strong> <strong className="font-bold text-primary">juancmandev</strong>
</p> </p>
<p> <p>
Built handcrafted with{" "} {locales[props.lang].build_handcrafted}{" "}
<Button <Button
asChild asChild
size={null} size={null}
@ -27,7 +40,10 @@ export default function Footer(props: Props) {
</a> </a>
</Button> </Button>
</p> </p>
<p>Last built {formatDate(new Date())}.</p> <p>
{locales[props.lang].last_build}: {formatDate(new Date(), props.lang)}
.
</p>
</section> </section>
<section className="w-max mx-auto flex items-center gap-12"> <section className="w-max mx-auto flex items-center gap-12">
<Button <Button

View File

@ -1,16 +1,19 @@
--- ---
import { marked } from "marked"; import { marked } from "marked";
import formatDate from "@/utils/format-date"; import formatDate from "@/utils/format-date";
import { getLangFromUrl } from "@/i18n/utils";
const props = Astro.props; const props = Astro.props;
const content = marked.parse(props.content); const content = marked.parse(props.content);
const lang = getLangFromUrl(Astro.url);
--- ---
<article class="rounded-md border px-4 py-2"> <article class="rounded-md border px-4 py-2">
<header class="mb-2"> <header class="mb-2">
<section class="flex items-center justify-between text-sm"> <section class="flex items-center justify-between text-sm">
<span class="font-light"> <span class="font-light">
{formatDate(new Date(props.published))}{" "} {formatDate(new Date(props.published), lang)}{" "}
</span> </span>
<span class="text-sm font-thin"> <span class="text-sm font-thin">
{new Date(props.published).toLocaleTimeString()} {new Date(props.published).toLocaleTimeString()}
@ -21,8 +24,7 @@ const content = marked.parse(props.content);
props && props &&
props.expand.tags && props.expand.tags &&
props?.expand.tags.map( props?.expand.tags.map(
(tag: any) => (tag: any) => tag && <span class="text-sm">#{tag.name} </span>,
tag && <span class="text-sm">#{tag.name} </span>,
) )
} }
</section> </section>

View File

@ -53,8 +53,7 @@ you don't open the post link in your RSS Reader.
The good thing is that almost every RSS Reader shows you content sorted by date, The good thing is that almost every RSS Reader shows you content sorted by date,
not by a creepy algorithm that wants you to be mad. not by a creepy algorithm that wants you to be mad.
[For my website](https://github.com/juancmandev/website/blob/main/scripts/rss.ts), For my website I use a Node.js script that takes the `.mdx` files inside `content/blog` and
I use a Node.js script that takes the `.mdx` files inside `content/blog` and
`content/portfolio`, then generates the RSS Items, those with the `rss: true` in `content/portfolio`, then generates the RSS Items, those with the `rss: true` in
the metadata. the metadata.
@ -115,6 +114,7 @@ https://youtube.com/feeds/videos.xml?channel_id=[CHANNEL ID]
- [Astronomic Picture of the Day (apod)](https://apod.com/feed.rss) - [Astronomic Picture of the Day (apod)](https://apod.com/feed.rss)
- [Earth Science Picture of the Day (epod)](https://feeds2.feedburner.com/EarthSciencePictureoftheDay) - [Earth Science Picture of the Day (epod)](https://feeds2.feedburner.com/EarthSciencePictureoftheDay)
- [Erick Murphy (cool guy)](https://ericmurphy.xyz/index.xml) - [Erick Murphy (cool guy)](https://ericmurphy.xyz/index.xml)
- [Luke Smith](https://lukesmith.xyz/index.xml)
## More About RSS ## More About RSS

View File

@ -1,14 +1,114 @@
--- ---
title: Una Mejor Forma de Consumir Contenido title: Una Mejor Forma de Consumir Contenido
description: description: Obtén tus noticias sin visitar websites con algoritmos que muestran contenido que no quieres ver.
Get your news without visiting websites with algorithms that shows content
that you don't want to see.
tags: [Tech] tags: [Tech]
image: /blog/a-better-way-for-consuming-content/banner.webp image: /blog/a-better-way-for-consuming-content/banner.webp
imageCaption: Newspapers. Photo by Ashni on Unsplash imageCaption: Periódicos. Foto de Ashni en Unsplash
date: 2024-4-11 date: 2024-4-11
author: Juan Manzanero author: Juan Manzanero
rss: true rss: true
--- ---
Hola ![Periódicos](@/assets/blog/a-better-way-for-consuming-content/banner.webp) _Foto de
[Ashni](https://unsplash.com/@ashni_ahlawat?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash)
en
[Unsplash](https://unsplash.com/photos/text-ePWaAwUn80k?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash)_
Obtén tus noticias sin visitar websites con algoritmos que muestran contenido que no quieres ver.
## Algoritmos que dictan lo que ves
Las redes sociales no están diseñadas para mostrarte las noticias más novedosas e importantes,
sino para mostrarte contenido dictado por un algoritmo.
Y este contenido es normalmente, viral; y viral no quiere decir interesante.
Normalmente estos algoritmos priorizan contenido que te hacen enojar.
Contenido que promueve la negatividad obtiene más "clicks" que aquel que promueve la positividad.
Esa es la razón por la cual Twitter y Facebook están llenos de posts estúpidos e irrelevantes (por lo regular).
Por supuesto, es genial cuando el algoritmo te muestra contenido que te gusta,
descubriendo nuevas personas y páginas, pero eso no es lo usual.
Sin mencionar los molestos anuncios y más cosas que quieren que les hagas click.
Meta (anteriormente Facebook) sabe sobre esto, y promueve en sus productos como Instagram y Facebook,
lo mismo con Twitter.
## La Solución: News Aggregators (RSS)
RSS es un acrónimo de "Really Simple Syndication".
Es una tecnología antigua, no muy promovida por las compañías.
Esto es debido a que cuando lees un post en un RSS Reader, no debes de visitar el website,
y el website no puede mostrarte anuncios usando Google Ads (por ejemplo). No generas tráfico,
tus visitas no cuentan, al menos no si no abres el link del post en tu RSS Reader.
Lo bueno que casi cualquier RSS Reader te muestra el contenido organizado por fechas,
no por un algoritmo raro que quiere hacerte enojar.
Para mi website utilizo un script en Node.js que toma todos los archivos `.mdx` dentro de `content/blog`
y `content/portfolio`, entonces genera los RSS Items, aquellos con `rss: true` en sus metadatos.
## Cómo usar un RSS Reader
Primero, debes descargar uno.
Hay muchas opciones:
- [NetNewsWire](https://netnewswire.com/): un RSS Reader nativo para macOS y iOS, gratis y Open Source,
mi opción favorita como ~~Pecador~~ usuario de Apple
- [Akregator](https://apps.kde.org/akregator): del proyecto KDE para Linux
- [Feeder](https://play.google.com/store/apps/details?id=com.nononsenseapps.feeder.play): para Android
- [Raven Reader](https://ravenreader.app/): aplicación de escritorio multiplataforma
### Agregando Feeds
Ahora debes buscar por el link RSS de tu website favorito, ¡[como este](https://juancman.dev/es/rss.xml)!
```
https://juancman.dev/es/rss.xml
```
Si lo abres, verás una página rara con código similar a HTML.
Una vez copiado, ve a tu RSS app y busca "Agregar feed" o algo similar, y pega el link, ¡y listo!,
ahora obtendrás los últimos posts de mi website.
### Agregando Feeds de Redes Sociales
Puedes agregar incluso feeds de sitios como Reddit o YouTube.
#### Reddit
Solo cambia `[SUBREDDIT]` por el nombre del subreddit a añadir:
```
https://reddit.com/r/[SUBREDDIT]/new/.rss
```
#### YouTube
Ve a el canal por añadir, luego ve a la pestaña "Acerca de", da click en **Compartir > Copiar ID del Canal**.
Ahora solo cambia `[CHANNEL ID]` por el copiado:
```
https://youtube.com/feeds/videos.xml?channel_id=[CHANNEL ID]
```
### Mis Feeds Favoritos
- [juancman.dev (¡obviamente!)](https://www.juancman.dev/es/rss.xml)
- [Astronomic Picture of the Day (apod)](https://apod.com/feed.rss)
- [Earth Science Picture of the Day (epod)](https://feeds2.feedburner.com/EarthSciencePictureoftheDay)
- [Erick Murphy](https://ericmurphy.xyz/index.xml)
- [Luke Smith](https://lukesmith.xyz/index.xml)
## Más Sobre RSS
- [Privacy Tools - RSS Feed Readers](https://www.privacytools.io/privacy-rss-feed-readers)
- [Privacy Guides - News Aggregators](https://www.privacyguides.org/en/news-aggregators/)

View File

@ -6,6 +6,12 @@ import Layout from "@/layouts/Layout.astro";
import { sortContentByDate } from "@/utils/sorts"; import { sortContentByDate } from "@/utils/sorts";
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
const pageData = {
title: "juancmandev",
description:
"Bienvenido a mi dominio, extraño. Soy juancmandev; Desarrollador Web, entusiasta de Linux, y defensor de la privacidad.",
};
const allPosts = await getCollection("blog", ({ data }) => data.draft !== true); const allPosts = await getCollection("blog", ({ data }) => data.draft !== true);
const allEsPosts = allPosts.map((post) => { const allEsPosts = allPosts.map((post) => {
const [lang, ...slug] = post.slug.split("/"); const [lang, ...slug] = post.slug.split("/");
@ -40,10 +46,7 @@ const last3Projects = allEnProjects.slice(0, 3);
const lang = getLangFromUrl(Astro.url); const lang = getLangFromUrl(Astro.url);
--- ---
<Layout <Layout {...pageData}>
title="juancmandev"
description="Bienvenido a mi dominio, extraño. Soy juancmandev; Desarrollador Web, entusiasta de Linux, y defensor de la privacidad."
>
<div class="prose prose-invert"> <div class="prose prose-invert">
<h1 class="text-primary">Bienvenido a mi dominio, extraño.</h1> <h1 class="text-primary">Bienvenido a mi dominio, extraño.</h1>
<p> <p>
@ -54,9 +57,9 @@ const lang = getLangFromUrl(Astro.url);
> >
</p> </p>
<p> <p>
Este es mi <strong>website</strong>, un pedazo de Internet al que Este es mi <strong>website</strong>, un pedazo de Internet al que puedo
puedo llamar <strong>hogar</strong>. Aquí comparto mi pasión por llamar <strong>hogar</strong>. Aquí comparto mi pasión por proyectos open
proyectos open source y otros temas. source y otros temas.
</p> </p>
<section> <section>
<h2>Últimos posts</h2> <h2>Últimos posts</h2>
@ -78,10 +81,8 @@ const lang = getLangFromUrl(Astro.url);
) )
} }
</ul> </ul>
<LinkButton <LinkButton variant="secondary" href="/blog" className="no-underline"
variant="secondary" >Más posts</LinkButton
href="/blog"
className="no-underline">Más posts</LinkButton
> >
</section> </section>
<section> <section>
@ -104,10 +105,8 @@ const lang = getLangFromUrl(Astro.url);
) )
} }
</ul> </ul>
<LinkButton <LinkButton variant="secondary" href="/portfolio" className="no-underline"
variant="secondary" >Más proyectos</LinkButton
href="/portfolio"
className="no-underline">More projects</LinkButton
> >
</section> </section>
</div> </div>

View File

@ -4,6 +4,7 @@ import { getCollection } from "astro:content";
import components from "@/components/mdx/wrapper"; import components from "@/components/mdx/wrapper";
import formatDate from "@/utils/format-date"; import formatDate from "@/utils/format-date";
import type { CollectionEntry } from "astro:content"; import type { CollectionEntry } from "astro:content";
import { getLangFromUrl } from "@/i18n/utils";
interface Props { interface Props {
project: CollectionEntry<"videos">; project: CollectionEntry<"videos">;
@ -12,7 +13,7 @@ interface Props {
export async function getStaticPaths() { export async function getStaticPaths() {
const allProjects = await getCollection( const allProjects = await getCollection(
"videos", "videos",
({ data }) => data.draft !== true ({ data }) => data.draft !== true,
); );
return allProjects.map((project) => ({ return allProjects.map((project) => ({
@ -23,6 +24,8 @@ export async function getStaticPaths() {
const { project } = Astro.props; const { project } = Astro.props;
const { Content } = await project.render(); const { Content } = await project.render();
const lang = getLangFromUrl(Astro.url);
--- ---
<Layout title={project.data.title} description={project.data.description}> <Layout title={project.data.title} description={project.data.description}>
@ -32,7 +35,7 @@ const { Content } = await project.render();
<hr /> <hr />
<p> <p>
<strong>Posted: </strong> <strong>Posted: </strong>
{project.data.date && formatDate(new Date(project.data.date))} {project.data.date && formatDate(new Date(project.data.date), lang)}
</p> </p>
</article> </article>
</Layout> </Layout>

View File

@ -1,5 +1,6 @@
--- ---
import PostItem from "@/components/post-item"; import PostItem from "@/components/post-item";
import { getLangFromUrl } from "@/i18n/utils";
import Layout from "@/layouts/Layout.astro"; import Layout from "@/layouts/Layout.astro";
import { sortContentByDate } from "@/utils/sorts"; import { sortContentByDate } from "@/utils/sorts";
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
@ -11,9 +12,11 @@ const pageData = {
const allVideos = await getCollection( const allVideos = await getCollection(
"videos", "videos",
({ data }) => data.draft !== true ({ data }) => data.draft !== true,
); );
sortContentByDate(allVideos); sortContentByDate(allVideos);
const lang = getLangFromUrl(Astro.url);
--- ---
<Layout {...pageData}> <Layout {...pageData}>
@ -26,6 +29,7 @@ sortContentByDate(allVideos);
allVideos.map((video: any) => ( allVideos.map((video: any) => (
<li> <li>
<PostItem <PostItem
lang={lang}
type="es/videos" type="es/videos"
slug={video.slug} slug={video.slug}
date={video.data.date!} date={video.data.date!}

View File

@ -6,6 +6,12 @@ import PostItem from "@/components/post-item";
import { sortContentByDate } from "@/utils/sorts"; import { sortContentByDate } from "@/utils/sorts";
import { getLangFromUrl } from "@/i18n/utils"; import { getLangFromUrl } from "@/i18n/utils";
const pageData = {
title: "juancmandev",
description:
"Welcome to my domain, stranger. I am juancmandev; Web Developer, Linux enthusiast, and privacy defender.",
};
const allPosts = await getCollection("blog", ({ data }) => data.draft !== true); const allPosts = await getCollection("blog", ({ data }) => data.draft !== true);
const allEnPosts = allPosts.map((post) => { const allEnPosts = allPosts.map((post) => {
const [lang, ...slug] = post.slug.split("/"); const [lang, ...slug] = post.slug.split("/");
@ -40,10 +46,7 @@ const last3Projects = allEnProjects.slice(0, 3);
const lang = getLangFromUrl(Astro.url); const lang = getLangFromUrl(Astro.url);
--- ---
<Layout <Layout {...pageData}>
title="juancmandev"
description="Welcome to my domain, stranger. I am juancmandev; Web Developer, Linux enthusiast, and privacy defender."
>
<div class="prose prose-invert"> <div class="prose prose-invert">
<h1 class="text-primary">Welcome to my domain, stranger.</h1> <h1 class="text-primary">Welcome to my domain, stranger.</h1>
<p> <p>
@ -52,9 +55,9 @@ const lang = getLangFromUrl(Astro.url);
>, <strong>Linux</strong> enthusiast, and <strong>privacy</strong> defender. >, <strong>Linux</strong> enthusiast, and <strong>privacy</strong> defender.
</p> </p>
<p> <p>
This is my <strong>website</strong>, a piece of the Internet that I This is my <strong>website</strong>, a piece of the Internet that I could
could call my <strong>home base</strong>. Here, I share my passion call my <strong>home base</strong>. Here, I share my passion about open
about open source projects and other topics. source projects and other topics.
</p> </p>
<section> <section>
<h2>Latest posts</h2> <h2>Latest posts</h2>
@ -73,10 +76,8 @@ const lang = getLangFromUrl(Astro.url);
)) ))
} }
</ul> </ul>
<LinkButton <LinkButton variant="secondary" href="/blog" className="no-underline"
variant="secondary" >More posts</LinkButton
href="/blog"
className="no-underline">More posts</LinkButton
> >
</section> </section>
<section> <section>
@ -99,10 +100,8 @@ const lang = getLangFromUrl(Astro.url);
) )
} }
</ul> </ul>
<LinkButton <LinkButton variant="secondary" href="/portfolio" className="no-underline"
variant="secondary" >More projects</LinkButton
href="/portfolio"
className="no-underline">More projects</LinkButton
> >
</section> </section>
</div> </div>

View File

@ -20,7 +20,7 @@ const allEnProjects = allProjects.map((project) => {
if (lang === "en") if (lang === "en")
return { return {
...project, ...project,
slug: slug, slug: slug.toString(),
}; };
else null; else null;
}); });