mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-27 06:52:35 -04:00

the #shared alias used by Nuxt cannot be easily disabled and to prevent breackage with jiti, we make use of it
375 lines
12 KiB
Vue
375 lines
12 KiB
Vue
<script setup lang="ts">
|
|
import { useNuxtApp } from 'nuxt/app';
|
|
|
|
import NounsNav from './NounsNav.vue';
|
|
import templates from './iksatywy.tsv';
|
|
|
|
import { Noun, SourceLibrary } from '#shared/classes.ts';
|
|
import type { Source } from '#shared/classes.ts';
|
|
import { removeSuffix } from '#shared/helpers.ts';
|
|
import { neutralGenderNameInjectionKey } from '#shared/injectionKeys.ts';
|
|
import { availableGenders, genders, numeri, symbolsByNumeri } from '#shared/nouns.ts';
|
|
import type { NounWords, NounDeclension } from '#shared/nouns.ts';
|
|
import useConfig from '~/composables/useConfig.ts';
|
|
import type { NounTemplatesData } from '~~/locale/data.ts';
|
|
|
|
definePageMeta({
|
|
translatedPaths: (config) => translatedPathForSingleLocale(config, 'pl', 'iksatywy'),
|
|
});
|
|
|
|
const xDeclension: NounDeclension = {
|
|
singular: {
|
|
m: ['x'],
|
|
d: ['x'],
|
|
c: ['x'],
|
|
b: ['x'],
|
|
n: ['x'],
|
|
msc: ['x'],
|
|
w: ['x'],
|
|
},
|
|
plural: {
|
|
m: ['xx'],
|
|
d: ['xx'],
|
|
c: ['xx'],
|
|
b: ['xx'],
|
|
n: ['xx'],
|
|
msc: ['xx'],
|
|
w: ['xx'],
|
|
},
|
|
};
|
|
|
|
const xTkaDeclension: NounDeclension = {
|
|
singular: {
|
|
m: ['txa'],
|
|
d: ['txy'],
|
|
c: ['txie'],
|
|
b: ['txę'],
|
|
n: ['txą'],
|
|
msc: ['txie'],
|
|
w: ['txo'],
|
|
},
|
|
plural: {
|
|
m: ['txx'],
|
|
d: ['txx'],
|
|
c: ['txx'],
|
|
b: ['txx'],
|
|
n: ['txx'],
|
|
msc: ['txx'],
|
|
w: ['txx'],
|
|
},
|
|
};
|
|
|
|
const { $translator: translator } = useNuxtApp();
|
|
const config = useConfig();
|
|
|
|
useSimpleHead({
|
|
title: translator.translate('nouns.xNouns.header'),
|
|
banner: `img/${config.locale}/flags/iksatywy.png`,
|
|
description: translator.translate('nouns.xNouns.info')[0],
|
|
}, translator);
|
|
|
|
provide(neutralGenderNameInjectionKey, translator.translate('nouns.xNouns.label'));
|
|
|
|
const xNouns = [
|
|
new Noun(config, {
|
|
id: 'astronauta',
|
|
words: {
|
|
masc: {
|
|
singular: [{ spelling: 'astronauta' }],
|
|
plural: [{ spelling: 'astronauci' }],
|
|
},
|
|
fem: {
|
|
singular: [{ spelling: 'astronautka' }],
|
|
plural: [{ spelling: 'astronautki' }],
|
|
},
|
|
neutr: {
|
|
singular: [{ spelling: 'astronau', declension: xTkaDeclension }],
|
|
plural: [{ spelling: 'astronau', declension: xTkaDeclension }],
|
|
},
|
|
},
|
|
}),
|
|
new Noun(config, {
|
|
id: 'Europejczyk',
|
|
words: {
|
|
masc: {
|
|
singular: [{ spelling: 'Europejczyk' }],
|
|
plural: [{ spelling: 'Europejczycy' }],
|
|
},
|
|
fem: {
|
|
singular: [{ spelling: 'Europejka' }],
|
|
plural: [{ spelling: 'Europejki' }],
|
|
},
|
|
neutr: {
|
|
singular: [{ spelling: 'Europejk', declension: xDeclension }],
|
|
plural: [{ spelling: 'Europejk', declension: xDeclension }],
|
|
},
|
|
},
|
|
}),
|
|
new Noun(config, {
|
|
id: 'przyjaciel',
|
|
words: {
|
|
masc: {
|
|
singular: [{ spelling: 'przyjaciel' }],
|
|
plural: [{ spelling: 'przyjaciele' }],
|
|
},
|
|
fem: {
|
|
singular: [{ spelling: 'przyjaciółka' }],
|
|
plural: [{ spelling: 'przyjaciółki' }],
|
|
},
|
|
neutr: {
|
|
singular: [{ spelling: 'przyjacioł', declension: xDeclension }],
|
|
plural: [{ spelling: 'przyjacioł', declension: xDeclension }],
|
|
},
|
|
},
|
|
}),
|
|
new Noun(config, {
|
|
id: 'twórca',
|
|
words: {
|
|
masc: {
|
|
singular: [{ spelling: 'twórca' }],
|
|
plural: [{ spelling: 'twórcy' }],
|
|
},
|
|
fem: {
|
|
singular: [{ spelling: 'twórczyni' }],
|
|
plural: [{ spelling: 'twórczynie' }],
|
|
},
|
|
neutr: {
|
|
singular: [{ spelling: 'twórc', declension: xDeclension }],
|
|
plural: [{ spelling: 'twórc', declension: xDeclension }],
|
|
},
|
|
},
|
|
}),
|
|
new Noun(config, {
|
|
id: 'radny',
|
|
words: {
|
|
masc: {
|
|
singular: [{ spelling: 'radny' }],
|
|
plural: [{ spelling: 'radni' }],
|
|
},
|
|
fem: {
|
|
singular: [{ spelling: 'radna' }],
|
|
plural: [{ spelling: 'radne' }],
|
|
},
|
|
neutr: {
|
|
singular: [{ spelling: 'radn', declension: xDeclension }],
|
|
plural: [{ spelling: 'radn', declension: xDeclension }],
|
|
},
|
|
},
|
|
}),
|
|
];
|
|
const xExtendedDeclension: NounDeclension = {
|
|
singular: {
|
|
m: ['tx kosmicznx twórcx'],
|
|
d: ['tx kosmicznx twórcx'],
|
|
c: ['tx kosmicznx twórcx'],
|
|
b: ['tx kosmicznx twórcx'],
|
|
n: ['tx kosmicznx twórcx'],
|
|
msc: ['tx kosmicznx twórcx'],
|
|
w: ['tx kosmicznx twórcx'],
|
|
},
|
|
plural: {
|
|
m: ['txx kosmicznxx twórcxx'],
|
|
d: ['txx kosmicznxx twórcxx'],
|
|
c: ['txx kosmicznxx twórcxx'],
|
|
b: ['txx kosmicznxx twórcxx'],
|
|
n: ['txx kosmicznxx twórcxx'],
|
|
msc: ['txx kosmicznxx twórcxx'],
|
|
w: ['txx kosmicznxx twórcxx'],
|
|
},
|
|
};
|
|
|
|
const generatorWord = ref('fotograf');
|
|
|
|
const template = computed((): NounTemplatesData | null => {
|
|
let longestMatch = 0;
|
|
let matchingTemplates: NounTemplatesData[] = [];
|
|
for (const t of templates) {
|
|
if (!generatorWord.value.endsWith(t.masc)) {
|
|
continue;
|
|
}
|
|
if (t.masc.length > longestMatch) {
|
|
longestMatch = t.masc.length;
|
|
matchingTemplates = [t];
|
|
} else if (t.masc.length === longestMatch) {
|
|
matchingTemplates.push(t);
|
|
}
|
|
}
|
|
|
|
if (!matchingTemplates.length) {
|
|
return null;
|
|
}
|
|
|
|
return matchingTemplates[0];
|
|
});
|
|
const generatorResult = computed(() => {
|
|
if (!template.value) {
|
|
return null;
|
|
}
|
|
|
|
const root = generatorWord.value.substring(0, generatorWord.value.length - (template.value.masc?.length ?? 0));
|
|
|
|
const words: NounWords = {};
|
|
for (const gender of genders) {
|
|
for (const numerus of numeri) {
|
|
const genderWithNumerus = `${gender}${numerus === 'singular' ? '' : 'Pl'}` as const;
|
|
words[gender] ??= {};
|
|
words[gender][numerus] = (template.value[genderWithNumerus] ?? '').split('/').map((ending) => {
|
|
return {
|
|
spelling: root + removeSuffix(ending, xDeclension[numerus]!.m[0]),
|
|
declension: xDeclension,
|
|
};
|
|
});
|
|
}
|
|
}
|
|
|
|
return new Noun(config, { id: 'generator', words });
|
|
});
|
|
|
|
const sources = ref<Record<string, Source[] | undefined>>();
|
|
onMounted(async () => {
|
|
const rawSources = await $fetch('/api/sources', { query: { pronoun: 'iksatywy' } });
|
|
sources.value = {
|
|
'': new SourceLibrary(config, rawSources).getForPronoun('iksatywy'),
|
|
};
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<Page>
|
|
<NounsNav />
|
|
|
|
<h2>
|
|
<Icon v="comment-times" />
|
|
<T>nouns.xNouns.header</T>
|
|
</h2>
|
|
|
|
<div class="d-flex flex-column flex-md-row">
|
|
<div>
|
|
<T>nouns.xNouns.info</T>
|
|
<CensusStat type="nouns" item="iksatywy" colour="info" />
|
|
<Share :title="$t('nouns.xNouns.header')" />
|
|
</div>
|
|
<figure>
|
|
<img src="/img/pl/flags/iksatywy.svg" :alt="$t('nouns.xNouns.flag.alt')">
|
|
<!-- <figcaption><T>nouns.xNouns.flag.caption</T></figcaption> -->
|
|
|
|
<details class="small mt-3">
|
|
<summary>
|
|
<Icon v="user-friends" />
|
|
Autorstwo
|
|
</summary>
|
|
<ul>
|
|
<li>Projekt: <nuxt-link to="/@andrea">@andrea</nuxt-link></li>
|
|
<li>Flaga osób niebinarych <a href="https://commons.wikimedia.org/wiki/File:Nonbinary_flag.svg" target="_blank" rel="noopener">Kye Rowan</a> (public domain)</li>
|
|
</ul>
|
|
</details>
|
|
</figure>
|
|
</div>
|
|
|
|
<details open class="border mb-3">
|
|
<summary class="bg-light p-3">
|
|
<h4 class="h5 d-inline">
|
|
<T>nouns.examples</T>
|
|
</h4>
|
|
</summary>
|
|
<div class="border-top table-responsive nouns-table">
|
|
<div class="container">
|
|
<div class="row-header p-2 d-grid gap-2 border-top">
|
|
<div v-for="gender of availableGenders(config)" :key="gender" class="d-none d-md-block bold">
|
|
<NounsGenderLabel :gender />
|
|
</div>
|
|
</div>
|
|
<div></div>
|
|
<div
|
|
v-for="noun of xNouns"
|
|
:key="noun.id"
|
|
class="row-content p-2 d-grid gap-2 border-top"
|
|
>
|
|
<NounsTableEntry :noun />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
|
|
<details open class="border mb-3">
|
|
<summary class="bg-light p-3">
|
|
<h4 class="h5 d-inline">
|
|
<T>nouns.xNouns.extended.header</T>
|
|
</h4>
|
|
</summary>
|
|
<div class="border-top">
|
|
<div class="d-flex flex-column flex-md-row">
|
|
<div v-for="numerus of numeri" :key="numerus" class="p-3">
|
|
<h5>{{ symbolsByNumeri[numerus] }} <T>nouns.{{ numerus }}</T></h5>
|
|
<NounsDeclension :word="{ spelling: '', declension: xExtendedDeclension }" :numerus />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
|
|
<details open class="border mb-3">
|
|
<summary class="bg-light p-3">
|
|
<h4 class="h5 d-inline">
|
|
Generator
|
|
</h4>
|
|
</summary>
|
|
<div class="border-top p-3">
|
|
<p>
|
|
Końcówki iksatywów są proste i regularne, dlatego stworzyłośmy poniższy automatyczny generator.
|
|
Jest on z natury uproszczony, dlatego prosimy nie traktować go zbyt poważnie, kod może czasem tworzyć dziwne formy 😉
|
|
</p>
|
|
<p>
|
|
Wpisz poniżej dowolny rzeczownik określający osobę,
|
|
<strong>w rodzaju męskim liczby pojedynczej</strong>:
|
|
</p>
|
|
<div class="form-group">
|
|
<input v-model="generatorWord" class="form-control" placeholder="Wpisz rzeczownik w rodzaju męskim liczby pojedynczej">
|
|
</div>
|
|
<div v-if="generatorResult" class="table-responsive nouns-table">
|
|
<div class="container">
|
|
<div class="row-header p-2 d-grid gap-2 border-top">
|
|
<div v-for="gender of availableGenders(config)" :key="gender" class="d-none d-md-block bold">
|
|
<NounsGenderLabel :gender />
|
|
</div>
|
|
</div>
|
|
<div></div>
|
|
<div class="row-content p-2 d-grid gap-2 border-top">
|
|
<NounsTableEntry :noun="generatorResult" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="alert alert-warning">
|
|
<p class="mb-0">
|
|
Niestety, podane słowo nie pasuje do żadnego naszego szablonu
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
|
|
<section v-if="sources && Object.keys(sources).length">
|
|
<Literature :sources="sources" />
|
|
</section>
|
|
</Page>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
@import "../../../app/assets/variables";
|
|
|
|
figure {
|
|
width: 100%;
|
|
max-width: 24rem;
|
|
padding: $spacer;
|
|
img {
|
|
width: 100%;
|
|
}
|
|
figcaption {
|
|
font-size: $small-font-size;
|
|
}
|
|
}
|
|
@include media-breakpoint-up('md') {
|
|
figure {
|
|
min-width: 20rem;
|
|
}
|
|
}
|
|
</style>
|