mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-25 22:19:28 -04:00
133 lines
4.7 KiB
TypeScript
133 lines
4.7 KiB
TypeScript
import assert from 'assert';
|
|
|
|
import { Router } from 'express';
|
|
import fetch from 'node-fetch';
|
|
|
|
import type { PronounExamplesData } from '../../locale/data.ts';
|
|
import { buildPronoun, buildPronounUsage, parsePronounGroups, parsePronouns } from '../../src/buildPronoun.ts';
|
|
import { Example, PronounLibrary } from '../../src/classes.ts';
|
|
import type { Pronoun } from '../../src/classes.ts';
|
|
import { buildList, handleErrorAsync } from '../../src/helpers.ts';
|
|
import { Translator } from '../../src/translator.ts';
|
|
import { loadTsv } from '../../src/tsv.ts';
|
|
import { loadSuml, loadSumlFromBase } from '../loader.ts';
|
|
|
|
import type { LocaleDescription } from '~/locale/locales.ts';
|
|
import { rootDir } from '~/server/paths.ts';
|
|
|
|
const translations = loadSuml('translations');
|
|
const baseTranslations = loadSumlFromBase('locale/_base/translations');
|
|
|
|
const translator = new Translator(translations, baseTranslations, global.config);
|
|
|
|
const pronouns = parsePronouns(global.config, loadTsv(`${rootDir}/data/pronouns/pronouns.tsv`));
|
|
const pronounGroups = parsePronounGroups(loadTsv(`${rootDir}/data/pronouns/pronounGroups.tsv`));
|
|
const pronounLibrary = new PronounLibrary(global.config, pronounGroups, pronouns);
|
|
|
|
const buildExample = (e: PronounExamplesData): Example => new Example(
|
|
Example.parse(e.singular),
|
|
Example.parse(e.plural || e.singular),
|
|
Example.parse(e.null || e.singular),
|
|
Example.parse(e.null_plural || e.plural || e.singular),
|
|
e.isHonorific,
|
|
);
|
|
|
|
const requestExamples = (r: string[] | undefined): PronounExamplesData[] => {
|
|
if (!r || !r.length) {
|
|
return loadTsv(`${rootDir}/data/pronouns/examples.tsv`);
|
|
}
|
|
|
|
return buildList(function* () {
|
|
for (const rr of r) {
|
|
const [singular, plural, isHonorific] = rr.split('|');
|
|
yield { singular, plural, isHonorific: !!isHonorific };
|
|
}
|
|
});
|
|
};
|
|
|
|
const addExamples = (pronoun: Pronoun, examples: PronounExamplesData[]): string[] => {
|
|
return buildList(function* () {
|
|
for (const example of examples) {
|
|
yield buildExample(example).format(pronoun);
|
|
}
|
|
});
|
|
};
|
|
|
|
interface PublicPronoun extends Omit<Pronoun, 'config' | 'hidden' | 'name'> {
|
|
examples: string[];
|
|
name: string;
|
|
}
|
|
|
|
const makePublicPronoun = (pronoun: Pronoun, examples: string[] | undefined): PublicPronoun => {
|
|
const publicPronoun: any = pronoun.clone();
|
|
publicPronoun.examples = addExamples(pronoun, requestExamples(examples));
|
|
publicPronoun.name = pronoun.name();
|
|
delete publicPronoun.config;
|
|
delete publicPronoun.hidden;
|
|
return publicPronoun;
|
|
};
|
|
|
|
const router = Router();
|
|
|
|
router.get('/pronouns', handleErrorAsync(async (req, res) => {
|
|
const publicPronouns: Record<string, PublicPronoun> = {};
|
|
for (const [name, pronoun] of Object.entries(pronouns)) {
|
|
if (pronoun.hidden) {
|
|
continue;
|
|
}
|
|
publicPronouns[name] = makePublicPronoun(pronoun, req.query.examples as string[] | undefined);
|
|
}
|
|
return res.json(publicPronouns);
|
|
}));
|
|
|
|
router.get('/pronouns/:pronoun*', handleErrorAsync(async (req, res) => {
|
|
const pronoun = buildPronoun(
|
|
pronouns,
|
|
req.params.pronoun + req.params[0],
|
|
global.config,
|
|
translator,
|
|
);
|
|
if (!pronoun) {
|
|
return res.status(404).json({ error: 'Not found' });
|
|
}
|
|
return res.json(makePublicPronoun(pronoun, req.query.examples as string[] | undefined));
|
|
}));
|
|
|
|
router.get('/pronouns-name/:pronoun*', handleErrorAsync(async (req, res) => {
|
|
const path = (req.params.pronoun + req.params[0]).split('/')
|
|
.map((p) => decodeURIComponent(p))
|
|
.join('/');
|
|
const usage = buildPronounUsage(pronounLibrary, path, global.config, translator);
|
|
if (usage === null) {
|
|
return res.status(404).json({ error: 'Not found' });
|
|
}
|
|
return res.json(usage.short.options.join(usage.short.glue));
|
|
}));
|
|
|
|
const getPronounName = defineCachedFunction(async (
|
|
locale: string,
|
|
pronoun: string,
|
|
locales: Record<string, LocaleDescription>,
|
|
) => {
|
|
const encodedPronoun = pronoun.split('/')
|
|
.map((p) => encodeURIComponent(p))
|
|
.join('/');
|
|
const res = await (await fetch(`${locales[locale].url}/api/pronouns-name/${encodedPronoun}`)).json();
|
|
if (typeof res === 'object' && res.error) {
|
|
return pronoun;
|
|
}
|
|
return res;
|
|
}, {
|
|
name: 'pronouns-name',
|
|
getKey: (locale, pronoun) => `${locale}:${pronoun}`,
|
|
maxAge: 24 * 60 * 60,
|
|
});
|
|
|
|
router.get('/remote-pronouns-name/:locale/:pronoun*', handleErrorAsync(async (req, res) => {
|
|
assert(Object.hasOwn(req.locales, req.params.locale));
|
|
const pronoun = req.params.pronoun + req.params[0];
|
|
return res.json(await getPronounName(req.params.locale, pronoun, req.locales));
|
|
}));
|
|
|
|
export default router;
|