mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-24 05:05:20 -04:00
(pronouns) enable translations for slash modifiers
This commit is contained in:
parent
d792270c80
commit
11d291a24f
@ -82,6 +82,10 @@ pronouns:
|
|||||||
comprehensive:
|
comprehensive:
|
||||||
simple: 'simple'
|
simple: 'simple'
|
||||||
comprehensive: 'comprehensive'
|
comprehensive: 'comprehensive'
|
||||||
|
slashes:
|
||||||
|
plural: 'plural'
|
||||||
|
pluralHonorific: 'plural-honorific'
|
||||||
|
description: 'description'
|
||||||
others: 'Other forms'
|
others: 'Other forms'
|
||||||
othersRaw: 'other'
|
othersRaw: 'other'
|
||||||
or: 'or'
|
or: 'or'
|
||||||
|
@ -86,6 +86,9 @@ pronouns:
|
|||||||
comprehensive:
|
comprehensive:
|
||||||
simple: 'häufige'
|
simple: 'häufige'
|
||||||
comprehensive: 'erweitert'
|
comprehensive: 'erweitert'
|
||||||
|
slashes:
|
||||||
|
plural: 'plural'
|
||||||
|
description: 'beschreibung'
|
||||||
others: 'Andere Formen'
|
others: 'Andere Formen'
|
||||||
othersRaw: 'andere'
|
othersRaw: 'andere'
|
||||||
or: 'oder'
|
or: 'oder'
|
||||||
|
@ -79,6 +79,9 @@ pronouns:
|
|||||||
Even though for many people it's incredibly important that people use specific pronouns to talk about them,
|
Even though for many people it's incredibly important that people use specific pronouns to talk about them,
|
||||||
others don't mind being addressed in any way – as long as the context is clear as to who one talks about.
|
others don't mind being addressed in any way – as long as the context is clear as to who one talks about.
|
||||||
options: 'check out the options [share]{/pronouns=here}.'
|
options: 'check out the options [share]{/pronouns=here}.'
|
||||||
|
slashes:
|
||||||
|
plural: 'plural'
|
||||||
|
description: 'description'
|
||||||
others: 'Other forms'
|
others: 'Other forms'
|
||||||
othersRaw: 'other'
|
othersRaw: 'other'
|
||||||
or: 'or'
|
or: 'or'
|
||||||
|
@ -60,7 +60,7 @@ export default {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pronounEntity = buildPronoun(pronouns, link);
|
const pronounEntity = buildPronoun(pronouns, link, this.$translator);
|
||||||
|
|
||||||
if (pronounEntity) {
|
if (pronounEntity) {
|
||||||
pronounOpinions.push({
|
pronounOpinions.push({
|
||||||
@ -76,7 +76,7 @@ export default {
|
|||||||
if (!this.config.profile?.flags?.defaultPronoun) {
|
if (!this.config.profile?.flags?.defaultPronoun) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let mainPronoun = buildPronoun(pronouns, this.config.profile.flags.defaultPronoun);
|
let mainPronoun = buildPronoun(pronouns, this.config.profile.flags.defaultPronoun, this.$translator);
|
||||||
let mainOpinion = -1;
|
let mainOpinion = -1;
|
||||||
for (const { pronoun, opinion } of this.pronounOpinions) {
|
for (const { pronoun, opinion } of this.pronounOpinions) {
|
||||||
if (typeof pronoun === 'string') {
|
if (typeof pronoun === 'string') {
|
||||||
|
@ -532,7 +532,7 @@ export default {
|
|||||||
if (!this.config.profile?.flags?.defaultPronoun) {
|
if (!this.config.profile?.flags?.defaultPronoun) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let mainPronoun = buildPronoun(pronouns, this.config.profile.flags?.defaultPronoun);
|
let mainPronoun = buildPronoun(pronouns, this.config.profile.flags?.defaultPronoun, this.$translator);
|
||||||
let mainOpinion = -1;
|
let mainOpinion = -1;
|
||||||
for (const { value: pronoun, opinion } of this.pronouns) {
|
for (const { value: pronoun, opinion } of this.pronouns) {
|
||||||
const opinionValue = opinions[opinion]?.value || 0;
|
const opinionValue = opinions[opinion]?.value || 0;
|
||||||
@ -627,7 +627,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
normaliseAndBuildPronoun(pronoun) {
|
normaliseAndBuildPronoun(pronoun) {
|
||||||
return buildPronoun(pronouns, this.normalisePronoun(pronoun));
|
return buildPronoun(pronouns, this.normalisePronoun(pronoun), this.$translator);
|
||||||
},
|
},
|
||||||
validatePronoun(pronoun) {
|
validatePronoun(pronoun) {
|
||||||
pronoun = this.normalisePronoun(pronoun);
|
pronoun = this.normalisePronoun(pronoun);
|
||||||
@ -637,7 +637,7 @@ export default {
|
|||||||
return this.validateAnyPronoun(pronoun) ||
|
return this.validateAnyPronoun(pronoun) ||
|
||||||
this.config.pronouns.null && this.config.pronouns.null.routes && this.config.pronouns.null.routes.includes(pronoun) ||
|
this.config.pronouns.null && this.config.pronouns.null.routes && this.config.pronouns.null.routes.includes(pronoun) ||
|
||||||
this.config.pronouns.mirror && this.config.pronouns.mirror.route === pronoun ||
|
this.config.pronouns.mirror && this.config.pronouns.mirror.route === pronoun ||
|
||||||
buildPronoun(pronouns, pronoun)
|
buildPronoun(pronouns, pronoun, this.$translator)
|
||||||
? null
|
? null
|
||||||
: 'profile.pronounsNotFound';
|
: 'profile.pronounsNotFound';
|
||||||
},
|
},
|
||||||
|
@ -130,7 +130,7 @@ export default {
|
|||||||
const key = this.getPronounKeyFromUrl();
|
const key = this.getPronounKeyFromUrl();
|
||||||
|
|
||||||
const selectedPronoun = this.config.pronouns.enabled && key
|
const selectedPronoun = this.config.pronouns.enabled && key
|
||||||
? buildPronoun(pronouns, key)
|
? buildPronoun(pronouns, key, this.$translator)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -322,7 +322,7 @@ export default {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const slashes = this.selectedPronoun.toStringSlashes();
|
const slashes = this.selectedPronoun.toStringSlashes(this.$translator);
|
||||||
|
|
||||||
let link;
|
let link;
|
||||||
if (this.usedBaseEquals) {
|
if (this.usedBaseEquals) {
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import SQL from 'sql-template-strings';
|
import SQL from 'sql-template-strings';
|
||||||
import { createCanvas, loadImage } from 'canvas';
|
import { createCanvas, loadImage } from 'canvas';
|
||||||
import { loadSuml } from '../loader.js';
|
import { loadSuml, loadSumlFromBase } from '../loader.js';
|
||||||
import avatar from '../avatar.js';
|
import avatar from '../avatar.js';
|
||||||
import { buildPronoun, parsePronouns } from '../../src/buildPronoun.js';
|
import { buildPronoun, parsePronouns } from '../../src/buildPronoun.js';
|
||||||
import { loadTsv } from '../../src/tsv.js';
|
import { loadTsv } from '../../src/tsv.js';
|
||||||
import { handleErrorAsync } from '../../src/helpers.js';
|
import { handleErrorAsync } from '../../src/helpers.js';
|
||||||
|
import { Translator } from '../../src/translator.js';
|
||||||
import { CacheObject } from '../../src/cache.js';
|
import { CacheObject } from '../../src/cache.js';
|
||||||
import { registerLocaleFont } from '../localeFont.js';
|
import { registerLocaleFont } from '../localeFont.js';
|
||||||
|
|
||||||
const translations = loadSuml('translations');
|
const translations = loadSuml('translations');
|
||||||
|
const baseTranslations = loadSumlFromBase('locale/_base/translations');
|
||||||
|
|
||||||
|
const translator = new Translator(translations, baseTranslations, global.config);
|
||||||
|
|
||||||
const drawCircle = (context, image, x, y, size) => {
|
const drawCircle = (context, image, x, y, size) => {
|
||||||
context.save();
|
context.save();
|
||||||
@ -84,6 +88,7 @@ router.get('/banner/:pronounName*.png', handleErrorAsync(async (req, res) => {
|
|||||||
const pronoun = buildPronoun(
|
const pronoun = buildPronoun(
|
||||||
parsePronouns(loadTsv(`${__dirname}/../../data/pronouns/pronouns.tsv`)),
|
parsePronouns(loadTsv(`${__dirname}/../../data/pronouns/pronouns.tsv`)),
|
||||||
pronounName,
|
pronounName,
|
||||||
|
translator,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (pronounName === 'zaimki' || !pronoun && pronounName !== global.config.pronouns.any && (!global.config.pronouns || pronounName !== global.config.pronouns.mirror)) {
|
if (pronounName === 'zaimki' || !pronoun && pronounName !== global.config.pronouns.any && (!global.config.pronouns || pronounName !== global.config.pronouns.mirror)) {
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import { loadTsv } from '../loader.js';
|
import { loadSuml, loadSumlFromBase, loadTsv } from '../loader.js';
|
||||||
import { buildPronoun, parsePronouns } from '../../src/buildPronoun.js';
|
import { buildPronoun, parsePronouns } from '../../src/buildPronoun.js';
|
||||||
import { buildList, handleErrorAsync } from '../../src/helpers.js';
|
import { buildList, handleErrorAsync } from '../../src/helpers.js';
|
||||||
import { Example } from '../../src/classes.js';
|
import { Example } from '../../src/classes.js';
|
||||||
import { caches } from '../../src/cache.js';
|
import { caches } from '../../src/cache.js';
|
||||||
|
import { Translator } from '../../src/translator.js';
|
||||||
import md5 from 'js-md5';
|
import md5 from 'js-md5';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
|
|
||||||
|
const translations = loadSuml('translations');
|
||||||
|
const baseTranslations = loadSumlFromBase('locale/_base/translations');
|
||||||
|
|
||||||
|
const translator = new Translator(translations, baseTranslations, global.config);
|
||||||
|
|
||||||
const buildExample = (e) => new Example(
|
const buildExample = (e) => new Example(
|
||||||
Example.parse(e.singular),
|
Example.parse(e.singular),
|
||||||
Example.parse(e.plural || e.singular),
|
Example.parse(e.plural || e.singular),
|
||||||
@ -52,6 +58,7 @@ router.get('/pronouns/:pronoun*', handleErrorAsync(async (req, res) => {
|
|||||||
const pronoun = buildPronoun(
|
const pronoun = buildPronoun(
|
||||||
parsePronouns(loadTsv('pronouns/pronouns')),
|
parsePronouns(loadTsv('pronouns/pronouns')),
|
||||||
req.params.pronoun + req.params[0],
|
req.params.pronoun + req.params[0],
|
||||||
|
translator,
|
||||||
);
|
);
|
||||||
if (pronoun) {
|
if (pronoun) {
|
||||||
pronoun.examples = addExamples(pronoun, requestExamples(req.query.examples));
|
pronoun.examples = addExamples(pronoun, requestExamples(req.query.examples));
|
||||||
@ -64,6 +71,7 @@ router.get('/pronouns-name/:pronoun*', handleErrorAsync(async (req, res) => {
|
|||||||
const pronoun = buildPronoun(
|
const pronoun = buildPronoun(
|
||||||
parsePronouns(loadTsv('pronouns/pronouns')),
|
parsePronouns(loadTsv('pronouns/pronouns')),
|
||||||
(req.params.pronoun + req.params[0]).toLowerCase(),
|
(req.params.pronoun + req.params[0]).toLowerCase(),
|
||||||
|
translator,
|
||||||
);
|
);
|
||||||
if (!pronoun) {
|
if (!pronoun) {
|
||||||
return res.status(404).json({ error: 'Not found' });
|
return res.status(404).json({ error: 'Not found' });
|
||||||
|
@ -58,7 +58,23 @@ const buildPronounFromTemplate = (key, template) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildPronounFromSlashes = (config, path) => {
|
const isModifier = (chunk, key, translator) => {
|
||||||
|
// use both locale and base translations to ensure backwards compatibility if key gets translated
|
||||||
|
return chunk === `:${translator.translate(key)}` || chunk === `:${translator.get(key, false, true)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const extractModifierValue = (chunk, key, translator) => {
|
||||||
|
// use both locale and base translations to ensure backwards compatibility if key gets translated
|
||||||
|
const prefixes = [`:${translator.translate(key)}=`, `:${translator.get(key, false, true)}=`];
|
||||||
|
for (const prefix of prefixes) {
|
||||||
|
if (chunk.startsWith(prefix)) {
|
||||||
|
return chunk.substring(prefix.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildPronounFromSlashes = (config, path, translator) => {
|
||||||
const chunks = path.split(/(?<!`)\//);
|
const chunks = path.split(/(?<!`)\//);
|
||||||
let plural = false;
|
let plural = false;
|
||||||
let pluralHonorific = false;
|
let pluralHonorific = false;
|
||||||
@ -66,14 +82,16 @@ const buildPronounFromSlashes = (config, path) => {
|
|||||||
const morphemeChunks = [];
|
const morphemeChunks = [];
|
||||||
for (const chunk of chunks) {
|
for (const chunk of chunks) {
|
||||||
if (chunk.startsWith(':')) {
|
if (chunk.startsWith(':')) {
|
||||||
if (config.pronouns.plurals && chunk === ':plural') {
|
if (config.pronouns.plurals && isModifier(chunk, 'pronouns.slashes.plural', translator)) {
|
||||||
plural = true;
|
plural = true;
|
||||||
} else if (config.pronouns.plurals && config.pronouns.honorifics && chunk === ':plural-honorific') {
|
} else if (config.pronouns.plurals && config.pronouns.honorifics &&
|
||||||
|
isModifier(chunk, 'pronouns.slashes.pluralHonorific', translator)) {
|
||||||
pluralHonorific = true;
|
pluralHonorific = true;
|
||||||
} else {
|
} else {
|
||||||
const descriptionModifierPrefix = ':description=';
|
const descriptionModifierValue =
|
||||||
if (chunk.startsWith(descriptionModifierPrefix)) {
|
extractModifierValue(chunk, 'pronouns.slashes.description', translator);
|
||||||
description = unescapeControlSymbols(chunk.substring(descriptionModifierPrefix.length));
|
if (descriptionModifierValue) {
|
||||||
|
description = unescapeControlSymbols(descriptionModifierValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -112,7 +130,7 @@ const buildPronounFromSlashes = (config, path) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buildPronoun = (pronouns, path) => {
|
export const buildPronoun = (pronouns, path, translator) => {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -180,7 +198,7 @@ export const buildPronoun = (pronouns, path) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!pronoun && config.pronouns.slashes !== false) {
|
if (!pronoun && config.pronouns.slashes !== false) {
|
||||||
return buildPronounFromSlashes(config, path);
|
return buildPronounFromSlashes(config, path, translator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pronoun;
|
return pronoun;
|
||||||
|
@ -467,7 +467,7 @@ export class Pronoun {
|
|||||||
return this.toArray().join(',');
|
return this.toArray().join(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
toStringSlashes() {
|
toStringSlashes(translator) {
|
||||||
if (!config.pronouns.slashes) {
|
if (!config.pronouns.slashes) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -490,13 +490,14 @@ export class Pronoun {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.plural[0]) {
|
if (this.plural[0]) {
|
||||||
chunks.push(':plural');
|
chunks.push(`:${translator.translate('pronouns.slashes.plural')}`);
|
||||||
}
|
}
|
||||||
if (this.pluralHonorific[0]) {
|
if (this.pluralHonorific[0]) {
|
||||||
chunks.push(':plural-honorific');
|
chunks.push(`:${translator.translate('pronouns.slashes.pluralHonorific')}`);
|
||||||
}
|
}
|
||||||
if (this.description) {
|
if (this.description) {
|
||||||
chunks.push(`:description=${escapeControlSymbols(this.description)}`);
|
const escapedDescription = escapeControlSymbols(this.description);
|
||||||
|
chunks.push(`:${translator.translate('pronouns.slashes.description')}=${escapedDescription}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode a trailing space so that it does not get removed during a request
|
// encode a trailing space so that it does not get removed during a request
|
||||||
|
@ -63,6 +63,22 @@ export function listMissingTranslations(translations, baseTranslations, config)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!config.pronouns.slashes && keyMatches('pronouns.slashes.')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.pronouns.plurals && keyMatches(
|
||||||
|
'pronouns.plural',
|
||||||
|
'pronouns.slashes.plural',
|
||||||
|
'pronouns.slashes.pluralHonorific',
|
||||||
|
)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.pronouns.honorifics && keyMatches('pronouns.slashes.pluralHonorific')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!config.pronouns.comprehensive && keyMatches('pronouns.comprehensive.')) {
|
if (!config.pronouns.comprehensive && keyMatches('pronouns.comprehensive.')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,16 @@
|
|||||||
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
|
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
|
||||||
|
import { Translator } from '../src/translator.js';
|
||||||
|
|
||||||
|
const translations = {
|
||||||
|
pronouns: {
|
||||||
|
slashes: {
|
||||||
|
plural: 'plural',
|
||||||
|
pluralHonorific: 'plural-honorific',
|
||||||
|
description: 'description',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const translator = new Translator(translations, translations, []);
|
||||||
|
|
||||||
// workaround to be independent of the current selected locale
|
// workaround to be independent of the current selected locale
|
||||||
jest.unstable_mockModule('../data/pronouns/morphemes.js', () => {
|
jest.unstable_mockModule('../data/pronouns/morphemes.js', () => {
|
||||||
@ -21,13 +33,13 @@ beforeEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('finds pronouns by canonical name', () => {
|
test('finds pronouns by canonical name', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'they'));
|
const actual = expect(buildPronoun(pronouns, 'they', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toBe(pronouns.they);
|
actual.toBe(pronouns.they);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('finds pronouns by alias', () => {
|
test('finds pronouns by alias', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'they/them'));
|
const actual = expect(buildPronoun(pronouns, 'they/them', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toBe(pronouns.they);
|
actual.toBe(pronouns.they);
|
||||||
});
|
});
|
||||||
@ -46,7 +58,7 @@ describe('when configured that emojiself pronouns are available', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('builds pronouns from emoji', () => {
|
test('builds pronouns from emoji', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, '💙'));
|
const actual = expect(buildPronoun(pronouns, '💙', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(new Pronoun(
|
actual.toEqual(new Pronoun(
|
||||||
'💙',
|
'💙',
|
||||||
@ -82,7 +94,7 @@ describe('when configured that null pronouns are available', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('builds pronouns from name', () => {
|
test('builds pronouns from name', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, ':S'));
|
const actual = expect(buildPronoun(pronouns, ':S', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(new Pronoun(
|
actual.toEqual(new Pronoun(
|
||||||
'S',
|
'S',
|
||||||
@ -103,7 +115,7 @@ describe('when configured that null pronouns are available', () => {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
test('builds nothing if name too long', () => {
|
test('builds nothing if name too long', () => {
|
||||||
expect(buildPronoun(pronouns, ':Abcdefghijklmnopqrstuvwxyz')).toBeUndefined();
|
expect(buildPronoun(pronouns, ':Abcdefghijklmnopqrstuvwxyz', translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with conditional placeholders', () => {
|
describe('with conditional placeholders', () => {
|
||||||
@ -112,10 +124,10 @@ describe('when configured that null pronouns are available', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.each(['S', 'Ringelnatz', 'Max', 'X'])('builds morpheme conditionally if name matches', (name) => {
|
test.each(['S', 'Ringelnatz', 'Max', 'X'])('builds morpheme conditionally if name matches', (name) => {
|
||||||
expect(buildPronoun(pronouns, `:${name}`).morphemes.possessive_pronoun).toBe(`${name}’`);
|
expect(buildPronoun(pronouns, `:${name}`, translator).morphemes.possessive_pronoun).toBe(`${name}’`);
|
||||||
});
|
});
|
||||||
test.each(['Sofi', 'Xavier'])('builds morpheme by default if name does not match', (name) => {
|
test.each(['Sofi', 'Xavier'])('builds morpheme by default if name does not match', (name) => {
|
||||||
expect(buildPronoun(pronouns, `:${name}`).morphemes.possessive_pronoun).toBe(`${name}s`);
|
expect(buildPronoun(pronouns, `:${name}`, translator).morphemes.possessive_pronoun).toBe(`${name}s`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -127,27 +139,31 @@ describe('when configured that slashes contain all morphemes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('builds generated pronoun from all morphemes', () => {
|
test('builds generated pronoun from all morphemes', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself'));
|
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aer);
|
actual.toEqual(generatedPronouns.aer);
|
||||||
});
|
});
|
||||||
test('unescapes morphemes', () => {
|
test('unescapes morphemes', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 's`/he/hir/hir/hirs/hirself'));
|
const actual = expect(buildPronoun(pronouns, 's`/he/hir/hir/hirs/hirself', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.sSlashHe);
|
actual.toEqual(generatedPronouns.sSlashHe);
|
||||||
});
|
});
|
||||||
test('builds generated pronoun from all required morphemes and plural modifier', () => {
|
test('builds generated pronoun from all required morphemes and plural modifier', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerselves/:plural'));
|
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerselves/:plural', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aerPlural);
|
actual.toEqual(generatedPronouns.aerPlural);
|
||||||
});
|
});
|
||||||
test('builds generated pronoun from all required morphemes and plural honorific modifier', () => {
|
test('builds generated pronoun from all required morphemes and plural honorific modifier', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerselves/:plural-honorific'));
|
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerselves/:plural-honorific', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aerPluralHonorific);
|
actual.toEqual(generatedPronouns.aerPluralHonorific);
|
||||||
});
|
});
|
||||||
test('builds generated pronoun from all required morphemes and description', () => {
|
test('builds generated pronoun from all required morphemes and description', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself/:description=Neopronoun “ae” `/ “æ”'));
|
const actual = expect(buildPronoun(
|
||||||
|
pronouns,
|
||||||
|
'ae/aer/aer/aers/aerself/:description=Neopronoun “ae” `/ “æ”',
|
||||||
|
translator,
|
||||||
|
));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aerWithDescription);
|
actual.toEqual(generatedPronouns.aerWithDescription);
|
||||||
});
|
});
|
||||||
@ -155,35 +171,37 @@ describe('when configured that slashes contain all morphemes', () => {
|
|||||||
const actual = expect(buildPronoun(
|
const actual = expect(buildPronoun(
|
||||||
pronouns,
|
pronouns,
|
||||||
'ae/aer/:description=Neopronoun “ae” `/ “æ”/:plural/aer/aers/aerselves',
|
'ae/aer/:description=Neopronoun “ae” `/ “æ”/:plural/aer/aers/aerselves',
|
||||||
|
translator,
|
||||||
));
|
));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aerPluralWithDescription);
|
actual.toEqual(generatedPronouns.aerPluralWithDescription);
|
||||||
});
|
});
|
||||||
test('builds generated pronoun with some morphemes empty', () => {
|
test('builds generated pronoun with some morphemes empty', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/ /aerself'));
|
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/ /aerself', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aerWithEmptyPossessivePronoun);
|
actual.toEqual(generatedPronouns.aerWithEmptyPossessivePronoun);
|
||||||
});
|
});
|
||||||
test('builds generated pronoun with morpheme at end empty', () => {
|
test('builds generated pronoun with morpheme at end empty', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/'));
|
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aerWithEmptyReflexive);
|
actual.toEqual(generatedPronouns.aerWithEmptyReflexive);
|
||||||
});
|
});
|
||||||
test('builds generated pronoun with some morphemes unset', () => {
|
test('builds generated pronoun with some morphemes unset', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/~/aerself'));
|
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/~/aerself', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aerWithUnsetPossessivePronoun);
|
actual.toEqual(generatedPronouns.aerWithUnsetPossessivePronoun);
|
||||||
});
|
});
|
||||||
test('builds nothing if morphemes are missing', () => {
|
test('builds nothing if morphemes are missing', () => {
|
||||||
expect(buildPronoun(pronouns, 'ae/aer/aer/aerself')).toBeUndefined();
|
expect(buildPronoun(pronouns, 'ae/aer/aer/aerself', translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
test('builds nothing if too many morphemes are given', () => {
|
test('builds nothing if too many morphemes are given', () => {
|
||||||
expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself/aer')).toBeUndefined();
|
expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself/aer', translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
test('builds nothing if description too long', () => {
|
test('builds nothing if description too long', () => {
|
||||||
expect(buildPronoun(
|
expect(buildPronoun(
|
||||||
pronouns,
|
pronouns,
|
||||||
'ae/aer/aer/aers/aerself/:description=Neopronoun “ae” `/ “æ” which is my favorite so you should use it too',
|
'ae/aer/aer/aers/aerself/:description=Neopronoun “ae” `/ “æ” which is my favorite so you should use it too',
|
||||||
|
translator,
|
||||||
)).toBeNull();
|
)).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -193,15 +211,15 @@ describe('when configured that slashes contain some morphemes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('builds generated pronoun from all required morphemes', () => {
|
test('builds generated pronoun from all required morphemes', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aerself'));
|
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aerself', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aerWithUnsetPossessivePronoun);
|
actual.toEqual(generatedPronouns.aerWithUnsetPossessivePronoun);
|
||||||
});
|
});
|
||||||
test('builds nothing if morphemes are missing', () => {
|
test('builds nothing if morphemes are missing', () => {
|
||||||
expect(buildPronoun(pronouns, 'ae/aer/aer')).toBeUndefined();
|
expect(buildPronoun(pronouns, 'ae/aer/aer', translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
test('builds nothing if too many morphemes are given', () => {
|
test('builds nothing if too many morphemes are given', () => {
|
||||||
expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself')).toBeUndefined();
|
expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself', translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('when configured that slashes cannot contain morphemes', () => {
|
describe('when configured that slashes cannot contain morphemes', () => {
|
||||||
@ -214,23 +232,23 @@ describe('when configured that slashes cannot contain morphemes', () => {
|
|||||||
test.each([3, 4, 5, 6])('builds nothing if %d morphemes are given', (count) => {
|
test.each([3, 4, 5, 6])('builds nothing if %d morphemes are given', (count) => {
|
||||||
const path = pathBase.split('/').slice(0, count)
|
const path = pathBase.split('/').slice(0, count)
|
||||||
.join('/');
|
.join('/');
|
||||||
expect(buildPronoun(pronouns, path.slice(0, count))).toBeUndefined();
|
expect(buildPronoun(pronouns, path.slice(0, count), translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('building generated pronouns from commas', () => {
|
describe('building generated pronouns from commas', () => {
|
||||||
test('succeeds with all parts present', () => {
|
test('succeeds with all parts present', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae,aer,aer,aers,aerself,0,'));
|
const actual = expect(buildPronoun(pronouns, 'ae,aer,aer,aers,aerself,0,', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aer);
|
actual.toEqual(generatedPronouns.aer);
|
||||||
});
|
});
|
||||||
test('succeeds with description missing present', () => {
|
test('succeeds with description missing present', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'ae,aer,aer,aers,aerself,0'));
|
const actual = expect(buildPronoun(pronouns, 'ae,aer,aer,aers,aerself,0', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(generatedPronouns.aer);
|
actual.toEqual(generatedPronouns.aer);
|
||||||
});
|
});
|
||||||
test('succeeds with base pronoun and some custom morphemes', () => {
|
test('succeeds with base pronoun and some custom morphemes', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'they,!2,aers,!2,'));
|
const actual = expect(buildPronoun(pronouns, 'they,!2,aers,!2,', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(new Pronoun(
|
actual.toEqual(new Pronoun(
|
||||||
'they/them',
|
'they/them',
|
||||||
@ -251,19 +269,19 @@ describe('building generated pronouns from commas', () => {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
test('fails when too few parts are given', () => {
|
test('fails when too few parts are given', () => {
|
||||||
expect(buildPronoun(pronouns, 'ae,aer,aer,aers,aerself')).toBeUndefined();
|
expect(buildPronoun(pronouns, 'ae, translator,aer,aer,aers,aerself', translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
test('fails when many few parts are given', () => {
|
test('fails when many few parts are given', () => {
|
||||||
expect(buildPronoun(pronouns, 'ae,aer,aer,aers,aerself,aersing,0,')).toBeUndefined();
|
expect(buildPronoun(pronouns, 'ae, translator,aer,aer,aers,aerself,aersing,0,', translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
test('fails when base pronoun is unknown', () => {
|
test('fails when base pronoun is unknown', () => {
|
||||||
expect(buildPronoun(pronouns, 's/he,!2,aers,!2,')).toBeUndefined();
|
expect(buildPronoun(pronouns, 's/he, translator,!2,aers,!2,', translator)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('builds interchangable pronouns from ampersand', () => {
|
describe('builds interchangable pronouns from ampersand', () => {
|
||||||
test('two interchangable pronouns', () => {
|
test('two interchangable pronouns', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'he&she'));
|
const actual = expect(buildPronoun(pronouns, 'he&she', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(new Pronoun(
|
actual.toEqual(new Pronoun(
|
||||||
'he&she',
|
'he&she',
|
||||||
@ -284,7 +302,7 @@ describe('builds interchangable pronouns from ampersand', () => {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
test('three interchangable pronouns', () => {
|
test('three interchangable pronouns', () => {
|
||||||
const actual = expect(buildPronoun(pronouns, 'he&she&they'));
|
const actual = expect(buildPronoun(pronouns, 'he&she&they', translator));
|
||||||
actual.toBeDefined();
|
actual.toBeDefined();
|
||||||
actual.toEqual(new Pronoun(
|
actual.toEqual(new Pronoun(
|
||||||
'he&she&they',
|
'he&she&they',
|
||||||
|
@ -8,6 +8,11 @@ const translations = {
|
|||||||
any: {
|
any: {
|
||||||
short: 'any',
|
short: 'any',
|
||||||
},
|
},
|
||||||
|
slashes: {
|
||||||
|
plural: 'plural',
|
||||||
|
pluralHonorific: 'plural-honorific',
|
||||||
|
description: 'description',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const translator = new Translator(translations, translations, []);
|
const translator = new Translator(translations, translations, []);
|
||||||
@ -39,7 +44,7 @@ describe('formatting a pronoun with slashes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('yields no result', () => {
|
test('yields no result', () => {
|
||||||
expect(generatedPronouns.aer.toStringSlashes()).toBeNull();
|
expect(generatedPronouns.aer.toStringSlashes(translator)).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('when configured that slashes contain all morphemes', () => {
|
describe('when configured that slashes contain all morphemes', () => {
|
||||||
@ -48,39 +53,39 @@ describe('formatting a pronoun with slashes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('chunks contain all morphemes', () => {
|
test('chunks contain all morphemes', () => {
|
||||||
expect(generatedPronouns.aer.toStringSlashes())
|
expect(generatedPronouns.aer.toStringSlashes(translator))
|
||||||
.toEqual('ae/aer/aer/aers/aerself');
|
.toEqual('ae/aer/aer/aers/aerself');
|
||||||
});
|
});
|
||||||
test('morphemes with control symbols gets escaped', () => {
|
test('morphemes with control symbols gets escaped', () => {
|
||||||
expect(generatedPronouns.sSlashHe.toStringSlashes())
|
expect(generatedPronouns.sSlashHe.toStringSlashes(translator))
|
||||||
.toEqual('s`/he/hir/hir/hirs/hirself');
|
.toEqual('s`/he/hir/hir/hirs/hirself');
|
||||||
});
|
});
|
||||||
test('empty morphemes receive space as placeholder', () => {
|
test('empty morphemes receive space as placeholder', () => {
|
||||||
expect(generatedPronouns.aerWithEmptyPossessivePronoun.toStringSlashes())
|
expect(generatedPronouns.aerWithEmptyPossessivePronoun.toStringSlashes(translator))
|
||||||
.toEqual('ae/aer/aer/ /aerself');
|
.toEqual('ae/aer/aer/ /aerself');
|
||||||
});
|
});
|
||||||
test('empty morphemes at end receive url-encoded space as placeholder', () => {
|
test('empty morphemes at end receive url-encoded space as placeholder', () => {
|
||||||
expect(generatedPronouns.aerWithEmptyReflexive.toStringSlashes())
|
expect(generatedPronouns.aerWithEmptyReflexive.toStringSlashes(translator))
|
||||||
.toEqual('ae/aer/aer/aers/%20');
|
.toEqual('ae/aer/aer/aers/%20');
|
||||||
});
|
});
|
||||||
test('unset morphemes receive tilde as placeholder', () => {
|
test('unset morphemes receive tilde as placeholder', () => {
|
||||||
expect(generatedPronouns.aerWithUnsetPossessivePronoun.toStringSlashes())
|
expect(generatedPronouns.aerWithUnsetPossessivePronoun.toStringSlashes(translator))
|
||||||
.toEqual('ae/aer/aer/~/aerself');
|
.toEqual('ae/aer/aer/~/aerself');
|
||||||
});
|
});
|
||||||
test('adds plural modifier if necessary', () => {
|
test('adds plural modifier if necessary', () => {
|
||||||
expect(generatedPronouns.aerPlural.toStringSlashes())
|
expect(generatedPronouns.aerPlural.toStringSlashes(translator))
|
||||||
.toEqual('ae/aer/aer/aers/aerselves/:plural');
|
.toEqual('ae/aer/aer/aers/aerselves/:plural');
|
||||||
});
|
});
|
||||||
test('adds plural honorific modifier if necessary', () => {
|
test('adds plural honorific modifier if necessary', () => {
|
||||||
expect(generatedPronouns.aerPluralHonorific.toStringSlashes())
|
expect(generatedPronouns.aerPluralHonorific.toStringSlashes(translator))
|
||||||
.toEqual('ae/aer/aer/aers/aerselves/:plural-honorific');
|
.toEqual('ae/aer/aer/aers/aerselves/:plural-honorific');
|
||||||
});
|
});
|
||||||
test('adds escaped description if necessary', () => {
|
test('adds escaped description if necessary', () => {
|
||||||
expect(generatedPronouns.aerWithDescription.toStringSlashes())
|
expect(generatedPronouns.aerWithDescription.toStringSlashes(translator))
|
||||||
.toEqual('ae/aer/aer/aers/aerself/:description=Neopronoun “ae” `/ “æ”');
|
.toEqual('ae/aer/aer/aers/aerself/:description=Neopronoun “ae” `/ “æ”');
|
||||||
});
|
});
|
||||||
test('adds multiple modifiers if necessary', () => {
|
test('adds multiple modifiers if necessary', () => {
|
||||||
expect(generatedPronouns.aerPluralWithDescription.toStringSlashes())
|
expect(generatedPronouns.aerPluralWithDescription.toStringSlashes(translator))
|
||||||
.toEqual('ae/aer/aer/aers/aerselves/:plural/:description=Neopronoun “ae” `/ “æ”');
|
.toEqual('ae/aer/aer/aers/aerselves/:plural/:description=Neopronoun “ae” `/ “æ”');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -92,7 +97,7 @@ describe('formatting a pronoun with slashes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('chunks contain configured morphemes', () => {
|
test('chunks contain configured morphemes', () => {
|
||||||
expect(generatedPronouns.aer.toStringSlashes()).toEqual('ae/aer/aer/aerself');
|
expect(generatedPronouns.aer.toStringSlashes(translator)).toEqual('ae/aer/aer/aerself');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user