Files
freeCodeCamp/client/tools/generate-search-placeholder.ts
2025-09-19 13:28:06 +05:30

116 lines
3.2 KiB
TypeScript

import { writeFileSync, readdirSync, lstatSync } from 'fs';
import { join, resolve } from 'path';
import algoliasearch from 'algoliasearch';
import i18n from 'i18next';
import backend from 'i18next-fs-backend';
import {
algoliaAppId,
algoliaAPIKey,
clientLocale,
environment
} from '../config/env.json';
import { newsIndex } from '../src/utils/algolia-locale-setup';
import { i18nextCodes } from '../../shared-dist/config/i18n';
const i18nextCode = i18nextCodes[clientLocale as keyof typeof i18nextCodes];
i18n
.use(backend)
.init({
defaultNS: 'translations',
fallbackLng: 'en',
interpolation: {
escapeValue: false
},
initImmediate: false,
preload: readdirSync(join(__dirname, '../i18n/locales')).filter(
fileName => {
const joinedPath = join(join(__dirname, '../i18n/locales'), fileName);
const isDirectory = lstatSync(joinedPath).isDirectory();
return isDirectory;
}
),
lng: i18nextCode,
ns: ['translations'],
backend: {
loadPath: resolve(
__dirname,
`../i18n/locales/${clientLocale}/translations.json`
)
}
})
.catch((error: Error) => {
throw Error(error.message);
});
const t = i18n.t.bind(i18n);
export const roundDownToNearestHundred = (num: number) =>
Math.floor(num / 100) * 100;
export const convertToLocalizedString = (num: number, ISOCode: string) =>
num.toLocaleString(ISOCode);
interface GenerateSearchPlaceholderOptions {
locale?: string;
mockRecordsNum?: number;
}
export const generateSearchPlaceholder = async (
options: GenerateSearchPlaceholderOptions = {}
) => {
const { locale, mockRecordsNum } = options;
let placeholderText = t('search.placeholder.default');
try {
let totalRecords = mockRecordsNum || 0;
if (!mockRecordsNum) {
const algoliaClient = algoliasearch(algoliaAppId, algoliaAPIKey);
const index = algoliaClient.initIndex(newsIndex);
const res = await index.search('');
totalRecords = res.nbHits;
}
const roundedTotalRecords = roundDownToNearestHundred(totalRecords);
if (roundedTotalRecords >= 100) {
placeholderText = i18n.t('search.placeholder.numbered', {
roundedTotalRecords: convertToLocalizedString(
roundedTotalRecords,
i18nextCode
)
});
}
} catch (_err) {
if (environment === 'production') {
console.warn(`
----------------------------------------------------------
Warning: Could not get the total number of Algolia records
----------------------------------------------------------
Make sure that Algolia keys and index are set up correctly.
Falling back to the default search placeholder text.
----------------------------------------------------------
`);
}
}
writeFileSync(
resolve(
__dirname,
`../i18n/locales/${locale ? locale : clientLocale}/search-bar.json`
),
JSON.stringify({
placeholder: placeholderText
})
);
return placeholderText; // for testing
};
void generateSearchPlaceholder();
// TODO: remove the need to fallback to english once we're confident it's
// unnecessary (client/i18n/config.js will need all references to 'en' removing)
if (clientLocale !== 'english')
void generateSearchPlaceholder({ locale: 'english' });