Merge branch 'de-noun-templates' into 'main'

noun templates preview

See merge request PronounsPage/PronounsPage!464
This commit is contained in:
Valentyne Stigloher 2024-06-03 17:36:06 +00:00
commit 7264c7e43c
32 changed files with 239 additions and 127 deletions

View File

@ -4,26 +4,35 @@
</span>
</template>
<script>
<script lang="ts">
import Vue from 'vue';
import { abbreviations } from '../src/data.ts';
export default {
export default Vue.extend({
props: {
v: { required: true },
v: { required: true, type: String },
},
data() {
const abbrs = {};
let word = this.v.trim();
let m = null;
while ((m = word.match(/^(\w+\.?) /)) !== null) {
const abbr = m[1];
abbrs[abbr] = abbreviations[abbr] || null;
word = word.substring(abbr.length + 1).trim();
}
computed: {
dissectedWord(): { abbrs: Record<string, string | null>, word: string } {
const abbrs: Record<string, string | null> = {};
let word = this.v.trim();
let m = null;
while ((m = word.match(/^(\w+\.?) /)) !== null) {
const abbr = m[1];
abbrs[abbr] = abbreviations[abbr] || null;
word = word.substring(abbr.length + 1).trim();
}
return { abbrs, word };
return { abbrs, word };
},
abbrs(): Record<string, string | null> {
return this.dissectedWord.abbrs;
},
word(): string {
return this.dissectedWord.word;
},
},
};
});
</script>
<style lang="scss" scoped>

View File

@ -29,11 +29,15 @@
</div>
</template>
<script>
export default {
<script lang="ts">
import Vue from 'vue';
import type { PropType } from 'vue';
import type { genders, MinimalNoun } from '../src/classes.ts';
export default Vue.extend({
props: {
noun: { required: true },
gender: { required: true },
noun: { required: true, type: Object as PropType<MinimalNoun> },
gender: { required: true, type: String as PropType<typeof genders[number]> },
},
};
});
</script>

View File

@ -83,24 +83,66 @@
<template v-if="$config.nouns.templates">
<a v-if="!templateVisible" href="#" class="btn btn-outline-primary w-100 mb-3" @click.prevent="templateVisible = true">
<Icon v="copy" />
<T>nouns.template</T>
<T>nouns.template.header</T>
</a>
<div v-else class="card mb-3">
<a href="#" class="card-header" @click.prevent="templateVisible = false">
<Icon v="copy" />
<T>nouns.template</T>
<T>nouns.template.header</T>
</a>
<div class="card-body">
<T>nouns.root</T><T>quotation.colon</T> <input v-model="templateBase" class="form-control form-control-sm d-inline-block w-auto" autofocus>
<ul>
<li v-for="template in templates" class="my-2">
{{ template.toString() }}
<button type="button" class="btn btn-outline-primary btn-sm" @click="form = template.fill(templateBase)">
<Icon v="copy" />
</button>
</li>
</ul>
<T>nouns.template.root</T><T>quotation.colon</T>
<input v-model="templateBase" class="form-control form-control-sm d-inline-block w-auto" autofocus>
<table class="table table-striped table-hover table-fixed-3 mt-2">
<thead>
<tr>
<th class="text-nowrap">
<Icon v="mars" />
<span class="d-none d-md-inline"><T>nouns.masculine</T></span>
<span class="d-md-none"><T>nouns.masculineShort</T></span>
</th>
<th class="text-nowrap">
<Icon v="venus" />
<span class="d-none d-md-inline"><T>nouns.feminine</T></span>
<span class="d-md-none"><T>nouns.feminineShort</T></span>
</th>
<th class="text-nowrap">
<Icon v="neuter" />
<span class="d-none d-md-inline"><T>nouns.neuter</T></span>
<span class="d-md-none"><T>nouns.neuterShort</T></span>
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="(template, i) in templates" :key="i">
<td>
<Noun :noun="template" gender="masc" />
</td>
<td>
<Noun :noun="template" gender="fem" />
</td>
<td>
<Noun :noun="template" gender="neutr" />
</td>
<th>
<ul class="list-unstyled list-btn-concise">
<li>
<button
type="button"
class="btn btn-concise btn-outline-primary btn-sm"
:disabled="!templateBase"
@click="applyTemplate(template)"
>
<Icon v="copy" />
<span class="btn-label"><T>nouns.template.apply</T></span>
</button>
</li>
</ul>
</th>
</tr>
</tbody>
</table>
</div>
</div>
</template>
@ -131,55 +173,65 @@
</section>
</template>
<script class="ts">
<script lang="ts">
import Vue from 'vue';
import { nounTemplates, abbreviations } from '../src/data.ts';
import type { Noun, MinimalNoun } from '../src/classes.ts';
import type { Config } from '../locale/config.ts';
const emptyForm = (config: Config): MinimalNoun => {
return {
masc: [''],
fem: [''],
neutr: [''],
mascPl: config.nouns.pluralsRequired ? [''] : [],
femPl: config.nouns.pluralsRequired ? [''] : [],
neutrPl: config.nouns.pluralsRequired ? [''] : [],
sources: [],
base: null,
};
};
export default Vue.extend({
data() {
return {
form: {
masc: [''],
fem: [''],
neutr: [''],
mascPl: this.$config.nouns.pluralsRequired ? [''] : [],
femPl: this.$config.nouns.pluralsRequired ? [''] : [],
neutrPl: this.$config.nouns.pluralsRequired ? [''] : [],
sources: [],
base: null,
},
form: emptyForm(this.$config),
submitting: false,
afterSubmit: false,
templates: nounTemplates,
templateBase: '',
templateVisible: false,
abbreviations,
};
},
computed: {
templates() {
return nounTemplates.map((template) => {
return template.fill(this.templateBase || '-');
});
},
},
methods: {
async applyTemplate(template: MinimalNoun): Promise<void> {
if (JSON.stringify(this.form) !== JSON.stringify(emptyForm(this.$config))) {
await this.$confirm(this.$t('nouns.template.overwrite'));
}
this.form = template;
this.templateVisible = false;
},
async submit() {
this.submitting = true;
try {
await this.$post('/nouns/submit', this.form);
this.afterSubmit = true;
this.form = {
masc: [''],
fem: [''],
neutr: [''],
mascPl: this.$config.nouns.pluralsRequired ? [''] : [],
femPl: this.$config.nouns.pluralsRequired ? [''] : [],
neutrPl: this.$config.nouns.pluralsRequired ? [''] : [],
sources: [],
base: null,
};
this.form = emptyForm(this.$config);
this.templateVisible = false;
this.templateBase = '';
} finally {
this.submitting = false;
}
},
edit(word) {
edit(word: Noun): void {
this.form = {
masc: word.masc,
fem: word.fem,

View File

@ -177,8 +177,11 @@ nouns:
another: 'Submit another one'
moderation: 'Submissions will have to get approved before getting published.'
template: 'Use a template'
root: 'Root'
template:
header: 'Use a template'
root: 'Root'
apply: 'Apply template'
overwrite: 'Are you sure you want to apply this template? This will replace previous inputs'
masculine: 'masculine'
masculineShort: 'masc.'

View File

@ -156,8 +156,9 @@ nouns:
another: 'إرسال المزيد'
moderation: 'يجب أن يتم الموافقة على التقديمات المطروحة قبل إتمام نشرها.'
template: 'استخدام نموذج'
root: 'الجذر'
template:
header: 'استخدام نموذج'
root: 'الجذر'
masculine: 'مذكر'
masculineShort: 'ذكري'

View File

@ -155,14 +155,14 @@ export default {
A_pl: 'die Arbeitense',
}),
extendedDeclension: new NounDeclension({
N: 'meinens beste Lehrens',
G: 'meinens beste Lehrens',
D: 'meinens beste Lehrens',
A: 'meinens beste Lehrens',
N_pl: 'meine besten Lehrens',
G_pl: 'meiner besten Lehrens',
D_pl: 'meinen besten Lehrens',
A_pl: 'meine besten Lehrens',
N: 'meinens beste Lehrense',
G: 'meinens beste Lehrense',
D: 'meinens beste Lehrense',
A: 'meinens beste Lehrense',
N_pl: 'meine besten Lehrense',
G_pl: 'meiner besten Lehrense',
D_pl: 'meinen besten Lehrense',
A_pl: 'meine besten Lehrense',
}),
},
'ex-Formen': {
@ -240,7 +240,7 @@ export default {
A: 'die Arbeitsperson',
N_pl: 'die Arbeitspersonen',
G_pl: 'der Arbeitspersonen',
D_pl: 'den Arbeitspersonenn',
D_pl: 'den Arbeitspersonen',
A_pl: 'die Arbeitspersonen',
}),
extendedDeclension: new NounDeclension({
@ -250,7 +250,7 @@ export default {
A: 'meine beste Lehrperson',
N_pl: 'meine besten Lehrpersonen',
G_pl: 'meiner besten Lehrpersonen',
D_pl: 'meinen besten Lehrpersonenn',
D_pl: 'meinen besten Lehrpersonen',
A_pl: 'meine besten Lehrpersonen',
}),
},

View File

@ -1,3 +1,6 @@
masc fem neutr mascPl femPl neutrPl
-mann -frau -person -männer -frauen -leute
- -in -In/-:in/-*in -e -innen -Innen/-:innen/-*innen
der -mann die -frau die -person die -männer die -frauen die -leute
der - die -in das -y/de -e/din -nin/dens -ens/der:die -:in/der_die -_in/der*die -*in die -en die -innen die -ys/die -erne/die -ninnen/die -ense/die -:innen/die -_innen/die -*innen
der - die -in das -y/de -ere/din -nin/dens -ens/der:die -:in/der_die -_in/der*die -*in die -e die -innen die -ys/die -erne/die -ninnen/die -ense/die -:innen/die -_innen/die -*innen
der -e die -in das -y/de -ere/din -nin/dens -ens/der:die -:in/der_die -_in/der*die -*in die -en die -innen die -ys/die -erne/die -erninnen/die -ense/die -:innen/die -_innen/die -*innen
der -er die -erin das -y/de -ere/din -ernin/dens -ens/der:die -er:in/der_die -er_in/der*die -er*in die -er die -erinnen die -ys/de -erne/die -erninnen/die -ense/die -er:innen/die -er_innen/die -er*innen

1 masc fem neutr mascPl femPl neutrPl
2 -mann der -mann -frau die -frau -person die -person -männer die -männer -frauen die -frauen -leute die -leute
3 - der - -in die -in -In/-:in/-*in das -y/de -e/din -nin/dens -ens/der:die -:in/der_die -_in/der*die -*in -e die -en -innen die -innen -Innen/-:innen/-*innen die -ys/die -erne/die -ninnen/die -ense/die -:innen/die -_innen/die -*innen
4 der - die -in das -y/de -ere/din -nin/dens -ens/der:die -:in/der_die -_in/der*die -*in die -e die -innen die -ys/die -erne/die -ninnen/die -ense/die -:innen/die -_innen/die -*innen
5 der -e die -in das -y/de -ere/din -nin/dens -ens/der:die -:in/der_die -_in/der*die -*in die -en die -innen die -ys/die -erne/die -erninnen/die -ense/die -:innen/die -_innen/die -*innen
6 der -er die -erin das -y/de -ere/din -ernin/dens -ens/der:die -er:in/der_die -er_in/der*die -er*in die -er die -erinnen die -ys/de -erne/die -erninnen/die -ense/die -er:innen/die -er_innen/die -er*innen

View File

@ -177,8 +177,11 @@ nouns:
another: 'Einen weiteren Eintrag einreichen'
moderation: 'Einreichungen müssen erst genehmigt werden, bevor sie veröffentlicht werden.'
template: 'Eine Vorlage nutzen.'
root: 'Wurzel'
template:
header: 'Eine Vorlage nutzen'
root: 'Wurzel'
apply: 'Vorlage anwenden'
overwrite: 'Bist du sicher, dass du diese Vorlage anwenden möchtest? Sie ersetzt die vorherigen Eingaben'
masculine: 'Maskulin'
masculineShort: 'Mask.'

View File

@ -175,8 +175,11 @@ nouns:
another: 'Submit another one'
moderation: 'Submissions will have to get approved before getting published.'
template: 'Use a template'
root: 'Root'
template:
header: 'Use a template'
root: 'Root'
apply: 'Apply template'
overwrite: 'Are you sure you want to apply this template? This will replace previous inputs'
masculine: 'masculine'
masculineShort: 'masc.'

View File

@ -114,8 +114,9 @@ nouns:
Parolante pri la homo kies genro estas nekonata, al mult-genra grupo, kaj specife al neduumuloj kiuj malferme
preferas ilin, uzu la formojn neŭtralajn. [*enmeti iun aldonon pri -ip- sufikso]
- 'Sube estas la vortaro de neŭtralaĵoj. Vi povas kontribui al ĝi kaj aldoni viajn proponojn.'
template: 'Uzi ŝablonon'
root: 'Radiko'
template:
header: 'Uzi ŝablonon'
root: 'Radiko'
masculine: 'vira'
masculineShort: 'vira'

View File

@ -164,8 +164,9 @@ nouns:
another: 'Enviar otra'
moderation: 'Los envíos deben ser aprobados antes de ser publicados.'
template: 'Usar una plantilla'
root: 'Raíz'
template:
header: 'Usar una plantilla'
root: 'Raíz'
masculine: 'masculino'
masculineShort: 'masc.'

View File

@ -142,8 +142,9 @@ nouns:
another: 'Esita veel üks'
moderation: 'Pakkumised kinnitatakse enne avaldamist moderaatori poolt.'
template: 'Kasuta malli'
root: 'Juur'
template:
header: 'Kasuta malli'
root: 'Juur'
masculine: 'mehelik'
masculineShort: 'meh.'

View File

@ -159,7 +159,8 @@ nouns:
another: 'Soumettre un autre mot'
moderation: 'Les soumissions devront être approuvées avant dêtre publiées.'
template: 'Utiliser un template'
template:
header: 'Utiliser un template'
masculine: 'masculin'
masculineShort: 'masc.'

View File

@ -154,8 +154,9 @@ nouns:
another: 'Enviar outra'
moderation: 'Os envios devem ser aprovados antes de serem publicados.'
template: 'Usar um modelo'
root: 'Radical'
template:
header: 'Usar um modelo'
root: 'Radical'
masculine: 'masculino'
masculineShort: 'masc.'

View File

@ -157,8 +157,9 @@ nouns:
another: 'Inviane unaltra'
moderation: 'Le proposte dovranno essere approvate prima di essere pubblicate.'
template: 'usa un template'
root: 'Radice'
template:
header: 'usa un template'
root: 'Radice'
masculine: 'maschile'
masculineShort: 'masc.'

View File

@ -150,7 +150,8 @@ nouns:
submit:
moderation: '公開前に管理者による承認が必要です。'
template: 'テンプレートを使う'
template:
header: 'テンプレートを使う'
community:
header: 'コミュニティ'

View File

@ -159,8 +159,9 @@ nouns:
another: '더 추가하기'
moderation: '제출물은 게시되기 전에 승인을 받아야 합니다.'
template: '템플릿 쓰기'
root: '룻'
template:
header: '템플릿 쓰기'
root: '룻'
masculine: '남성 명사'
masculineShort: '남성'

View File

@ -157,8 +157,9 @@ nouns:
another: 'Embiar otruno'
moderation: 'Los embios deven ser aseptados antes de ser publikados.'
template: 'Uzar una plantiya'
root: 'Rais'
template:
header: 'Uzar una plantiya'
root: 'Rais'
masculine: 'maskulino'
masculineShort: 'mask.'

View File

@ -156,7 +156,8 @@ nouns:
another: 'Dien nog een woord in'
moderation: 'Inzendingen zullen moeten worden goedgekeurd alvorens te worden gepubliceerd.'
template: 'Gebruik een sjabloon'
template:
header: 'Gebruik een sjabloon'
masculine: 'mannelijk'
masculineShort: 'mann.'

View File

@ -151,8 +151,9 @@ nouns:
another: 'Legg til en annen'
moderation: 'Bidrag må bli vurdert før de blir lagt ut.'
template: 'Bruk en mal'
root: 'Rot'
template:
header: 'Bruk en mal'
root: 'Rot'
masculine: 'maskulin'
masculineShort: 'mask.'

View File

@ -300,8 +300,9 @@ nouns:
another: 'Zgłoś kolejne słowo'
moderation: 'Propozycje będą musiały zostać zatwierdzone przed opublikowaniem.'
template: 'Użyj szablonu'
root: 'Rdzeń rzeczownika'
template:
header: 'Użyj szablonu'
root: 'Rdzeń rzeczownika'
masculine: 'maskulatyw'
masculineShort: 'mask.'

View File

@ -168,8 +168,9 @@ nouns:
another: 'Enviar outra'
moderation: 'Os envios devem ser aprovados antes de serem publicados.'
template: 'Usar um modelo'
root: 'Radical'
template:
header: 'Usar um modelo'
root: 'Radical'
masculine: 'masculino'
masculineShort: 'masc.'

View File

@ -161,8 +161,9 @@ nouns:
another: 'Trimite încă unul'
moderation: 'Contribuțiile trebuie să fie aprobate înainte de a apărea.'
template: 'Folosește un șablon'
root: 'Rădăcină'
template:
header: 'Folosește un șablon'
root: 'Rădăcină'
masculine: 'masculin'
masculineShort: 'masc.'

View File

@ -183,8 +183,9 @@ nouns:
another: 'Добавить ещё'
moderation: 'Предложения должны быть одобрены перед публикацией.'
template: 'Использовать шаблон'
root: 'Корень'
template:
header: 'Использовать шаблон'
root: 'Корень'
masculine: 'мужской'
masculineShort: 'м.'

View File

@ -163,8 +163,9 @@ nouns:
another: 'Skicka in en till'
moderation: 'Bidragen måste godkännas innan de publiceras.'
template: 'Använd en mall'
root: 'Rot'
template:
header: 'Använd en mall'
root: 'Rot'
masculine: 'maskulin'
masculineShort: 'mask.'

View File

@ -147,8 +147,9 @@ nouns:
another: 'Başka bir kelime gönder'
moderation: 'Gönderimlerin yayınlanmadan önce onaylanması gerekecektir.'
template: 'Şablon kullan'
root: 'Kökü'
template:
header: 'Şablon kullan'
root: 'Kökü'
masculine: 'maskülen'
masculineShort: 'mask.'

View File

@ -188,8 +188,9 @@ nouns:
another: 'Додати ще'
moderation: 'Пропозиції мають бути схвалені перед публікацією.'
template: 'Використати шаблон'
root: 'Корінь'
template:
header: 'Використати шаблон'
root: 'Корінь'
masculine: 'чоловічий'
masculineShort: 'ч.'

View File

@ -165,7 +165,8 @@ nouns:
another: 'Gửi thêm'
moderation: 'Các từ sẽ phải được phê duyệt trước khi được thêm vào.'
template: 'Sử dụng một mẫu'
template:
header: 'Sử dụng một mẫu'
masculine: 'nam tính'
masculineShort: 'nam'

View File

@ -148,8 +148,9 @@ nouns:
another: '提交另一個'
moderation: '提交的內容必須先批准才能發布。'
template: '使用模板'
root: '根'
template:
header: '使用模板'
root: '根'
# TODO: 陽剛 and 陰柔 sounds waaay better than (translated) men-ish and woman-ish
# but i'm not exactly sure about the implications and how other people see them

View File

@ -875,6 +875,9 @@ export interface NounRaw {
declension: unknown;
}
export const genders = ['masc', 'fem', 'neutr'] as const;
const gendersWithNumerus = ['masc', 'fem', 'neutr', 'mascPl', 'femPl', 'neutrPl'] as const;
export class Noun {
id: string;
masc: string[];
@ -914,7 +917,7 @@ export class Noun {
return true;
}
for (const field of ['masc', 'fem', 'neutr', 'mascPl', 'femPl', 'neutrPl'] as const) {
for (const field of gendersWithNumerus) {
for (const value of this[field]) {
const v = value.toLowerCase();
if (filter.startsWith('-') && v.endsWith(filter.substring(1))) {
@ -930,6 +933,8 @@ export class Noun {
}
}
export type MinimalNoun = Pick<Noun, typeof gendersWithNumerus[number] | 'sources' | 'base'>;
export class NounTemplate {
masc: string[];
fem: string[];
@ -947,21 +952,33 @@ export class NounTemplate {
this.neutrPl = neutrPl;
}
fill(stem: string) {
static from(data: Record<typeof gendersWithNumerus[number], string>): NounTemplate {
return new NounTemplate(
data.masc.split('/'),
data.fem.split('/'),
data.neutr.split('/'),
data.mascPl.split('/'),
data.femPl.split('/'),
data.neutrPl.split('/'),
);
}
fill(stem: string): MinimalNoun {
return {
masc: this.masc.map((e) => stem + e),
fem: this.fem.map((e) => stem + e),
neutr: this.neutr.map((e) => stem + e),
mascPl: this.mascPl.map((e) => stem + e),
femPl: this.femPl.map((e) => stem + e),
neutrPl: this.neutrPl.map((e) => stem + e),
masc: this.masc.map((e) => e.replace('-', stem)),
fem: this.fem.map((e) => e.replace('-', stem)),
neutr: this.neutr.map((e) => e.replace('-', stem)),
mascPl: this.mascPl.map((e) => e.replace('-', stem)),
femPl: this.femPl.map((e) => e.replace('-', stem)),
neutrPl: this.neutrPl.map((e) => e.replace('-', stem)),
sources: [],
base: null,
};
}
toString(): string {
return [this.masc, this.fem, this.neutr, this.mascPl, this.femPl, this.neutrPl]
.map((es) => es.map((e) => `-${e}`).join('/'))
.map((es) => es.join('/'))
.join(', ')
;
}

View File

@ -20,14 +20,7 @@ export const examples = buildList(function* () {
import nounTemplatesRaw from '../data/nouns/nounTemplates.tsv';
export const nounTemplates = buildList(function* () {
for (const t of nounTemplatesRaw) {
yield new NounTemplate(
t.masc.replace(/-/g, '').split('/'),
t.fem.replace(/-/g, '').split('/'),
t.neutr.replace(/-/g, '').split('/'),
t.mascPl.replace(/-/g, '').split('/'),
t.femPl.replace(/-/g, '').split('/'),
t.neutrPl.replace(/-/g, '').split('/'),
);
yield NounTemplate.from(t);
}
});

View File

@ -128,6 +128,10 @@ export function listMissingTranslations(
return false;
}
if (!config.nouns.templates && keyMatches('nouns.template.')) {
return false;
}
if (!config.terminology.enabled && keyMatches('terminology.')) {
return false;
}