django-polish-inflection 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. django_polish_inflection-0.1.0/.github/workflows/ci.yml +52 -0
  2. django_polish_inflection-0.1.0/.gitignore +14 -0
  3. django_polish_inflection-0.1.0/.pre-commit-config.yaml +16 -0
  4. django_polish_inflection-0.1.0/LICENSE +24 -0
  5. django_polish_inflection-0.1.0/PKG-INFO +273 -0
  6. django_polish_inflection-0.1.0/README.md +245 -0
  7. django_polish_inflection-0.1.0/example_project/README.md +49 -0
  8. django_polish_inflection-0.1.0/example_project/demo/__init__.py +0 -0
  9. django_polish_inflection-0.1.0/example_project/demo/apps.py +6 -0
  10. django_polish_inflection-0.1.0/example_project/demo/templates/demo/base.html +56 -0
  11. django_polish_inflection-0.1.0/example_project/demo/templates/demo/index.html +23 -0
  12. django_polish_inflection-0.1.0/example_project/demo/templates/demo/odmien.html +50 -0
  13. django_polish_inflection-0.1.0/example_project/demo/templates/demo/podaj.html +65 -0
  14. django_polish_inflection-0.1.0/example_project/demo/views.py +86 -0
  15. django_polish_inflection-0.1.0/example_project/manage.py +16 -0
  16. django_polish_inflection-0.1.0/example_project/odmieniarka/__init__.py +0 -0
  17. django_polish_inflection-0.1.0/example_project/odmieniarka/settings.py +65 -0
  18. django_polish_inflection-0.1.0/example_project/odmieniarka/urls.py +8 -0
  19. django_polish_inflection-0.1.0/example_project/odmieniarka/wsgi.py +6 -0
  20. django_polish_inflection-0.1.0/pyproject.toml +58 -0
  21. django_polish_inflection-0.1.0/src/django_polish_inflection/__init__.py +1 -0
  22. django_polish_inflection-0.1.0/src/django_polish_inflection/conf.py +30 -0
  23. django_polish_inflection-0.1.0/src/django_polish_inflection/templatetags/__init__.py +0 -0
  24. django_polish_inflection-0.1.0/src/django_polish_inflection/templatetags/polish_inflection.py +156 -0
  25. django_polish_inflection-0.1.0/sshot1.png +0 -0
  26. django_polish_inflection-0.1.0/tests/test_conf.py +17 -0
  27. django_polish_inflection-0.1.0/tests/test_frazy.py +114 -0
  28. django_polish_inflection-0.1.0/tests/test_override.py +89 -0
  29. django_polish_inflection-0.1.0/tests/test_readme_examples.py +146 -0
  30. django_polish_inflection-0.1.0/tests/test_smoke.py +7 -0
  31. django_polish_inflection-0.1.0/tests/test_tags.py +248 -0
  32. django_polish_inflection-0.1.0/tests/testproject/__init__.py +0 -0
  33. django_polish_inflection-0.1.0/tests/testproject/settings.py +15 -0
@@ -0,0 +1,52 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ test:
17
+ name: py${{ matrix.python-version }} / dj${{ matrix.django-version }}
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
23
+ django-version: ["5.2", "6.0"]
24
+ exclude:
25
+ # Django 6.0 wymaga Pythona >= 3.12
26
+ - python-version: "3.10"
27
+ django-version: "6.0"
28
+ - python-version: "3.11"
29
+ django-version: "6.0"
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+ - uses: actions/setup-python@v5
33
+ with:
34
+ python-version: ${{ matrix.python-version }}
35
+ - name: Install
36
+ run: |
37
+ python -m pip install --upgrade pip
38
+ pip install -e .
39
+ pip install "django==${{ matrix.django-version }}.*" pytest pytest-django
40
+ - name: Test
41
+ run: pytest -q
42
+
43
+ lint:
44
+ name: ruff
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+ - uses: actions/setup-python@v5
49
+ with:
50
+ python-version: "3.13"
51
+ - run: pip install ruff
52
+ - run: ruff check .
@@ -0,0 +1,14 @@
1
+ .superpowers/
2
+ .venv/
3
+ __pycache__/
4
+ *.pyc
5
+ uv.lock
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ .DS_Store
12
+
13
+ # wewnętrzne dokumenty planistyczne (superpowers)
14
+ docs/superpowers/
@@ -0,0 +1,16 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v6.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-toml
9
+ - id: check-added-large-files
10
+ - id: detect-private-key
11
+ - repo: https://github.com/astral-sh/ruff-pre-commit
12
+ rev: v0.15.20
13
+ hooks:
14
+ - id: ruff-check
15
+ args: [--fix]
16
+ - id: ruff-format
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, Michał Pasternak
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,273 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-polish-inflection
3
+ Version: 0.1.0
4
+ Summary: Cienka warstwa Django (template tagi i filtry) nad polish-inflection — odmiana rzeczowników przez przypadki.
5
+ Project-URL: Homepage, https://github.com/iplweb/django-polish-inflection
6
+ Project-URL: Repository, https://github.com/iplweb/django-polish-inflection
7
+ Project-URL: Issues, https://github.com/iplweb/django-polish-inflection/issues
8
+ Author-email: Michał Pasternak <m@iplweb.pl>
9
+ License: BSD-2-Clause
10
+ License-File: LICENSE
11
+ Keywords: declension,django,inflection,odmiana,polish,przypadki,templatetags
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: Django
14
+ Classifier: Framework :: Django :: 5.2
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: BSD License
17
+ Classifier: Natural Language :: Polish
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Text Processing :: Linguistic
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: django>=5.2
26
+ Requires-Dist: polish-inflection>=0.7.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # django-polish-inflection
30
+
31
+ [![CI](https://github.com/iplweb/django-polish-inflection/actions/workflows/ci.yml/badge.svg)](https://github.com/iplweb/django-polish-inflection/actions/workflows/ci.yml)
32
+ [![License: BSD-2-Clause](https://img.shields.io/badge/License-BSD--2--Clause-blue.svg)](LICENSE)
33
+
34
+ Cienka warstwa Django (template tagi i filtry) nad
35
+ [`polish-inflection`](https://github.com/iplweb/polish-inflection) —
36
+ odmiana polszczyzny wprost w szablonach Django, oparta o słownik SGJP:
37
+
38
+ - **rzeczowniki** przez wszystkie przypadki i obie liczby (`odmien`,
39
+ aliasy pytajne `kogo_czego`/`komu_czemu`/…),
40
+ - **frazy wielowyrazowe** (nazwy własne instytucji, np. „Uniwersytet
41
+ Lubelski") — `odmien_fraze`,
42
+ - **przymiotniki** wg rodzaju głowy — `odmien_przymiotnik`,
43
+ - **dobór formy wg liczebnika** (1 wydział / 2 wydziały / 5 wydziałów) —
44
+ `odmiana_liczebnikowa`.
45
+
46
+ <p align="center">
47
+ <img src="https://raw.githubusercontent.com/iplweb/django-polish-inflection/v0.1.0/sshot1.png" alt="Odmieniarka — przykładowy projekt: pełna tabela odmiany przez przypadki" width="640">
48
+ <br>
49
+ <sub><i>Przykładowy projekt <a href="example_project/">„Odmieniarka"</a> — pełna tabela odmiany przez przypadki wprost w przeglądarce.</i></sub>
50
+ </p>
51
+
52
+ <p align="center">
53
+ <b>Support graciously provided by</b><br><br>
54
+ <a href="https://www.iplweb.pl"><img src="https://www.iplweb.pl/images/ipl-logo-large.png" width="120" alt="IPLweb"></a>
55
+ </p>
56
+
57
+ ## Instalacja
58
+
59
+ ```bash
60
+ pip install django-polish-inflection
61
+ ```
62
+
63
+ Dodaj do `INSTALLED_APPS`:
64
+
65
+ ```python
66
+ INSTALLED_APPS = [
67
+ ...,
68
+ "django_polish_inflection",
69
+ ]
70
+ ```
71
+
72
+ ## Użycie
73
+
74
+ Wczytaj bibliotekę tagów raz na szablon przez `{% load polish_inflection %}` — od
75
+ tej chwili masz w szablonie cztery narzędzia: generyczny `odmien` (dowolny
76
+ przypadek), zestaw czytelnych aliasów pytajnych (`kogo_czego`, `komu_czemu`, …),
77
+ dobór formy wg liczebnika (`odmiana_liczebnikowa`) i odmianę wielowyrazowych nazw
78
+ własnych (`odmien_fraze`). Większość działa i jako **tag** `{% … %}`, i — gdy
79
+ wystarczy sam przypadek — jako **filtr** `|…`; oba warianty zwracają to samo.
80
+
81
+ ```django
82
+ {% load polish_inflection %}
83
+ ```
84
+
85
+ Dla przykładowych danych `nazwa_jednostki = "wydział"` i `liczba = 5`
86
+ (w komentarzach `{# → … #}` jest wynik renderowania):
87
+
88
+ **Dowolny przypadek — generyczny `odmien`** (w tym mianownik i wołacz, których
89
+ aliasów pytajnych brak):
90
+
91
+ ```django
92
+ {{ nazwa_jednostki|odmien:"dopelniacz" }}
93
+ {# → wydziału #}
94
+
95
+ {% odmien nazwa_jednostki "dopelniacz" %}
96
+ {# → wydziału #}
97
+
98
+ {% odmien nazwa_jednostki "dopelniacz" liczba="mnoga" %}
99
+ {# → wydziałów #}
100
+
101
+ {% odmien nazwa_jednostki "dopelniacz" as forma %}{{ forma }}
102
+ {# → wydziału #}
103
+ ```
104
+
105
+ **Aliasy pytajne** — czytają się jak zdanie, wystawiane automatycznie z
106
+ `polish_inflection.pytania`:
107
+
108
+ ```django
109
+ Oto lista pracowników {% kogo_czego nazwa_jednostki %}
110
+ {# → Oto lista pracowników wydziału #}
111
+
112
+ Kliknij przycisk z {% z_kim_z_czym nazwa_jednostki %}
113
+ {# → Kliknij przycisk z wydziałem #}
114
+
115
+ {% komu_czemu nazwa_jednostki liczba="mnoga" %}
116
+ {# → wydziałom #}
117
+
118
+ {% podstawowa_forma "wydziałów" %}
119
+ {# → wydział #}
120
+ ```
121
+
122
+ **Dobór formy wg liczebnika** — polska zgoda liczebnikowa (1 wydział / 2 wydziały
123
+ / 5 wydziałów); numer doklejasz sam:
124
+
125
+ ```django
126
+ {{ liczba }} {% odmiana_liczebnikowa nazwa_jednostki liczba %}
127
+ {# → 5 wydziałów #}
128
+
129
+ {% odmiana_liczebnikowa nazwa_jednostki liczba "narzednik" %}
130
+ {# → wydziałami #}
131
+ ```
132
+
133
+ **Frazy wielowyrazowe i przymiotniki** — nazwy własne instytucji oraz sam
134
+ przymiotnik wg rodzaju:
135
+
136
+ ```django
137
+ {% odmien_fraze "Uniwersytet Lubelski" "dopelniacz" %}
138
+ {# → Uniwersytetu Lubelskiego #}
139
+
140
+ {{ "Akademia Medyczna"|odmien_fraze:"narzednik" }}
141
+ {# → Akademią Medyczną #}
142
+
143
+ {% odmien_przymiotnik "lubelski" "dopelniacz" "meski" %}
144
+ {# → lubelskiego #}
145
+ ```
146
+
147
+ Dostępne aliasy pytajne (dokładnie te, które eksportuje zainstalowana wersja
148
+ `polish_inflection.pytania.__all__` — nowe funkcje upstreamu o zgodnej
149
+ sygnaturze `(wyraz, *, liczba=None, default=...)` pojawiają się tu
150
+ automatycznie): `kogo_czego`, `komu_czemu`, `kogo_co`, `z_kim_z_czym`,
151
+ `o_kim_o_czym`, `podstawowa_forma`, oraz skróty `komu`, `czemu`, `z_kim`,
152
+ `z_czym`, `o_kim`, `o_czym`.
153
+
154
+ Mianownik i wołacz nie mają aliasu pytajnego (upstream też ich nie ma) —
155
+ używaj do nich generycznego `{% odmien wyraz "mianownik" %}` / `"wolacz"`.
156
+
157
+ ### Odmiana liczebnikowa
158
+
159
+ `{% odmiana_liczebnikowa wyraz liczba %}` zwraca **rzeczownik** w formie
160
+ narzuconej przez liczebnik (polska zgoda liczebnikowa: `1 wydział`,
161
+ `2 wydziały`, `5 wydziałów`). Liczby słownie nie generuje — numer doklejasz
162
+ sam. Rodzaj (w tym męskoosobowy m1, np. `2 studentów` a nie `2 studenci`) jest
163
+ wykrywany automatycznie ze słownika. Opcjonalny trzeci argument to przypadek
164
+ frazy (domyślnie mianownik), np. `{% odmiana_liczebnikowa wyraz liczba "narzednik" %}`
165
+ przy `liczba=5` zwraca `wydziałami` (liczebnik „pięcioma" doklejasz sam).
166
+ Kolejność argumentów jest jak w pozostałych tagach: `wyraz` pierwszy.
167
+
168
+ ### Odmiana fraz wielowyrazowych (nazw własnych instytucji)
169
+
170
+ `{% odmien_fraze fraza "przypadek" %}` odmienia **wielowyrazowe nazwy własne**
171
+ instytucji — uczelni, wydziałów, instytutów — a nie tylko pojedyncze
172
+ rzeczowniki. Silnik rozpoznaje głowę frazy, odmienia ją wraz z uzgadniającymi
173
+ się z nią przymiotnikami i **zamraża** dopełniaczowy ogon. Wymaga
174
+ `polish-inflection >= 0.5.2`.
175
+
176
+ ```django
177
+ {% load polish_inflection %}
178
+
179
+ {# rzeczownik + przymiotnik — odmieniają się razem #}
180
+ {% odmien_fraze nazwa_uczelni "dopelniacz" %}
181
+ {# "Uniwersytet Lubelski" -> "Uniwersytetu Lubelskiego" #}
182
+ {# "Akademia Medyczna" (narzednik) -> "Akademią Medyczną" #}
183
+
184
+ {# rzeczownik + dopełniacz zależny — odmienia się tylko głowa #}
185
+ {% odmien_fraze nazwa_instytutu "dopelniacz" %}
186
+ {# "Instytut Technologii Stosowanej" -> "Instytutu Technologii Stosowanej" #}
187
+
188
+ {# filtr — gdy wystarcza sam przypadek #}
189
+ Sprawozdanie {{ nazwa_uczelni|odmien_fraze:"dopelniacz" }}
190
+
191
+ {# przypisanie do zmiennej #}
192
+ {% odmien_fraze nazwa_uczelni "miejscownik" as forma %}Konferencja na {{ forma }}
193
+ ```
194
+
195
+ Trafność heurystyki to ok. 85–95% realnych nazw; frazy, których nie łapie (np.
196
+ „Instytut Polski" — przymiotnik czy dopełniacz?), nadpisujesz ręcznie warstwą
197
+ override (patrz [Ustawienia](#ustawienia)). Liczba mnoga fraz jest obsługiwana
198
+ (`liczba="mnoga"`) — przymiotnik uzgadnia się z głową, a zależny ogon
199
+ dopełniaczowy pozostaje zamrożony (wymaga `polish-inflection >= 0.6.0`).
200
+
201
+ Dostępny jest też niższopoziomowy tag `{% odmien_przymiotnik lemat "przypadek"
202
+ "rodzaj" %}` (rodzaj: `"meski"` / `"zenski"` / `"nijaki"`), użyteczny gdy
203
+ składasz formę samodzielnie:
204
+
205
+ ```django
206
+ {% odmien_przymiotnik "lubelski" "dopelniacz" "meski" %} {# lubelskiego #}
207
+ {% odmien_przymiotnik "stosowany" "dopelniacz" "zenski" %} {# stosowanej #}
208
+ ```
209
+
210
+ `odmien_przymiotnik` ma wymagany argument `rodzaj`, więc — jak
211
+ `odmiana_liczebnikowa` — jest tylko tagiem (filtr Django przyjmuje jeden
212
+ argument).
213
+
214
+ ## Ustawienia
215
+
216
+ ```python
217
+ # settings.py
218
+ POLISH_INFLECTION_STRICT = False # domyślnie
219
+ ```
220
+
221
+ - `False` (domyślnie): nieznane słowo w słowniku SGJP nigdy nie wywala
222
+ renderowania strony — tag/filtr zwraca oryginalne słowo bez zmian.
223
+ - `True`: nieznane słowo podnosi `polish_inflection.BrakOdmiany`. Przydatne
224
+ w testach/CI.
225
+
226
+ ### Nadpisania fraz (`POLISH_INFLECTION_PHRASE_OVERRIDES`)
227
+
228
+ Zawór bezpieczeństwa dla fraz, których heurystyka `{% odmien_fraze %}` nie
229
+ rozstrzyga poprawnie. Mapa `{(fraza, "przypadek"): "gotowa forma"}` jest
230
+ konsultowana **przed** silnikiem — jeśli para pasuje, zwracana jest ręczna
231
+ forma, w przeciwnym razie działa silnik.
232
+
233
+ ```python
234
+ # settings.py
235
+ POLISH_INFLECTION_PHRASE_OVERRIDES = {
236
+ # silnik heurystycznie daje „Instytutu Polski" (czyta jako dopełniacz);
237
+ # wymuszamy czytanie przymiotnikowe:
238
+ ("Instytut Polski", "dopelniacz"): "Instytutu Polskiego",
239
+ ("Instytut Polski", "miejscownik"): "Instytucie Polskim",
240
+ }
241
+ ```
242
+
243
+ - Klucz przypadka to ten sam przyjazny string, którego używasz w tagu
244
+ (`"dopelniacz"`, `"miejscownik"`, …).
245
+ - Dopasowanie frazy ignoruje nadmiarowe białe znaki (trim + collapse spacji);
246
+ wielkość liter jest znacząca.
247
+ - Nadpisanie dotyczy liczby pojedynczej (klucz nie zawiera liczby); przy
248
+ `liczba="mnoga"` używany jest silnik.
249
+
250
+ ## Przykładowy projekt
251
+
252
+ W katalogu [`example_project/`](example_project/) jest gotowy do uruchomienia
253
+ projekt Django („Odmieniarka"): wpisujesz słowo lub nazwę własną, a strona
254
+ generuje pełną tabelę odmiany przez przypadki (l.poj. i l.mn.), łącznie z
255
+ działającą warstwą override. Uruchomienie (z korzenia repo, `uv` sam ogarnia
256
+ zależności): `uv run python example_project/manage.py runserver`.
257
+
258
+ ## Zakres
259
+
260
+ Ten pakiet odmienia pojedyncze rzeczowniki pospolite obecne w słowniku SGJP
261
+ (np. "wydział", "uczelnia", "instytut") przez wszystkie przypadki i obie liczby.
262
+
263
+ Odmiana wielowyrazowych nazw własnych instytucji (np. "Uniwersytet Lubelski")
264
+ jest dostępna heurystycznie przez `{% odmien_fraze %}` (patrz wyżej) — wymaga
265
+ `polish-inflection >= 0.5.2`.
266
+
267
+ Dobór formy rzeczownika wg liczebnika (1 wydział / 2 wydziały / 5 wydziałów)
268
+ jest dostępny przez `{% odmiana_liczebnikowa %}` (patrz wyżej) — wymaga
269
+ `polish-inflection >= 0.3.0`.
270
+
271
+ ## Licencja
272
+
273
+ BSD 2-Clause — patrz [LICENSE](LICENSE). Copyright © 2026 Michał Pasternak.
@@ -0,0 +1,245 @@
1
+ # django-polish-inflection
2
+
3
+ [![CI](https://github.com/iplweb/django-polish-inflection/actions/workflows/ci.yml/badge.svg)](https://github.com/iplweb/django-polish-inflection/actions/workflows/ci.yml)
4
+ [![License: BSD-2-Clause](https://img.shields.io/badge/License-BSD--2--Clause-blue.svg)](LICENSE)
5
+
6
+ Cienka warstwa Django (template tagi i filtry) nad
7
+ [`polish-inflection`](https://github.com/iplweb/polish-inflection) —
8
+ odmiana polszczyzny wprost w szablonach Django, oparta o słownik SGJP:
9
+
10
+ - **rzeczowniki** przez wszystkie przypadki i obie liczby (`odmien`,
11
+ aliasy pytajne `kogo_czego`/`komu_czemu`/…),
12
+ - **frazy wielowyrazowe** (nazwy własne instytucji, np. „Uniwersytet
13
+ Lubelski") — `odmien_fraze`,
14
+ - **przymiotniki** wg rodzaju głowy — `odmien_przymiotnik`,
15
+ - **dobór formy wg liczebnika** (1 wydział / 2 wydziały / 5 wydziałów) —
16
+ `odmiana_liczebnikowa`.
17
+
18
+ <p align="center">
19
+ <img src="https://raw.githubusercontent.com/iplweb/django-polish-inflection/v0.1.0/sshot1.png" alt="Odmieniarka — przykładowy projekt: pełna tabela odmiany przez przypadki" width="640">
20
+ <br>
21
+ <sub><i>Przykładowy projekt <a href="example_project/">„Odmieniarka"</a> — pełna tabela odmiany przez przypadki wprost w przeglądarce.</i></sub>
22
+ </p>
23
+
24
+ <p align="center">
25
+ <b>Support graciously provided by</b><br><br>
26
+ <a href="https://www.iplweb.pl"><img src="https://www.iplweb.pl/images/ipl-logo-large.png" width="120" alt="IPLweb"></a>
27
+ </p>
28
+
29
+ ## Instalacja
30
+
31
+ ```bash
32
+ pip install django-polish-inflection
33
+ ```
34
+
35
+ Dodaj do `INSTALLED_APPS`:
36
+
37
+ ```python
38
+ INSTALLED_APPS = [
39
+ ...,
40
+ "django_polish_inflection",
41
+ ]
42
+ ```
43
+
44
+ ## Użycie
45
+
46
+ Wczytaj bibliotekę tagów raz na szablon przez `{% load polish_inflection %}` — od
47
+ tej chwili masz w szablonie cztery narzędzia: generyczny `odmien` (dowolny
48
+ przypadek), zestaw czytelnych aliasów pytajnych (`kogo_czego`, `komu_czemu`, …),
49
+ dobór formy wg liczebnika (`odmiana_liczebnikowa`) i odmianę wielowyrazowych nazw
50
+ własnych (`odmien_fraze`). Większość działa i jako **tag** `{% … %}`, i — gdy
51
+ wystarczy sam przypadek — jako **filtr** `|…`; oba warianty zwracają to samo.
52
+
53
+ ```django
54
+ {% load polish_inflection %}
55
+ ```
56
+
57
+ Dla przykładowych danych `nazwa_jednostki = "wydział"` i `liczba = 5`
58
+ (w komentarzach `{# → … #}` jest wynik renderowania):
59
+
60
+ **Dowolny przypadek — generyczny `odmien`** (w tym mianownik i wołacz, których
61
+ aliasów pytajnych brak):
62
+
63
+ ```django
64
+ {{ nazwa_jednostki|odmien:"dopelniacz" }}
65
+ {# → wydziału #}
66
+
67
+ {% odmien nazwa_jednostki "dopelniacz" %}
68
+ {# → wydziału #}
69
+
70
+ {% odmien nazwa_jednostki "dopelniacz" liczba="mnoga" %}
71
+ {# → wydziałów #}
72
+
73
+ {% odmien nazwa_jednostki "dopelniacz" as forma %}{{ forma }}
74
+ {# → wydziału #}
75
+ ```
76
+
77
+ **Aliasy pytajne** — czytają się jak zdanie, wystawiane automatycznie z
78
+ `polish_inflection.pytania`:
79
+
80
+ ```django
81
+ Oto lista pracowników {% kogo_czego nazwa_jednostki %}
82
+ {# → Oto lista pracowników wydziału #}
83
+
84
+ Kliknij przycisk z {% z_kim_z_czym nazwa_jednostki %}
85
+ {# → Kliknij przycisk z wydziałem #}
86
+
87
+ {% komu_czemu nazwa_jednostki liczba="mnoga" %}
88
+ {# → wydziałom #}
89
+
90
+ {% podstawowa_forma "wydziałów" %}
91
+ {# → wydział #}
92
+ ```
93
+
94
+ **Dobór formy wg liczebnika** — polska zgoda liczebnikowa (1 wydział / 2 wydziały
95
+ / 5 wydziałów); numer doklejasz sam:
96
+
97
+ ```django
98
+ {{ liczba }} {% odmiana_liczebnikowa nazwa_jednostki liczba %}
99
+ {# → 5 wydziałów #}
100
+
101
+ {% odmiana_liczebnikowa nazwa_jednostki liczba "narzednik" %}
102
+ {# → wydziałami #}
103
+ ```
104
+
105
+ **Frazy wielowyrazowe i przymiotniki** — nazwy własne instytucji oraz sam
106
+ przymiotnik wg rodzaju:
107
+
108
+ ```django
109
+ {% odmien_fraze "Uniwersytet Lubelski" "dopelniacz" %}
110
+ {# → Uniwersytetu Lubelskiego #}
111
+
112
+ {{ "Akademia Medyczna"|odmien_fraze:"narzednik" }}
113
+ {# → Akademią Medyczną #}
114
+
115
+ {% odmien_przymiotnik "lubelski" "dopelniacz" "meski" %}
116
+ {# → lubelskiego #}
117
+ ```
118
+
119
+ Dostępne aliasy pytajne (dokładnie te, które eksportuje zainstalowana wersja
120
+ `polish_inflection.pytania.__all__` — nowe funkcje upstreamu o zgodnej
121
+ sygnaturze `(wyraz, *, liczba=None, default=...)` pojawiają się tu
122
+ automatycznie): `kogo_czego`, `komu_czemu`, `kogo_co`, `z_kim_z_czym`,
123
+ `o_kim_o_czym`, `podstawowa_forma`, oraz skróty `komu`, `czemu`, `z_kim`,
124
+ `z_czym`, `o_kim`, `o_czym`.
125
+
126
+ Mianownik i wołacz nie mają aliasu pytajnego (upstream też ich nie ma) —
127
+ używaj do nich generycznego `{% odmien wyraz "mianownik" %}` / `"wolacz"`.
128
+
129
+ ### Odmiana liczebnikowa
130
+
131
+ `{% odmiana_liczebnikowa wyraz liczba %}` zwraca **rzeczownik** w formie
132
+ narzuconej przez liczebnik (polska zgoda liczebnikowa: `1 wydział`,
133
+ `2 wydziały`, `5 wydziałów`). Liczby słownie nie generuje — numer doklejasz
134
+ sam. Rodzaj (w tym męskoosobowy m1, np. `2 studentów` a nie `2 studenci`) jest
135
+ wykrywany automatycznie ze słownika. Opcjonalny trzeci argument to przypadek
136
+ frazy (domyślnie mianownik), np. `{% odmiana_liczebnikowa wyraz liczba "narzednik" %}`
137
+ przy `liczba=5` zwraca `wydziałami` (liczebnik „pięcioma" doklejasz sam).
138
+ Kolejność argumentów jest jak w pozostałych tagach: `wyraz` pierwszy.
139
+
140
+ ### Odmiana fraz wielowyrazowych (nazw własnych instytucji)
141
+
142
+ `{% odmien_fraze fraza "przypadek" %}` odmienia **wielowyrazowe nazwy własne**
143
+ instytucji — uczelni, wydziałów, instytutów — a nie tylko pojedyncze
144
+ rzeczowniki. Silnik rozpoznaje głowę frazy, odmienia ją wraz z uzgadniającymi
145
+ się z nią przymiotnikami i **zamraża** dopełniaczowy ogon. Wymaga
146
+ `polish-inflection >= 0.5.2`.
147
+
148
+ ```django
149
+ {% load polish_inflection %}
150
+
151
+ {# rzeczownik + przymiotnik — odmieniają się razem #}
152
+ {% odmien_fraze nazwa_uczelni "dopelniacz" %}
153
+ {# "Uniwersytet Lubelski" -> "Uniwersytetu Lubelskiego" #}
154
+ {# "Akademia Medyczna" (narzednik) -> "Akademią Medyczną" #}
155
+
156
+ {# rzeczownik + dopełniacz zależny — odmienia się tylko głowa #}
157
+ {% odmien_fraze nazwa_instytutu "dopelniacz" %}
158
+ {# "Instytut Technologii Stosowanej" -> "Instytutu Technologii Stosowanej" #}
159
+
160
+ {# filtr — gdy wystarcza sam przypadek #}
161
+ Sprawozdanie {{ nazwa_uczelni|odmien_fraze:"dopelniacz" }}
162
+
163
+ {# przypisanie do zmiennej #}
164
+ {% odmien_fraze nazwa_uczelni "miejscownik" as forma %}Konferencja na {{ forma }}
165
+ ```
166
+
167
+ Trafność heurystyki to ok. 85–95% realnych nazw; frazy, których nie łapie (np.
168
+ „Instytut Polski" — przymiotnik czy dopełniacz?), nadpisujesz ręcznie warstwą
169
+ override (patrz [Ustawienia](#ustawienia)). Liczba mnoga fraz jest obsługiwana
170
+ (`liczba="mnoga"`) — przymiotnik uzgadnia się z głową, a zależny ogon
171
+ dopełniaczowy pozostaje zamrożony (wymaga `polish-inflection >= 0.6.0`).
172
+
173
+ Dostępny jest też niższopoziomowy tag `{% odmien_przymiotnik lemat "przypadek"
174
+ "rodzaj" %}` (rodzaj: `"meski"` / `"zenski"` / `"nijaki"`), użyteczny gdy
175
+ składasz formę samodzielnie:
176
+
177
+ ```django
178
+ {% odmien_przymiotnik "lubelski" "dopelniacz" "meski" %} {# lubelskiego #}
179
+ {% odmien_przymiotnik "stosowany" "dopelniacz" "zenski" %} {# stosowanej #}
180
+ ```
181
+
182
+ `odmien_przymiotnik` ma wymagany argument `rodzaj`, więc — jak
183
+ `odmiana_liczebnikowa` — jest tylko tagiem (filtr Django przyjmuje jeden
184
+ argument).
185
+
186
+ ## Ustawienia
187
+
188
+ ```python
189
+ # settings.py
190
+ POLISH_INFLECTION_STRICT = False # domyślnie
191
+ ```
192
+
193
+ - `False` (domyślnie): nieznane słowo w słowniku SGJP nigdy nie wywala
194
+ renderowania strony — tag/filtr zwraca oryginalne słowo bez zmian.
195
+ - `True`: nieznane słowo podnosi `polish_inflection.BrakOdmiany`. Przydatne
196
+ w testach/CI.
197
+
198
+ ### Nadpisania fraz (`POLISH_INFLECTION_PHRASE_OVERRIDES`)
199
+
200
+ Zawór bezpieczeństwa dla fraz, których heurystyka `{% odmien_fraze %}` nie
201
+ rozstrzyga poprawnie. Mapa `{(fraza, "przypadek"): "gotowa forma"}` jest
202
+ konsultowana **przed** silnikiem — jeśli para pasuje, zwracana jest ręczna
203
+ forma, w przeciwnym razie działa silnik.
204
+
205
+ ```python
206
+ # settings.py
207
+ POLISH_INFLECTION_PHRASE_OVERRIDES = {
208
+ # silnik heurystycznie daje „Instytutu Polski" (czyta jako dopełniacz);
209
+ # wymuszamy czytanie przymiotnikowe:
210
+ ("Instytut Polski", "dopelniacz"): "Instytutu Polskiego",
211
+ ("Instytut Polski", "miejscownik"): "Instytucie Polskim",
212
+ }
213
+ ```
214
+
215
+ - Klucz przypadka to ten sam przyjazny string, którego używasz w tagu
216
+ (`"dopelniacz"`, `"miejscownik"`, …).
217
+ - Dopasowanie frazy ignoruje nadmiarowe białe znaki (trim + collapse spacji);
218
+ wielkość liter jest znacząca.
219
+ - Nadpisanie dotyczy liczby pojedynczej (klucz nie zawiera liczby); przy
220
+ `liczba="mnoga"` używany jest silnik.
221
+
222
+ ## Przykładowy projekt
223
+
224
+ W katalogu [`example_project/`](example_project/) jest gotowy do uruchomienia
225
+ projekt Django („Odmieniarka"): wpisujesz słowo lub nazwę własną, a strona
226
+ generuje pełną tabelę odmiany przez przypadki (l.poj. i l.mn.), łącznie z
227
+ działającą warstwą override. Uruchomienie (z korzenia repo, `uv` sam ogarnia
228
+ zależności): `uv run python example_project/manage.py runserver`.
229
+
230
+ ## Zakres
231
+
232
+ Ten pakiet odmienia pojedyncze rzeczowniki pospolite obecne w słowniku SGJP
233
+ (np. "wydział", "uczelnia", "instytut") przez wszystkie przypadki i obie liczby.
234
+
235
+ Odmiana wielowyrazowych nazw własnych instytucji (np. "Uniwersytet Lubelski")
236
+ jest dostępna heurystycznie przez `{% odmien_fraze %}` (patrz wyżej) — wymaga
237
+ `polish-inflection >= 0.5.2`.
238
+
239
+ Dobór formy rzeczownika wg liczebnika (1 wydział / 2 wydziały / 5 wydziałów)
240
+ jest dostępny przez `{% odmiana_liczebnikowa %}` (patrz wyżej) — wymaga
241
+ `polish-inflection >= 0.3.0`.
242
+
243
+ ## Licencja
244
+
245
+ BSD 2-Clause — patrz [LICENSE](LICENSE). Copyright © 2026 Michał Pasternak.
@@ -0,0 +1,49 @@
1
+ # Odmieniarka — przykładowy projekt
2
+
3
+ Minimalny projekt Django pokazujący `django-polish-inflection` w akcji. Strona
4
+ startowa (`/`) daje wybór między dwoma narzędziami:
5
+
6
+ - **Odmiana wyrazów** (`/odmien/`) — wpisujesz słowo lub wielowyrazową nazwę
7
+ własną, a strona generuje pełną odmianę przez wszystkie przypadki (liczba
8
+ pojedyncza i mnoga) w szablonie przez tag `{% odmien_fraze %}`.
9
+ - **Podawanie form** (`/podaj/`) — kierunek odwrotny: wpisujesz dowolną formę,
10
+ a widok pokazuje jej analizy (forma podstawowa, przypadek, liczba, rodzaj)
11
+ zarówno jako **rzeczownik** (`podaj()`), jak i **przymiotnik**
12
+ (`podaj_przymiotnik()`) — obie słownikowe (SGJP), łącznie z synkretyzmem
13
+ i homografią.
14
+
15
+ ## Uruchomienie
16
+
17
+ Z tego katalogu — `uv` sam znajdzie projekt w katalogu nadrzędnym i ogarnie
18
+ zależności (Django i `django-polish-inflection`) w izolowanym środowisku:
19
+
20
+ ```bash
21
+ uv run python manage.py runserver
22
+ ```
23
+
24
+ Otwórz http://127.0.0.1:8000/ i wybierz jedno z dwóch narzędzi.
25
+
26
+ Projekt nie używa bazy danych — `runserver` startuje bez migracji.
27
+
28
+ ## Co pokazuje
29
+
30
+ - **Odmianę słów i fraz** przez jeden tag `{% odmien_fraze %}` (działa dla obu —
31
+ patrz `demo/templates/demo/odmien.html`).
32
+ - **Odmianę w pętli**: przypadek jest zmienną (`{% odmien_fraze wyraz p.key %}`),
33
+ więc jedna pętla generuje całą tabelę.
34
+ - **Warstwę override**: `odmieniarka/settings.py` zawiera
35
+ `POLISH_INFLECTION_PHRASE_OVERRIDES` dla „Instytut Polski" — wpisz tę frazę
36
+ na stronie odmiany, by zobaczyć ręczną formę zamiast heurystycznej.
37
+ - **Analizę form** jako rzeczownik i przymiotnik: strona „Podawanie form"
38
+ łączy `podaj()` (rzeczowniki) i `podaj_przymiotnik()` (przymiotniki) w widoku
39
+ (`demo/views.py`), bo obie zwracają listy obiektów, nie tekst — dlatego nie są
40
+ tagami szablonu jak odmiana. Od `polish-inflection` 0.7.0 analiza przymiotnika
41
+ jest słownikowa (bazy z SGJP), więc nie nadgeneruje form, które tylko wyglądają
42
+ jak przymiotnik.
43
+
44
+ ## Struktura
45
+
46
+ - `odmieniarka/urls.py` — trzy trasy: `/` (wybór), `/odmien/`, `/podaj/`.
47
+ - `demo/views.py` — widoki `index`, `odmien`, `analiza`.
48
+ - `demo/templates/demo/` — `base.html` (wspólny szkielet) + `index`, `odmien`,
49
+ `podaj`.
@@ -0,0 +1,6 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class DemoConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "demo"