Learn how to create a multi-language blog with Remix JS

Learn how to create a multi-language blog with Remix JS

Creating a multi language blog with Remix JS

Posted by Yakub Ali Siyam on December 31, 2021

so that it can set up everything for you:

In this article, we will learn how to build a multi-language blog using Remix JS. I will be guiding you throughout the entire process step by step.

Let's get started with Remix.

Prerequisites

The requirements are pretty simple:

  • Make sure you have node installed
  • Basic understanding of React
  • Basic terminal knowledge

Installation

npx create-remix@latest

Choose the folder name you want to install:

Remix installation

Pick the Remix App Server option, which is the built-in server (you can change that later):

Remix installation

Pick Javascript to simply copy-paste the code from this tutorial.

Remix installation

Make sure you tell the installer to run

npm install

Remix installation

Then cd foldername

Run remix npm run dev

Remix installation

For more information about Remix, visit remix.run!

Create A Blog Page:

The app folder contains our main app logic. All the folders and files under the routes folder are exposed to the public and can be accessed with a URL.

root.jsx — It’s the main component of our app. It contains our general page layout and Bootstrap CDN.


import { Outlet, LiveReload, Link, Links, Meta } from '@remix-run/react';

export const links = () => [
  // Bootstrap CSS CDN
  {
    rel: 'stylesheet',
    href: 'https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css',
  },
];

export const meta = () => {
  return {
    description: 'A multi-language blog built with Remix',
  };
};

export default function App() {
  return (
    <Document>
      <Layout>
        <Outlet />
      </Layout>
    </Document>
  );
}

function Document({ children, title }) {
  return (
    <html>
      <head>
        <Meta />
        <Links />
        <title>Blog</title>
      </head>
      <body>
        {children}
        {process.env.NODE_ENV === 'development' ? <LiveReload /> : null}

        {/* Bootstrap JS CDN */}
        <script
          src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
          integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
          crossOrigin="anonymous"
        ></script>
      </body>
    </html>
  );
}

function Layout({ children }) {
  return (
    <>
      {/* Navbar */}
      <nav className="navbar navbar-expand-lg navbar-light bg-info">
        <div className="container">
          <Link
            className="navbar-brand text-color fw-bold"
            to="/"
            style={{ color: 'RGBA(0,0,0,.55)' }}
          >
            Blog
          </Link>
          <button
            className="navbar-toggler"
            type="button"
            data-bs-toggle="collapse"
            data-bs-target="#navbarTogglerDemo02"
            aria-controls="navbarTogglerDemo02"
            aria-expanded="false"
            aria-label="Toggle navigation"
          >
            <span className="navbar-toggler-icon"></span>
          </button>
          <div className="collapse navbar-collapse" id="navbarTogglerDemo02">
            <ul className="navbar-nav ms-auto mb-2 mb-lg-0 fw-bold">
              <li class="nav-item">
                <Link to="/en" class="nav-link">
                  English
                </Link>
              </li>
              <li class="nav-item">
                <Link to="/es" class="nav-link">
                  Español
                </Link>
              </li>
            </ul>
          </div>
        </div>
      </nav>

      <div className="container p-4">{children}</div>
    </>
  );
}

export function ErrorBoundary({ error }) {
  console.log(error);
  return (
    <Document>
      <Layout>
        <h1 className="text-center">Error</h1>
        <p className="text-center">{error.message}</p>
      </Layout>
    </Document>
  );
}

Home Page : Create a new file here, app/routes/index.jsx. It is the homepage of our blog website.


import { redirect } from '@remix-run/server-runtime';

export function loader({ request }) {
  let languageHeader = request.headers.get('accept-language');
  let locale = languageHeader?.split(',')[0] || 'en';
  let language = locale.split('-')[0];

  if (!['en', 'es'].includes(language)) {
    language = 'en';
  }

  return redirect(`/${language}`);
}

Articles Component —

Install Polyblog API:

npm install @polyblog/polyblog-js-client

We will write our code to display all the blogs we fetched from Polyblog API and display it. To find the articles go to localhost:3000/en find english articles, go to localhost:3000/es find spanish articles.

Create a folder app/routes/$locale
Create a file app/routes/$locale/index.jsx


import { getArticles } from '@polyblog/polyblog-js-client';
import { useLoaderData, Link } from '@remix-run/react';

export const loader = async ({ params }) => {
  const locale = params.locale;
  let articles = await getArticles({
    // signup at https://www.polyblog.io/signup to get your blogId
    blogId: '4217f90b8eaa86551e7f7d55',
    published: true,
    locale,
  });

  return articles;
};

export default function BlogPage() {
  const article = useLoaderData();
  return (
    <>
      <div className="row row-cols-1 row-cols-md-2 g-4">
        {article.map(
          ({
            _id,
            locale,
            slugLocalized,
            coverUrl,
            title,
            author,
            creationTime,
            subtitle,
          }) => (
            <div key={_id} className="col-md-6 col-lg-4 col-12">
              <Link
                key={_id}
                to={`/${locale}/${slugLocalized}`}
                className="text-decoration-none"
              >
                <div className="card h-100 shadow">
                  <img src={coverUrl} className="card-img-top" alt={title} />
                  <div className="card-body">
                    <h3 className="card-title my-3 text-dark">{title}</h3>
                    <h5 className="my-3 text-dark">{subtitle}</h5>
                    <p className="text-dark">
                      Posted by {author} on{' '}
                      {new Date(creationTime).toLocaleString(locale, {
                        dateStyle: 'long',
                      })}
                    </p>
                  </div>
                </div>
              </Link>
            </div>
          ),
        )}
      </div>
    </>
  );
}

Displaying a detailed article:

Create a file app/routes/$locale/$slug.jsx

It is the component that fetches a single article and displays it on a separate page.Goto localhost:3000/en/:slug to find a detailed blog.


import { getArticles } from '@polyblog/polyblog-js-client';
import { useLoaderData } from '@remix-run/react';

export const loader = async ({ params }) => {
  const { locale, slug } = params;

  const articles = await getArticles({
    // signup at https://www.polyblog.io/signup to get your blogId
    blogId: '4217f90b8eaa86551e7f7d55',
    locale,
    slugLocalized: slug,
  });

  const article = articles?.[0];
  return article;
};

export default function ArticlePage() {
  const article = useLoaderData();
  return (
    <div>
      {article && (
        <>
          <div
            style={{
              width: '100%',
              height: '400px',
              backgroundImage: `url(${article?.coverUrl})`,
              backgroundSize: 'cover',
            }}
            className="mb-5"
          >
            <h2 className="text-center pt-5">{article?.title}</h2>
            <h4 className="text-center pt-3">{article?.subtitle}</h4>
            <p className="text-center">
              <i>
                Posted by <span>{article?.author}</span> on{' '}
                <span>
                  {new Date(article?.creationTime).toLocaleDateString()}
                </span>
              </i>
            </p>
          </div>

          <style>
            {`article img {
                max-width: 512px;
                display: block;
                margin-left: auto;
                margin-right: auto;
              }`}
          </style>

          <article dangerouslySetInnerHTML={{ __html: article?.content }} />
        </>
      )}
    </div>
  );
}

Signup at https://app.polyblog.io/signup to get your blogId to enter in the code above.

After signing up visit the page Settings to find the id of your blog (ex. 1234567890abcdef12345678)

Our folder structure looks like this

Remix blog folder structure
Folder structure of this project

Conclusion

Here in this article, I have described how you can add articles to any Remix website using the API provided by Polyblog. We have successfully created our multilingual blog with Polyblog API and it made it easier for us. You can find more information on the API parameters supported in the Polyblog API Reference.

Thank you for going through this tutorial! If you are stuck on any step, refer to this github repo and find your problem.

Happy Coding!!!

Sign up for our newsletter

Recent articles