Create Algolia i18n indices

Create Algolia i18n indices

Published on November 8, 2023 (2y ago)

Let's say we're creating an index for posts in two locales: en and de. We'll need to create two indices: indexName-en and indexName-de. Each index will contain posts in the respective locale.

1. Fetch data from Sanity for each locale

// lib/sanity.ts

import groq from 'groq'
import { createClient } from 'next-sanity'

// Hereinafter I've omitted explicit type definitions for brevity

const sanityClient = createClient({
  apiVersion: process.env.SANITY_API_VERSION,
  dataset: process.env.SANITY_DATASET,
  projectId: process.env.SANITY_PROJECT_ID
})

const query = groq`*[_type == "post" && !(_id in path("drafts.**")] {
    "objectID": _id,
    "title": title[$locale],
    "slug": slug.current,
  }`

export async function getPostsForLocale(
  locale: 'en' | 'de'
): Promise<IPost[]> {
  const data = await sanityClient.fetch(query, { locale })
  return data
}

2. Create a script that runs the index creation process for each locale.

// scripts/createIndex.ts

import algoliasearch from 'algoliasearch'

import { getPostsForLocale } from '@/lib/sanity'

const algoliaInstance = algoliasearch(
  process.env.ALGOLIA_APP_ID!,
  process.env.ALGOLIA_SEARCH_ADMIN_KEY!
)

const ALGOLIA_INDICES = [
  {
    indexName: 'indexName-en',
    locale: 'en'
  },
  {
    indexName: 'indexName-de',
    locale: 'de'
  }
]

async function createIndexForLocale(indexName, locale) {
  try {
    const index = algoliaInstance.initIndex(indexName)
    const data = await getPostsForLocale(locale)
    await index.saveObjects(indexData)
    console.log(
      `Saved ${data.length} docs to index: ${index.indexName}`
    )
    return {
      status: 200,
      body: 'Success!'
    }
  } catch (error) {
    console.error(error)
    return {
      status: 500,
      body: error
    }
  }
}

export default async function createIndex() {
  const promises = ALGOLIA_INDICES.map(({ indexName, locale }) =>
    createIndexForLocale(indexName, locale)
  )
  const results = await Promise.all(promises)
  return results
}

3. Create a route handler to run the script

// api/cron/route.ts

import createIndex from '@/scripts/createIndex'

export async function GET(req: Request) {
  if (
    req.headers.get('Authorization') !==
    `Bearer ${process.env.CRON_SECRET}`
  ) {
    return new Response(`Unauthorized`, { status: 401 })
  }
  try {
    await generateIndex()
    return new Response('Algolia index re-created', {
      status: 200
    })
  } catch (e) {
    const serializedError =
      e instanceof Error
        ? JSON.stringify(e, Object.getOwnPropertyNames(e))
        : 'Unknown error'
    return new Response(serializedError, { status: 500 })
  }
}

4. Setup Cron Job

Create a vercel.json file in your project's root directory

{
  "crons": [
    {
      "path": "/api/cron",
      "schedule": "0 0 * * 0"
    }
  ]
}

Cron is scheduled to run every Sunday at midnight. You can use crontab.guru to generate your own schedule.

5. Deploy to Vercel and test it out by running cron manually.

Vercel project settings
Vercel project settings
💡

Alternatively, you can choose to omit steps 3-5 and execute the script from step 2 directly as part of the build process.