mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-23 20:54:48 -04:00
feat(rewrite): Start implementing name algorithm
This commit is contained in:
parent
29fe79bdf7
commit
bc2abe50fa
@ -87,8 +87,8 @@ export function isLocaleActive(localeCode: string): boolean {
|
||||
|
||||
export interface Pronoun {
|
||||
keys: Array<string>;
|
||||
description: string;
|
||||
history: string;
|
||||
description?: string;
|
||||
history?: string;
|
||||
source?: string;
|
||||
isNormative: boolean;
|
||||
isPlural: boolean;
|
||||
@ -99,6 +99,39 @@ export interface Pronoun {
|
||||
smallForm?: string;
|
||||
|
||||
forms: Record<string, { written: string; pronounced: string }>;
|
||||
|
||||
canonicalName: string;
|
||||
}
|
||||
|
||||
export function parsePronounFromParts(
|
||||
parts: Array<string>,
|
||||
forms: Array<string>
|
||||
): Pronoun | null {
|
||||
if (parts.length !== forms.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pronounForms: Pronoun["forms"] = {};
|
||||
for (let i = 0; i < forms.length; i++) {
|
||||
const form = parts[i].split("|");
|
||||
pronounForms[forms[i]] = {
|
||||
written: form[0],
|
||||
pronounced: form[1],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
forms: pronounForms,
|
||||
isNormative: false,
|
||||
keys: [],
|
||||
isPronounceable: false,
|
||||
isPlural: false,
|
||||
isPluralHonorific: false,
|
||||
canonicalName: `${parts[0]}/${parts[1]}`,
|
||||
};
|
||||
}
|
||||
export function parsePronounFromString(s: string, forms: Array<string>) {
|
||||
return parsePronounFromParts(s.split("/"), forms);
|
||||
}
|
||||
|
||||
export interface PronounExample {
|
||||
@ -162,7 +195,7 @@ export class Locale {
|
||||
}
|
||||
}
|
||||
|
||||
private _config: unknown | null = null;
|
||||
private _config: any | null = null;
|
||||
private _translations: unknown | null = null;
|
||||
private _pronouns: Array<Pronoun> = [];
|
||||
private _pronounsByAlias: Record<string, number> = {};
|
||||
@ -261,6 +294,7 @@ export class Locale {
|
||||
for (const key of obj.keys) {
|
||||
this._pronounsByAlias[key] = i;
|
||||
}
|
||||
obj.canonicalName = obj.keys[0];
|
||||
}
|
||||
const examples = await this.readFile(
|
||||
["pronouns/examples.tsv"],
|
||||
@ -302,9 +336,67 @@ export class Locale {
|
||||
return this._pronouns[index];
|
||||
}
|
||||
|
||||
public pronounNameVariants(pronoun: Pronoun): Array<string> {
|
||||
// NOTE(tecc): This is an attempt at decoding the code from classes.js.
|
||||
// I make no guarantee regarding the accuracy.
|
||||
const variants: Set<string> = new Set();
|
||||
|
||||
const firstMorpheme =
|
||||
pronoun.forms[this.morphemes[0]].written.split("&");
|
||||
if (this.morphemes.length === 1) {
|
||||
return firstMorpheme;
|
||||
}
|
||||
|
||||
const secondMorpheme =
|
||||
pronoun.forms[this.morphemes[1]].written.split("&");
|
||||
const thirdMorpheme =
|
||||
this.morphemes.length > 2
|
||||
? pronoun.forms[this.morphemes[2]].written.split("&")
|
||||
: [];
|
||||
|
||||
let thirdFormMorpheme = pronoun.thirdForm
|
||||
? pronoun.forms[pronoun.thirdForm].written.split("&")
|
||||
: [];
|
||||
|
||||
let thirdMorphemeThreeForms = thirdMorpheme;
|
||||
if (this.code === "ru" || this.code === "ua") {
|
||||
thirdMorphemeThreeForms = thirdMorpheme.map((x) => `[-${x}]`);
|
||||
}
|
||||
|
||||
for (let istr in firstMorpheme) {
|
||||
const i = istr as unknown as number;
|
||||
let firstPart = firstMorpheme[i];
|
||||
let secondPart =
|
||||
secondMorpheme[Math.max(i, secondMorpheme.length - 1)];
|
||||
if (
|
||||
firstPart === secondPart &&
|
||||
thirdMorpheme.length &&
|
||||
!this.config.pronouns.threeForms
|
||||
) {
|
||||
secondPart =
|
||||
thirdMorpheme[Math.max(i, thirdMorpheme.length - 1)];
|
||||
}
|
||||
let variant = firstPart + "/" + secondPart;
|
||||
if (this.config.pronouns.threeForms) {
|
||||
variant += "/" + thirdMorphemeThreeForms[i];
|
||||
} else if (pronoun.thirdForm) {
|
||||
variant += "/" + thirdFormMorpheme[i];
|
||||
}
|
||||
|
||||
variants.add(variant);
|
||||
}
|
||||
return [...variants];
|
||||
}
|
||||
public pronounName(pronoun: Pronoun, separator: string = ","): string {
|
||||
return this.pronounNameVariants(pronoun).join(separator);
|
||||
}
|
||||
|
||||
public get examples() {
|
||||
return this._examples;
|
||||
}
|
||||
public get morphemes() {
|
||||
return this._morphemes;
|
||||
}
|
||||
}
|
||||
|
||||
export function examplesFor(
|
||||
|
@ -1,5 +1,11 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { examplesFor, getLocale, Pronoun, PronounExample } from "#self/locales";
|
||||
import {
|
||||
examplesFor,
|
||||
getLocale,
|
||||
Locale,
|
||||
Pronoun,
|
||||
PronounExample,
|
||||
} from "#self/locales";
|
||||
import pronouns from "#self/server/v1/pronouns";
|
||||
|
||||
export type V1AppInstance = AppInstance;
|
||||
@ -28,7 +34,7 @@ export function error<T extends ApiErrorOptions>(options: T) {
|
||||
|
||||
export function replyError<T extends ApiErrorOptions>(
|
||||
reply: AppReply,
|
||||
options: T,
|
||||
options: T
|
||||
): AppReply {
|
||||
const response = error(options);
|
||||
return reply.status(options.code).send(response);
|
||||
@ -41,7 +47,8 @@ export const ApiError = {
|
||||
},
|
||||
UNKNOWN_PRONOUN: {
|
||||
code: 404,
|
||||
message: "We aren't aware of any such pronoun. Perhaps there's a typo?\nNote that for custom pronouns, you need to specify all necessary forms: https://en.pronouns.page/faq#custom-pronouns",
|
||||
message:
|
||||
"We aren't aware of any such pronoun. Perhaps there's a typo?\nNote that for custom pronouns, you need to specify all necessary forms: https://en.pronouns.page/faq#custom-pronouns",
|
||||
},
|
||||
} satisfies Record<string, ApiErrorOptions>;
|
||||
|
||||
@ -52,6 +59,8 @@ export const localeSpecific = Type.Object({
|
||||
export function transformPronoun(
|
||||
pronoun: Pronoun,
|
||||
examples: Array<PronounExample>,
|
||||
locale: Locale,
|
||||
processName = false
|
||||
) {
|
||||
const morphemes: Record<string, string> = {};
|
||||
const pronunciations: Record<string, string> = {};
|
||||
@ -60,7 +69,7 @@ export function transformPronoun(
|
||||
pronunciations[name] = form.pronounced;
|
||||
}
|
||||
return {
|
||||
canonicalName: pronoun.keys[0],
|
||||
canonicalName: pronoun.canonicalName,
|
||||
description: pronoun.description,
|
||||
normative: pronoun.isNormative,
|
||||
morphemes,
|
||||
@ -74,6 +83,7 @@ export function transformPronoun(
|
||||
smallForm: pronoun.smallForm ?? null,
|
||||
sourcesInfo: pronoun.source ?? null,
|
||||
examples: examplesFor(pronoun, examples),
|
||||
name: processName ? locale.pronounName(pronoun) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@ -83,7 +93,7 @@ export function transformPronoun(
|
||||
* every route is prefixed with the respective locale ID.
|
||||
*/
|
||||
|
||||
export const routes = async function(app: AppInstance) {
|
||||
export const routes = async function (app: AppInstance) {
|
||||
app.register(pronouns);
|
||||
} satisfies AppPluginAsync;
|
||||
export default routes;
|
||||
|
@ -4,7 +4,12 @@ import {
|
||||
replyError,
|
||||
transformPronoun,
|
||||
} from "#self/server/v1";
|
||||
import { getLocale, PronounExample } from "#self/locales";
|
||||
import {
|
||||
getLocale,
|
||||
parsePronounFromParts,
|
||||
parsePronounFromString,
|
||||
PronounExample,
|
||||
} from "#self/locales";
|
||||
import { isNotBlank, parseBool } from "@pronounspage/common/util";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
|
||||
@ -27,7 +32,8 @@ export const plugin = async function (app: AppInstance) {
|
||||
for (const pronoun of locale.pronouns) {
|
||||
obj[pronoun.keys[0]] = transformPronoun(
|
||||
pronoun,
|
||||
locale.examples
|
||||
locale.examples,
|
||||
locale
|
||||
);
|
||||
}
|
||||
|
||||
@ -64,8 +70,15 @@ export const plugin = async function (app: AppInstance) {
|
||||
return replyError(reply, ApiError.INVALID_LOCALE);
|
||||
}
|
||||
|
||||
const key = req.params["*"].split("/").filter(isNotBlank).join("/"); // This is to get rid of any extraneous parts
|
||||
const found = locale.pronoun(key);
|
||||
const keyParts: Array<string> = req.params["*"]
|
||||
.split("/")
|
||||
.filter(isNotBlank);
|
||||
const key = keyParts.join("/");
|
||||
let found = locale.pronoun(key);
|
||||
if (found == null) {
|
||||
found = parsePronounFromParts(keyParts, locale.morphemes);
|
||||
req.log.info(`${JSON.stringify(keyParts)} - ${found}`);
|
||||
}
|
||||
if (found == null) {
|
||||
return replyError(reply, ApiError.UNKNOWN_PRONOUN);
|
||||
}
|
||||
@ -76,7 +89,9 @@ export const plugin = async function (app: AppInstance) {
|
||||
found,
|
||||
examples.length < 1
|
||||
? locale.examples
|
||||
: examples.map(parseExample)
|
||||
: examples.map(parseExample),
|
||||
locale,
|
||||
true
|
||||
);
|
||||
}
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user