PronounsPage/locale/pl/nouns/iksatywy.vue
Valentyne Stigloher 10180aa6a3 (refactor) use #shared alias instead of ~~/shared
the #shared alias used by Nuxt cannot be easily disabled and to prevent breackage with jiti, we make use of it
2025-08-17 18:56:02 +02:00

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 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>