123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- /* eslint-disable no-console */
- /* eslint-disable max-lines */
- /* eslint-disable jsdoc/require-returns */
- /* eslint-disable import/no-extraneous-dependencies */
- /* eslint-disable react-func/max-lines-per-function */
- /* eslint-disable global-require */
- /* eslint-disable import/no-dynamic-require */
- const range = require('lodash/range');
- const fetch = require('node-fetch');
- const englishChaptersData = require('./data/chapters/en.json');
- const { locales } = require('./i18n.json');
- const isProduction = process.env.NEXT_PUBLIC_VERCEL_ENV === 'production';
- const isDevelopment = process.env.NEXT_PUBLIC_VERCEL_ENV === 'development';
- const shouldGenerateAdditionalPaths =
- process.env.NEXT_PUBLIC_GENERATE_SITEMAP_ADDITIONAL_PATHS === 'true';
- const BASE_PATH =
- `${isDevelopment ? 'http' : 'https'}://${process.env.NEXT_PUBLIC_VERCEL_URL}` ||
- 'https://quran.com';
- const BASE_AUTH_PATH = process.env.NEXT_PUBLIC_AUTH_BASE_URL;
- const chapters = range(1, 115);
- const getAvailableCourses = async () => {
- const res = await fetch(`${BASE_AUTH_PATH}/courses`);
- const data = await res.json();
- return data;
- };
- const getAvailableTafsirs = async () => {
- const res = await fetch(`https://api.qurancdn.com/api/qdc/resources/tafsirs`);
- const data = await res.json();
- return data;
- };
- const getAvailableReciters = async () => {
- const res = await fetch(`https://api.qurancdn.com/api/qdc/audio/reciters`);
- const data = await res.json();
- return data;
- };
- /**
- * Get the alternate ref objects for a path. We append "-remove-from-here" because
- * next-sitemap library appends the alternate ref to the beginning
- * of the url of the English version rather than replacing it completely.
- * e.g. for english the url is /surah/al-fatihah/info
- * but for Arabic it becomes /ar/surah/سورة-الفاتحة/info/surah/al-fatihah/info
- * although we don't want "surah/al-fatihah/info" part at the end of the path.
- * so appending "-remove-from-here" indicator would make it easier for us to manually
- * process the .xml file and remove the characters starting from "-remove-from-here".
- * e.g. /ar/سورة-الفاتحة/1-remove-from-here/al-fatihah/1
- *
- * @param {number} chapterId
- * @param {boolean} appendSlug
- * @param {string} prefix
- * @param {string} suffix
- */
- const getAlternateRefs = (chapterId = null, appendSlug = true, prefix = '', suffix = '') => {
- return locales.map((locale) => {
- let href = `${BASE_PATH}/${locale}`;
- if (prefix) {
- href = `${href}/${prefix}`;
- }
- if (appendSlug) {
- const localeChaptersData = require(`./data/chapters/${locale}.json`);
- href = `${href}/${localeChaptersData[chapterId].slug}`;
- }
- if (suffix) {
- href = `${href}/${suffix}`;
- }
- return {
- href: `${href}-remove-from-here`,
- hreflang: locale,
- };
- });
- };
- module.exports = {
- siteUrl: BASE_PATH,
- sitemapSize: 20000,
- generateRobotsTxt: isProduction,
- exclude: [
- ...locales.map((locale) => `/${locale}`),
- '/*/product-updates*',
- '/*/search',
- '/*my-learning-plans',
- ],
- alternateRefs: locales.map((locale) => ({
- href: `${BASE_PATH}/${locale}`,
- hreflang: locale,
- })),
- transform: async (config, path) => {
- return {
- loc: path,
- lastmod: new Date().toISOString(),
- alternateRefs: config.alternateRefs ?? [],
- };
- },
- additionalPaths: shouldGenerateAdditionalPaths
- ? async (config) => {
- const result = [];
- let tafsirSlugs = [];
- let reciterIds = [];
- await getAvailableTafsirs().then((response) => {
- tafsirSlugs = response.tafsirs.map((tafsir) => tafsir.slug);
- });
- await getAvailableReciters().then((response) => {
- reciterIds = response.reciters.map((reciter) => reciter.id);
- });
- chapters.forEach((chapterId) => {
- // 1. add the chapter slugs in English along with the localized slugs in every locale
- const englishChapterSlug = englishChaptersData[chapterId].slug;
- result.push({
- loc: `/${englishChapterSlug}`,
- alternateRefs: getAlternateRefs(chapterId),
- });
- // 2. add slugged /surah/[chapterSlug]/info in English along with the localized slugs in every locale
- result.push({
- loc: `/surah/${englishChapterSlug}/info`,
- alternateRefs: getAlternateRefs(chapterId, true, 'surah', 'info'),
- });
- // 3. /reciters/[reciterId]/[chapterSlug]
- reciterIds.forEach((reciterId) => {
- const location = `/reciters/${reciterId}/${englishChapterSlug}`;
- result.push({
- loc: location,
- alternateRefs: getAlternateRefs(chapterId, false, '', location),
- });
- });
- // 4. generate the verses for each of the chapters in each locale as well
- range(englishChaptersData[chapterId].versesCount).forEach((verseId) => {
- const verseNumber = verseId + 1;
- const verseIdValue = verseNumber;
- const verseKey = `${chapterId}:${verseIdValue}`;
- const isAyatulKursi = chapterId === 2 && verseNumber === 255;
- if (isAyatulKursi) {
- // instead of /al-baqarah/255, we push /ayatul-kursi
- result.push({
- loc: `/ayatul-kursi`,
- alternateRefs: getAlternateRefs(null, false, '', 'ayatul-kursi'),
- });
- } else {
- result.push({
- loc: `/${englishChapterSlug}/${verseIdValue}`,
- alternateRefs: getAlternateRefs(chapterId, true, '', verseIdValue),
- });
- }
- // 5. add /[chapterId]/[verseId]/tafsirs route
- result.push({
- loc: `/${englishChapterSlug}/${verseIdValue}/tafsirs`,
- alternateRefs: getAlternateRefs(chapterId, true, '', `${verseIdValue}/tafsirs`),
- });
- // 6. /[verseKey]/tafsirs/[tafsirSlug]
- tafsirSlugs.forEach((tafsirSlug) => {
- const location = `${verseKey}/tafsirs/${tafsirSlug}`;
- result.push({
- loc: location,
- alternateRefs: getAlternateRefs(chapterId, false, '', location),
- });
- });
- // 7. /[verseKey]/reflections
- const reflectionsLocation = `${verseKey}/reflections`;
- result.push({
- loc: reflectionsLocation,
- alternateRefs: getAlternateRefs(chapterId, false, '', reflectionsLocation),
- });
- });
- });
- // 7. /juz/[juzId]
- range(1, 31).forEach(async (juzId) => {
- result.push(await config.transform(config, `/juz/${juzId}`));
- });
- // 8. /hizb/[hizbId]
- range(1, 61).forEach(async (hizbId) => {
- result.push(await config.transform(config, `/hizb/${hizbId}`));
- });
- // 9. /rub/[rubId]
- range(1, 241).forEach(async (rubId) => {
- result.push(await config.transform(config, `/rub/${rubId}`));
- });
- // 10. /page/[pageId]
- range(1, 605).forEach(async (pageId) => {
- result.push(await config.transform(config, `/page/${pageId}`));
- });
- // 11. /reciters/[reciterId]
- reciterIds.forEach((reciterId) => {
- const location = `/reciters/${reciterId}`;
- result.push({
- loc: location,
- alternateRefs: getAlternateRefs('', false, '', location),
- });
- });
- // 12. /learning-plans/[learningPlanSlug]
- const learningPlans = await getAvailableCourses();
- // TODO: handle pagination in the future when we have more than 10 learning plans
- learningPlans.data.forEach((learningPlan) => {
- const location = `/learning-plans/${learningPlan.slug}`;
- // TODO: handle per language learning plans e.g. Arabic learning plan should only show under /ar/[learning-plan-slug]
- result.push({
- loc: location,
- alternateRefs: getAlternateRefs('', false, '', location),
- });
- });
- return result;
- }
- : async () => {
- console.log('Skipping additional paths generation...');
- return Promise.resolve([]);
- },
- };
|