Compare commits
11 commits
master
...
storefront
| Author | SHA1 | Date | |
|---|---|---|---|
| 9eb495529d | |||
| b7b63e3739 | |||
| 63a824d78d | |||
| 0b829d3b5f | |||
| 9ceeb32f5d | |||
| 4e4c9c4f4f | |||
| ba90b98455 | |||
| cc8c2245ee | |||
| 14b69c1654 | |||
| 7fd483376e | |||
| 1b0538694f |
14
.claude/settings.local.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(cat:*)",
|
||||
"Bash(xargs:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(npx create-next-app@latest . --typescript --tailwind --eslint --app --src-dir --import-alias \"@/*\" --use-npm --yes)",
|
||||
"Bash(npm install:*)",
|
||||
"Bash(npx shadcn@latest init:*)",
|
||||
"Bash(npx shadcn@latest add:*)",
|
||||
"Bash(npm run build:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
223
.gitignore
vendored
|
|
@ -1,150 +1,137 @@
|
|||
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ███████╗ ██████╗██╗ ██╗ ██████╗ ███╗ ██╗ ║
|
||||
# ║ ██╔════╝██╔════╝██║ ██║██╔═══██╗████╗ ██║ ║
|
||||
# ║ ███████╗██║ ███████║██║ ██║██╔██╗ ██║ ║
|
||||
# ║ ╚════██║██║ ██╔══██║██║ ██║██║╚██╗██║ ║
|
||||
# ║ ███████║╚██████╗██║ ██║╚██████╔╝██║ ╚████║ ║
|
||||
# ║ ╚══════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ║
|
||||
# ║ ║
|
||||
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Python │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# Bytecode & compiled
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# Python bytecode, caches, and compiled artifacts
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# Byte-compiled / optimized / DLL files
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
|
||||
# Caches
|
||||
# Cache directories
|
||||
__pycache__/
|
||||
.pytest_cache/
|
||||
.hypothesis/
|
||||
.mypy_cache/
|
||||
.pyre/
|
||||
.pytype/
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
cython_debug/
|
||||
|
||||
# Virtual environments
|
||||
# Python environments
|
||||
.Python
|
||||
.venv/
|
||||
venv/
|
||||
env/
|
||||
ENV/
|
||||
env.bak/
|
||||
ENV.bak/
|
||||
venv/
|
||||
venv.bak/
|
||||
ENV/
|
||||
.venv/
|
||||
__pypackages__/
|
||||
.python-version
|
||||
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Django │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# Local Django settings and database
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Django backups and metadata
|
||||
instance/
|
||||
backups/
|
||||
|
||||
# Static & media (collected)
|
||||
static/
|
||||
media/
|
||||
|
||||
# Allow checked-in app static files
|
||||
!engine/core/static/
|
||||
!engine/payments/static/
|
||||
!engine/vibes_auth/static/
|
||||
!engine/blog/static/
|
||||
|
||||
# Celery
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Testing & Coverage │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
htmlcov/
|
||||
.coverage
|
||||
.coverage.*
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# Logs and reports
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
logs/
|
||||
*.log
|
||||
debug.log
|
||||
errors.log
|
||||
test.json
|
||||
coverage.xml
|
||||
coverage.*
|
||||
*.cover
|
||||
*.py,cover
|
||||
nosetests.xml
|
||||
test.json
|
||||
tmp
|
||||
|
||||
# Coverage / test reports
|
||||
htmlcov/
|
||||
.coverage
|
||||
.coverage.*
|
||||
|
||||
# CI / tox / nox
|
||||
.tox/
|
||||
.nox/
|
||||
.scrapy
|
||||
.cover
|
||||
.pybuilder/
|
||||
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Logs │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
logs/
|
||||
*.log
|
||||
debug.log
|
||||
errors.log
|
||||
tmp/
|
||||
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Build & Distribution │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
build/
|
||||
dist/
|
||||
dist-ssr/
|
||||
sdist/
|
||||
wheels/
|
||||
*.egg
|
||||
*.egg-info/
|
||||
*.manifest
|
||||
*.spec
|
||||
.installed.cfg
|
||||
MANIFEST
|
||||
share/python-wheels/
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Node.js & Frontend │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
node_modules/
|
||||
# Storefronts
|
||||
.nuxt/
|
||||
.next/
|
||||
next-env.d.ts
|
||||
*.tsbuildinfo
|
||||
.webassets-cache/
|
||||
site/
|
||||
|
||||
# Debug logs
|
||||
# Celery
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# Packaging and distribution
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
build/
|
||||
dist/
|
||||
dist-ssr/
|
||||
*.egg
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
MANIFEST
|
||||
*.manifest
|
||||
*.spec
|
||||
sdist/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
desktop.ini
|
||||
*.iml
|
||||
|
||||
# Node build artifacts
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
site/
|
||||
|
||||
# Cypress
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# Static, media, and uploads
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
static/
|
||||
media/
|
||||
|
||||
# Allow checked-in static from apps
|
||||
!engine/core/static/
|
||||
!engine/payments/static/
|
||||
!engine/vibes_auth/static/
|
||||
!engine/blog/static/
|
||||
|
||||
# Webassets
|
||||
.webassets-cache/
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# Node dependencies
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
node_modules/
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# Cypress test artifacts
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
cypress/videos/
|
||||
cypress/screenshots/
|
||||
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ IDEs & Editors │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# VS Code
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# IDEs and editors
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
# VSCode
|
||||
.vscode/
|
||||
!.vscode/extensions.json
|
||||
|
||||
|
|
@ -152,49 +139,33 @@ cypress/screenshots/
|
|||
.idea/
|
||||
!.idea/icon.svg
|
||||
!.idea/externalDependencies.xml
|
||||
!.idea/schon.iml
|
||||
!.idea/evibes.iml
|
||||
!.idea/evibes.ico
|
||||
|
||||
# Visual Studio
|
||||
# Microsoft
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# Spyder & Rope
|
||||
# Spyder / Rope
|
||||
.spyderproject
|
||||
.spyproject
|
||||
.ropeproject
|
||||
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ OS & System │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
desktop.ini
|
||||
*.iml
|
||||
|
||||
# TypeScript
|
||||
*.tsbuildinfo
|
||||
|
||||
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
# │ Project-specific │
|
||||
# └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# Environment
|
||||
# Environment file
|
||||
.env
|
||||
|
||||
# Development
|
||||
# Development stuff
|
||||
test.ipynb
|
||||
.scrapy
|
||||
.cover
|
||||
.pybuilder/
|
||||
engine/core/vendors/docs/*
|
||||
|
||||
# Production
|
||||
# Production stuff
|
||||
.initialized
|
||||
/queries
|
||||
/nginx.conf
|
||||
/monitoring/web.yml
|
||||
|
||||
# AI assistants
|
||||
.claude/
|
||||
queries
|
||||
53
.gitlab-ci.yml
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
image: ghcr.io/astral-sh/uv:python3.12-bookworm
|
||||
|
||||
stages:
|
||||
- lint
|
||||
- typecheck
|
||||
- test
|
||||
|
||||
variables:
|
||||
UV_PYTHON: "3.12"
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
||||
PYTHONDONTWRITEBYTECODE: "1"
|
||||
|
||||
before_script:
|
||||
- uv sync --frozen --extra linting
|
||||
|
||||
lint:
|
||||
stage: lint
|
||||
script:
|
||||
- uv run ruff format --check .
|
||||
- uv run ruff check --force-exclude .
|
||||
rules:
|
||||
- changes:
|
||||
- "**/*.py"
|
||||
- "pyproject.toml"
|
||||
- ".pre-commit-config.yaml"
|
||||
- "pyrightconfig.json"
|
||||
when: on_success
|
||||
- when: never
|
||||
|
||||
typecheck:
|
||||
stage: typecheck
|
||||
script:
|
||||
- uv run pyright
|
||||
rules:
|
||||
- changes:
|
||||
- "**/*.py"
|
||||
- "pyproject.toml"
|
||||
- "pyrightconfig.json"
|
||||
when: on_success
|
||||
- when: never
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- uv run pytest -q
|
||||
rules:
|
||||
- changes:
|
||||
- "**/*.py"
|
||||
- "pyproject.toml"
|
||||
- "pytest.ini"
|
||||
- "pyproject.toml"
|
||||
when: on_success
|
||||
- when: never
|
||||
BIN
.idea/evibes.ico
Normal file
|
After Width: | Height: | Size: 41 KiB |
1268
.idea/icon.svg
|
Before Width: | Height: | Size: 355 KiB After Width: | Height: | Size: 1.4 KiB |
18
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.6.9
|
||||
hooks:
|
||||
- id: ruff
|
||||
name: Ruff (lint & fix)
|
||||
args: ["--fix", "--exit-non-zero-on-fix"]
|
||||
files: "\\.(py|pyi)$"
|
||||
exclude: "^storefront/"
|
||||
- id: ruff-format
|
||||
name: Ruff (format)
|
||||
files: "\\.(py|pyi)$"
|
||||
exclude: "^storefront/"
|
||||
|
||||
ci:
|
||||
autofix_commit_msg: "chore(pre-commit): auto-fix issues"
|
||||
autofix_prs: true
|
||||
autoupdate_commit_msg: "chore(pre-commit): autoupdate hooks"
|
||||
35
CHANGELOG.md
|
|
@ -1,35 +0,0 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to Schon are documented in this file.
|
||||
|
||||
Version format follows [CalVer](https://calver.org/) as `YYYY.MAJOR`.
|
||||
|
||||
---
|
||||
|
||||
## [2026.1] - 2026-01-25
|
||||
|
||||
Initial CalVer release. Project renamed from eVibes to Schon.
|
||||
|
||||
### Highlights
|
||||
|
||||
- Complete rebrand from eVibes to Schon
|
||||
- Native Linux deployment with systemd service files
|
||||
- uv-based dependency management
|
||||
- Interactive installer supporting Docker and native deployments
|
||||
- Professional documentation and project structure
|
||||
|
||||
### Added
|
||||
|
||||
- systemd service files for production deployment (`schon-web`, `schon-worker`, `schon-beat`, `schon-stock-updater`)
|
||||
- Native Linux installation script with automated setup
|
||||
- CHANGELOG.md for tracking releases
|
||||
|
||||
### Changed
|
||||
|
||||
- Project name: eVibes to Schon
|
||||
- Version scheme: SemVer to CalVer (YYYY.MAJOR)
|
||||
- Installation: `make install` now prompts for Docker vs native deployment
|
||||
|
||||
### Removed
|
||||
|
||||
- Legacy eVibes branding and assets
|
||||
|
|
@ -26,7 +26,7 @@ uv.lock @fureunoir contact@fureunoir.com
|
|||
|
||||
blog/ @fureunoir contact@fureunoir.com
|
||||
core/ @fureunoir contact@fureunoir.com
|
||||
schon/ @fureunoir contact@fureunoir.com
|
||||
evibes/ @fureunoir contact@fureunoir.com
|
||||
payments/ @fureunoir contact@fureunoir.com
|
||||
scripts/ @fureunoir contact@fureunoir.com
|
||||
vibes_auth/ @fureunoir contact@fureunoir.com
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ LABEL authors="fureunoir"
|
|||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
LANG=C.UTF-8 \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
PATH="/root/.local/bin:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -22,9 +23,11 @@ RUN set -eux; \
|
|||
libpq-dev \
|
||||
gettext \
|
||||
libgettextpo-dev \
|
||||
graphviz-dev \
|
||||
libgts-dev \
|
||||
libpq5 \
|
||||
chrony \
|
||||
graphviz \
|
||||
binutils \
|
||||
libproj-dev \
|
||||
postgresql-client-17 \
|
||||
|
|
@ -32,28 +35,23 @@ RUN set -eux; \
|
|||
rm -rf /var/lib/apt/lists/*; \
|
||||
pip install --upgrade pip
|
||||
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||
|
||||
ENV VIRTUAL_ENV=/opt/schon-python
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/schon-python
|
||||
ENV PATH="/opt/schon-python/bin:/usr/local/bin:$PATH"
|
||||
RUN uv venv /opt/evibes-python
|
||||
ENV VIRTUAL_ENV=/opt/evibes-python
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
||||
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||
|
||||
COPY pyproject.toml pyproject.toml
|
||||
COPY uv.lock uv.lock
|
||||
|
||||
RUN uv venv /opt/schon-python && \
|
||||
uv sync --extra worker --extra openai --locked
|
||||
RUN set -eux; \
|
||||
uv sync --extra graph --extra worker --extra openai --locked
|
||||
|
||||
COPY ./scripts/Docker/app-entrypoint.sh /usr/local/bin/app-entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/app-entrypoint.sh
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN groupadd --system --gid 1000 schon && \
|
||||
useradd --system --uid 1000 --gid schon --shell /bin/bash --create-home schon && \
|
||||
mkdir -p /app/static /app/media && \
|
||||
chown -R schon:schon /app /opt/schon-python
|
||||
|
||||
USER schon
|
||||
|
||||
ENTRYPOINT ["/usr/bin/bash", "app-entrypoint.sh"]
|
||||
|
|
@ -5,7 +5,8 @@ LABEL authors="fureunoir"
|
|||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
LANG=C.UTF-8 \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
PATH="/root/.local/bin:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -22,9 +23,11 @@ RUN set -eux; \
|
|||
libpq-dev \
|
||||
gettext \
|
||||
libgettextpo-dev \
|
||||
graphviz-dev \
|
||||
libgts-dev \
|
||||
libpq5 \
|
||||
chrony \
|
||||
graphviz \
|
||||
binutils \
|
||||
libproj-dev \
|
||||
postgresql-client-17 \
|
||||
|
|
@ -32,16 +35,18 @@ RUN set -eux; \
|
|||
rm -rf /var/lib/apt/lists/*; \
|
||||
pip install --upgrade pip
|
||||
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
||||
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||
|
||||
ENV VIRTUAL_ENV=/opt/schon-python
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/schon-python
|
||||
ENV PATH="/opt/schon-python/bin:/usr/local/bin:$PATH"
|
||||
RUN uv venv /opt/evibes-python
|
||||
ENV VIRTUAL_ENV=/opt/evibes-python
|
||||
|
||||
COPY pyproject.toml pyproject.toml
|
||||
COPY uv.lock uv.lock
|
||||
|
||||
RUN uv venv /opt/schon-python && \
|
||||
RUN set -eux; \
|
||||
uv sync --extra worker --extra openai --locked
|
||||
|
||||
COPY ./scripts/Docker/beat-entrypoint.sh /usr/local/bin/beat-entrypoint.sh
|
||||
|
|
@ -49,11 +54,4 @@ RUN chmod +x /usr/local/bin/beat-entrypoint.sh
|
|||
|
||||
COPY . .
|
||||
|
||||
RUN groupadd --system --gid 1000 schon && \
|
||||
useradd --system --uid 1000 --gid schon --shell /bin/bash --create-home schon && \
|
||||
mkdir -p /app/media && \
|
||||
chown -R schon:schon /app /opt/schon-python
|
||||
|
||||
USER schon
|
||||
|
||||
ENTRYPOINT ["/usr/bin/bash", "beat-entrypoint.sh"]
|
||||
|
|
@ -5,7 +5,8 @@ LABEL authors="fureunoir"
|
|||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
LANG=C.UTF-8 \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
PATH="/root/.local/bin:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -22,9 +23,11 @@ RUN set -eux; \
|
|||
libpq-dev \
|
||||
gettext \
|
||||
libgettextpo-dev \
|
||||
graphviz-dev \
|
||||
libgts-dev \
|
||||
libpq5 \
|
||||
chrony \
|
||||
graphviz \
|
||||
binutils \
|
||||
libproj-dev \
|
||||
postgresql-client-17 \
|
||||
|
|
@ -32,16 +35,18 @@ RUN set -eux; \
|
|||
rm -rf /var/lib/apt/lists/*; \
|
||||
pip install --upgrade pip
|
||||
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
||||
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||
|
||||
ENV VIRTUAL_ENV=/opt/schon-python
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/schon-python
|
||||
ENV PATH="/opt/schon-python/bin:/usr/local/bin:$PATH"
|
||||
RUN uv venv /opt/evibes-python
|
||||
ENV VIRTUAL_ENV=/opt/evibes-python
|
||||
|
||||
COPY pyproject.toml pyproject.toml
|
||||
COPY uv.lock uv.lock
|
||||
|
||||
RUN uv venv /opt/schon-python && \
|
||||
RUN set -eux; \
|
||||
uv sync --extra worker --extra openai --locked
|
||||
|
||||
COPY ./scripts/Docker/stock-updater-entrypoint.sh /usr/local/bin/stock-updater-entrypoint.sh
|
||||
|
|
@ -49,11 +54,4 @@ RUN chmod +x /usr/local/bin/stock-updater-entrypoint.sh
|
|||
|
||||
COPY . .
|
||||
|
||||
RUN groupadd --system --gid 1000 schon && \
|
||||
useradd --system --uid 1000 --gid schon --shell /bin/bash --create-home schon && \
|
||||
mkdir -p /app/media && \
|
||||
chown -R schon:schon /app /opt/schon-python
|
||||
|
||||
USER schon
|
||||
|
||||
ENTRYPOINT ["/usr/bin/bash", "stock-updater-entrypoint.sh"]
|
||||
72
Dockerfiles/storefront.Dockerfile
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM node:22-bookworm-slim AS base
|
||||
|
||||
# Install dependencies only when needed
|
||||
FROM base AS deps
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY ./storefront/package.json ./storefront/package-lock.json ./
|
||||
RUN npm ci --include=optional
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Build arguments for environment variables needed at build time
|
||||
ARG NEXT_PUBLIC_API_URL
|
||||
ARG NEXT_PUBLIC_SITE_URL
|
||||
ARG NEXT_PUBLIC_PROJECT_NAME
|
||||
ARG NEXT_PUBLIC_BASE_DOMAIN
|
||||
ARG EVIBES_BASE_DOMAIN
|
||||
ARG EVIBES_PROJECT_NAME
|
||||
|
||||
# Set build-time environment variables
|
||||
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
|
||||
ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL
|
||||
ENV NEXT_PUBLIC_PROJECT_NAME=${NEXT_PUBLIC_PROJECT_NAME:-$EVIBES_PROJECT_NAME}
|
||||
ENV NEXT_PUBLIC_BASE_DOMAIN=${NEXT_PUBLIC_BASE_DOMAIN:-$EVIBES_BASE_DOMAIN}
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY ./storefront ./
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# Production image, copy all the files and run next
|
||||
FROM base AS runtime
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV HOST=0.0.0.0
|
||||
ENV PORT=3000
|
||||
|
||||
# Install curl for health checks
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup --system --gid 1001 nodejs \
|
||||
&& adduser --system --uid 1001 --ingroup nodejs nextjs
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# Set the correct permission for prerender cache
|
||||
RUN mkdir .next
|
||||
RUN chown nextjs:nodejs .next
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||
CMD curl -f http://localhost:3000/ || exit 1
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
FROM node:22-bookworm-slim AS build
|
||||
WORKDIR /app
|
||||
|
||||
ARG schon_BASE_DOMAIN
|
||||
ARG schon_PROJECT_NAME
|
||||
ENV schon_BASE_DOMAIN=$schon_BASE_DOMAIN
|
||||
ENV schon_PROJECT_NAME=$schon_PROJECT_NAME
|
||||
ARG EVIBES_BASE_DOMAIN
|
||||
ARG EVIBES_PROJECT_NAME
|
||||
ENV EVIBES_BASE_DOMAIN=$EVIBES_BASE_DOMAIN
|
||||
ENV EVIBES_PROJECT_NAME=$EVIBES_PROJECT_NAME
|
||||
|
||||
COPY ./supervisor/package.json ./supervisor/package-lock.json ./
|
||||
RUN npm ci --include=optional
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ LABEL authors="fureunoir"
|
|||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
LANG=C.UTF-8 \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
PATH="/root/.local/bin:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -22,9 +23,11 @@ RUN set -eux; \
|
|||
libpq-dev \
|
||||
gettext \
|
||||
libgettextpo-dev \
|
||||
graphviz-dev \
|
||||
libgts-dev \
|
||||
libpq5 \
|
||||
chrony \
|
||||
graphviz \
|
||||
binutils \
|
||||
libproj-dev \
|
||||
postgresql-client-17 \
|
||||
|
|
@ -32,16 +35,18 @@ RUN set -eux; \
|
|||
rm -rf /var/lib/apt/lists/*; \
|
||||
pip install --upgrade pip
|
||||
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||
|
||||
ENV VIRTUAL_ENV=/opt/schon-python
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/schon-python
|
||||
ENV PATH="/opt/schon-python/bin:/usr/local/bin:$PATH"
|
||||
RUN uv venv /opt/evibes-python
|
||||
ENV VIRTUAL_ENV=/opt/evibes-python
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
||||
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||
|
||||
COPY pyproject.toml pyproject.toml
|
||||
COPY uv.lock uv.lock
|
||||
|
||||
RUN uv venv /opt/schon-python && \
|
||||
RUN set -eux; \
|
||||
uv sync --extra worker --extra openai --locked
|
||||
|
||||
COPY ./scripts/Docker/worker-entrypoint.sh /usr/local/bin/worker-entrypoint.sh
|
||||
|
|
@ -49,11 +54,4 @@ RUN chmod +x /usr/local/bin/worker-entrypoint.sh
|
|||
|
||||
COPY . .
|
||||
|
||||
RUN groupadd --system --gid 1000 schon && \
|
||||
useradd --system --uid 1000 --gid schon --shell /bin/bash --create-home schon && \
|
||||
mkdir -p /app/media && \
|
||||
chown -R schon:schon /app /opt/schon-python
|
||||
|
||||
USER schon
|
||||
|
||||
ENTRYPOINT ["/usr/bin/bash", "worker-entrypoint.sh"]
|
||||
6
LICENSE
|
|
@ -1,8 +1,8 @@
|
|||
Schon License – Version 2.0, April 29, 2025
|
||||
eVibes License – Version 2.0, April 29, 2025
|
||||
|
||||
Copyright (c) 2025 Egor “fureunoir” Gorbunov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Schon software and associated documentation (the “Software”), to use, copy, modify, merge, publish, distribute, and sublicense the Software, subject to the terms and conditions below. Any distribution of the Software (in source or binary form) must include a copy of this License and preserve the above copyright notice. By using the Software, you indicate your acceptance of these terms. If you do not agree to these terms, you have no rights to use the Software.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the eVibes software and associated documentation (the “Software”), to use, copy, modify, merge, publish, distribute, and sublicense the Software, subject to the terms and conditions below. Any distribution of the Software (in source or binary form) must include a copy of this License and preserve the above copyright notice. By using the Software, you indicate your acceptance of these terms. If you do not agree to these terms, you have no rights to use the Software.
|
||||
|
||||
1. Non-Commercial Use
|
||||
The Software is provided at no cost for personal, academic, or other non-commercial purposes. “Non-Commercial Use” means any use of the Software that does not generate income (directly or indirectly) and is not part of a for-profit or revenue-generating activity. For Non-Commercial Use, the Software is provided “AS IS” and without any warranty or liability. You may freely use and modify the Software for Non-Commercial purposes, and you may distribute it for non-commercial ends as long as this License is included and the same terms apply to all recipients.
|
||||
|
|
@ -55,4 +55,4 @@ Egor “fureunoir” Gorbunov
|
|||
Email: contact@fureunoir.com
|
||||
Telegram: https://t.me/fureunoir
|
||||
|
||||
By using the Schon framework, you acknowledge that you have read and understood this License and agree to be bound by its terms.
|
||||
By using the eVibes framework, you acknowledge that you have read and understood this License and agree to be bound by its terms.
|
||||
|
|
|
|||
113
Makefile
|
|
@ -1,113 +0,0 @@
|
|||
.PHONY: help install run restart test test-xml test-html uninstall backup \
|
||||
generate-env export-env make-messages compile-messages \
|
||||
format check typecheck precommit clear make-migrations migrate \
|
||||
delete-elasticsearch
|
||||
|
||||
# Detect OS and set script paths
|
||||
ifeq ($(OS),Windows_NT)
|
||||
SCRIPT_DIR := scripts/Windows
|
||||
SCRIPT_EXT := .ps1
|
||||
RUN_SCRIPT = pwsh -ExecutionPolicy Bypass -File ./$(SCRIPT_DIR)/$(1)$(SCRIPT_EXT)
|
||||
CLEAR_CMD := cls
|
||||
else
|
||||
SCRIPT_DIR := scripts/Unix
|
||||
SCRIPT_EXT := .sh
|
||||
RUN_SCRIPT = bash ./$(SCRIPT_DIR)/$(1)$(SCRIPT_EXT)
|
||||
CLEAR_CMD := clear
|
||||
endif
|
||||
|
||||
clear:
|
||||
ifeq ($(OS),Windows_NT)
|
||||
@$(CLEAR_CMD)
|
||||
else
|
||||
@if [ -t 1 ] && [ -n "$$TERM" ]; then $(CLEAR_CMD); fi 2>/dev/null || true
|
||||
endif
|
||||
|
||||
help: clear
|
||||
@echo "Schon Project Management"
|
||||
@echo ""
|
||||
@echo "Usage: make [target]"
|
||||
@echo ""
|
||||
@echo "Targets:"
|
||||
@echo " install Pull and build Docker images"
|
||||
@echo " run Start all services"
|
||||
@echo " restart Restart all services"
|
||||
@echo " test Run tests with coverage"
|
||||
@echo " test-xml Generate XML coverage report"
|
||||
@echo " test-html Generate HTML coverage report"
|
||||
@echo " uninstall Remove containers, volumes, and generated files"
|
||||
@echo " delete-elasticsearch Wipe Elasticsearch data (recreated on restart)"
|
||||
@echo " backup Create a backup"
|
||||
@echo " generate-env Generate .env file from template"
|
||||
@echo " export-env Export environment variables"
|
||||
@echo " make-messages Extract translation strings"
|
||||
@echo " compile-messages Compile translation files"
|
||||
@echo " make-migrations Generate migration files"
|
||||
@echo " migrate Apply migration files"
|
||||
@echo " format Format code with ruff"
|
||||
@echo " check Lint code with ruff"
|
||||
@echo " typecheck Typecheck code with ty"
|
||||
@echo " precommit Run format, check, and typecheck"
|
||||
@echo ""
|
||||
@echo "Detected OS: $(if $(filter Windows_NT,$(OS)),Windows,Unix)"
|
||||
@echo "Scripts directory: $(SCRIPT_DIR)"
|
||||
|
||||
install: clear
|
||||
@$(call RUN_SCRIPT,install)
|
||||
|
||||
run: clear
|
||||
@$(call RUN_SCRIPT,run)
|
||||
|
||||
restart: clear
|
||||
@$(call RUN_SCRIPT,restart)
|
||||
|
||||
test: clear
|
||||
@$(call RUN_SCRIPT,test)
|
||||
|
||||
test-xml: clear
|
||||
ifeq ($(OS),Windows_NT)
|
||||
@pwsh -ExecutionPolicy Bypass -File ./$(SCRIPT_DIR)/test$(SCRIPT_EXT) -r xml
|
||||
else
|
||||
@bash ./$(SCRIPT_DIR)/test$(SCRIPT_EXT) --report xml
|
||||
endif
|
||||
|
||||
test-html: clear
|
||||
ifeq ($(OS),Windows_NT)
|
||||
@pwsh -ExecutionPolicy Bypass -File ./$(SCRIPT_DIR)/test$(SCRIPT_EXT) -r html
|
||||
else
|
||||
@bash ./$(SCRIPT_DIR)/test$(SCRIPT_EXT) --report html
|
||||
endif
|
||||
|
||||
uninstall: clear
|
||||
@echo "This will remove all Docker containers, volumes, and generated files."
|
||||
ifeq ($(OS),Windows_NT)
|
||||
@pwsh -Command "$$confirm = Read-Host 'Continue? [y/N]'; if ($$confirm -eq 'y') { pwsh -ExecutionPolicy Bypass -File ./$(SCRIPT_DIR)/uninstall$(SCRIPT_EXT) } else { Write-Host 'Uninstall cancelled.' }"
|
||||
else
|
||||
@read -p "Continue? [y/N] " confirm && [ "$$confirm" = "y" ] && bash ./$(SCRIPT_DIR)/uninstall$(SCRIPT_EXT) || echo "Uninstall cancelled."
|
||||
endif
|
||||
|
||||
backup: clear
|
||||
@$(call RUN_SCRIPT,backup)
|
||||
|
||||
generate-env: clear
|
||||
@$(call RUN_SCRIPT,generate-environment-file)
|
||||
|
||||
export-env: clear
|
||||
@$(call RUN_SCRIPT,export-environment-file)
|
||||
|
||||
make-messages: clear
|
||||
@$(call RUN_SCRIPT,make-messages)
|
||||
|
||||
compile-messages: clear
|
||||
@$(call RUN_SCRIPT,compile-messages)
|
||||
|
||||
make-migrations: clear
|
||||
@$(call RUN_SCRIPT,make-migrations)
|
||||
|
||||
migrate: clear
|
||||
@$(call RUN_SCRIPT,migrate)
|
||||
|
||||
migration: clear make-migrations migrate
|
||||
|
||||
delete-elasticsearch: clear
|
||||
@$(call RUN_SCRIPT,delete-elasticsearch)
|
||||
321
README.md
|
|
@ -1,263 +1,132 @@
|
|||
# Schon
|
||||
# eVibes
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
<p align="center">
|
||||
<img src="engine/core/static/logo.png" alt="Schon Logo" width="200"/>
|
||||
</p>
|
||||
eVibes — a lightweight, production-ready e‑commerce backend. Storefront, product catalog, cart, and orders work out of the box. Minimal complexity, maximum flexibility — install, adjust to your needs, and start selling.
|
||||
|
||||
**Schon** is a production-ready e-commerce backend. Storefront, product catalog, cart, orders, and payments work out of the box. Minimal complexity, maximum flexibility.
|
||||
- Public issues: https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban
|
||||
|
||||
---
|
||||
## Table of Contents
|
||||
|
||||
## What is Schon?
|
||||
|
||||
Schon is a complete backend solution for online stores. Whether you're launching a small shop or scaling a marketplace, Schon provides the foundation:
|
||||
|
||||
- **Ready to use** - Clone, configure, deploy. No assembly required.
|
||||
- **API-first** - REST and GraphQL endpoints for any frontend framework.
|
||||
- **Multilingual** - 28 languages supported out of the box.
|
||||
- **Extensible** - Modular Django apps, easy to customize.
|
||||
|
||||
---
|
||||
- Features
|
||||
- Quick Start
|
||||
- Prerequisites
|
||||
- Installation
|
||||
- Configuration
|
||||
- Dockerfile
|
||||
- nginx
|
||||
- .env
|
||||
- Usage
|
||||
- Contributing
|
||||
- Contact
|
||||
- License
|
||||
|
||||
## Features
|
||||
|
||||
| Category | Details |
|
||||
|----------|---------|
|
||||
| **Framework** | Django 5.2, Django REST Framework 3.16, Graphene-Django |
|
||||
| **Database** | PostgreSQL with PostGIS, Redis caching, Elasticsearch search |
|
||||
| **Tasks** | Celery workers with Redis broker, scheduled tasks with Beat |
|
||||
| **Auth** | JWT authentication, rate limiting, custom user model (email-based) |
|
||||
| **APIs** | REST + GraphQL, Swagger/ReDoc documentation |
|
||||
| **i18n** | 28 languages, model translation support |
|
||||
| **Deployment** | Docker Compose or native Linux with systemd |
|
||||
|
||||
---
|
||||
- Modular backend, easy to extend and customize
|
||||
- Dockerized deployment with Docker Compose
|
||||
- Celery workers and beat for background tasks
|
||||
- REST and GraphQL APIs
|
||||
- Internationalization with modeltranslation
|
||||
- Redis-based caching and queues
|
||||
- JWT auth and rate limiting
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Git
|
||||
- Docker and Docker Compose **or** Linux with Python 3.12+, PostgreSQL, Redis, Elasticsearch
|
||||
- Docker and Docker Compose
|
||||
|
||||
### Docker (Recommended for Development)
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://git.wiseless.xyz/fureunoir/schon
|
||||
cd schon
|
||||
1. Clone the repository
|
||||
```bash
|
||||
git clone https://gitlab.com/wiseless.xyz/eVibes.git
|
||||
cd eVibes
|
||||
```
|
||||
|
||||
# Generate environment file
|
||||
make generate-env
|
||||
2. Choose a storefront (optional). The `main` branch ships without a storefront. If you want one, pick a branch:
|
||||
```bash
|
||||
git checkout storefront-<nuxt|next|sk|qwik>
|
||||
```
|
||||
|
||||
# Review and adjust .env as needed
|
||||
nano .env
|
||||
3. Generate your .env file and review its values
|
||||
- Windows
|
||||
```powershell
|
||||
scripts\Windows\generate-environment-file.ps1
|
||||
```
|
||||
- Unix
|
||||
```bash
|
||||
scripts/Unix/generate-environment-file.sh
|
||||
```
|
||||
|
||||
# Install (pull and build images)
|
||||
make install
|
||||
4. Install dependencies
|
||||
- Windows
|
||||
```powershell
|
||||
scripts\Windows\install.ps1
|
||||
```
|
||||
- Unix
|
||||
```bash
|
||||
scripts/Unix/install.sh
|
||||
```
|
||||
|
||||
# Start all services
|
||||
make run
|
||||
```
|
||||
5. Run the stack
|
||||
- Windows
|
||||
```powershell
|
||||
scripts\Windows\run.ps1
|
||||
```
|
||||
- Unix
|
||||
```bash
|
||||
scripts/Unix/run.sh
|
||||
```
|
||||
|
||||
### Native Linux (Production)
|
||||
|
||||
```bash
|
||||
# Clone to /opt/schon
|
||||
sudo git clone https://git.wiseless.xyz/fureunoir/schon /opt/schon
|
||||
cd /opt/schon
|
||||
|
||||
# Generate environment file
|
||||
make generate-env
|
||||
|
||||
# Review and adjust .env
|
||||
sudo nano .env
|
||||
|
||||
# Install (creates schon user, syncs dependencies, configures systemd)
|
||||
sudo make install
|
||||
# Select option 2: Native Linux
|
||||
|
||||
# Start services
|
||||
sudo systemctl start schon-web schon-worker schon-beat schon-stock-updater
|
||||
```
|
||||
|
||||
### Storefronts
|
||||
|
||||
The `main` branch ships backend-only. For a complete store with frontend:
|
||||
|
||||
```bash
|
||||
git checkout storefront-<nuxt|next|sk|qwik>
|
||||
```
|
||||
|
||||
---
|
||||
6. Production checklist
|
||||
- Include `nginx.conf` into your Nginx setup
|
||||
- Issue TLS certs with Certbot (https://certbot.eff.org/)
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
After running `make generate-env`, review `.env`:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `DEBUG` | Set to `0` for production |
|
||||
| `SECRET_KEY` | Django secret key (auto-generated) |
|
||||
| `JWT_SIGNING_KEY` | JWT token signing key (auto-generated) |
|
||||
| `POSTGRES_*` | Database credentials |
|
||||
| `REDIS_PASSWORD` | Redis authentication |
|
||||
| `SCHON_PROJECT_NAME` | Your store name |
|
||||
| `SCHON_BASE_DOMAIN` | Your domain (e.g., `example.com`) |
|
||||
|
||||
### Nginx
|
||||
|
||||
1. Copy the example config:
|
||||
```bash
|
||||
sudo cp nginx.example.conf /etc/nginx/sites-available/schon
|
||||
```
|
||||
|
||||
2. Update domain names and paths in the config
|
||||
|
||||
3. Enable the site:
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/schon /etc/nginx/sites-enabled/
|
||||
```
|
||||
|
||||
4. Obtain SSL certificates:
|
||||
```bash
|
||||
sudo certbot --nginx -d api.yourdomain.com -d yourdomain.com -d www.yourdomain.com
|
||||
```
|
||||
|
||||
5. Reload Nginx:
|
||||
```bash
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### DNS Records
|
||||
|
||||
Configure these DNS records pointing to your server:
|
||||
|
||||
- `yourdomain.com` (A record)
|
||||
- `www.yourdomain.com` (A or CNAME)
|
||||
- `api.yourdomain.com` (A or CNAME)
|
||||
- `prometheus.yourdomain.com` (A or CNAME, optional)
|
||||
|
||||
---
|
||||
|
||||
## API Documentation
|
||||
|
||||
Once running, access the API documentation:
|
||||
|
||||
| Endpoint | Description |
|
||||
|----------|-------------|
|
||||
| `http://api.localhost:8000/` | API root / Admin redirect |
|
||||
| `http://api.localhost:8000/docs/swagger/` | Swagger UI |
|
||||
| `http://api.localhost:8000/docs/redoc/` | ReDoc |
|
||||
| `http://api.localhost:8000/graphql/` | GraphQL Playground |
|
||||
| `http://api.localhost:8000/admin/` | Django Admin |
|
||||
| `http://api.localhost:8000/health/` | Health check endpoint |
|
||||
|
||||
Authentication header: `X-SCHON-AUTH: Bearer <token>`
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
### Commands
|
||||
|
||||
```bash
|
||||
make run # Start services
|
||||
make restart # Restart services
|
||||
make test # Run tests with coverage
|
||||
make format # Format code with Ruff
|
||||
make check # Lint code with Ruff
|
||||
make typecheck # Type check with ty
|
||||
make precommit # Run format, check, typecheck
|
||||
make make-messages # Extract translation strings
|
||||
make compile-messages # Compile translations
|
||||
make backup # Create database backup
|
||||
### Dockerfile
|
||||
If you rely on locale mirrors, adjust Debian sources before running installation scripts:
|
||||
```
|
||||
RUN sed -i 's|https://deb.debian.org/debian|https://ftp.<locale>.debian.org/debian|g' /etc/apt/sources.list.d/debian.sources
|
||||
```
|
||||
|
||||
### Running Migrations
|
||||
### nginx
|
||||
- Comment out SSL-related lines
|
||||
- Apply your domain-specific settings
|
||||
- Run `certbot --cert-only --nginx`
|
||||
- Uncomment SSL lines and reload Nginx
|
||||
|
||||
```bash
|
||||
# Docker
|
||||
docker compose exec app uv run python manage.py migrate
|
||||
### .env
|
||||
After generation, review and update secrets and credentials (API keys, DB password, Redis password, etc.).
|
||||
|
||||
# Native
|
||||
cd /opt/schon && .venv/bin/python manage.py migrate
|
||||
```
|
||||
## Usage
|
||||
|
||||
### Creating a Superuser
|
||||
- DNS records you’ll typically want:
|
||||
1. @.your-domain.com
|
||||
2. www.your-domain.com
|
||||
3. api.your-domain.com
|
||||
4. prometheus.your-domain.com
|
||||
|
||||
```bash
|
||||
# Docker
|
||||
docker compose exec app uv run python manage.py createsuperuser
|
||||
- Once running, access:
|
||||
- API root / Admin redirect: http://api.localhost:8000/
|
||||
- REST docs: http://api.localhost:8000/docs/swagger or http://api.localhost:8000/docs/redoc
|
||||
- GraphQL: http://api.localhost:8000/graphql/
|
||||
|
||||
# Native
|
||||
cd /opt/schon && .venv/bin/python manage.py createsuperuser
|
||||
```
|
||||
## Contributing
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
schon/
|
||||
├── schon/ # Django project settings
|
||||
│ ├── settings/ # Split settings (base, drf, celery, etc.)
|
||||
│ ├── middleware.py # Custom middleware
|
||||
│ └── urls.py # URL routing
|
||||
├── engine/ # Django apps
|
||||
│ ├── core/ # Products, orders, categories, vendors
|
||||
│ ├── payments/ # Transactions, payment gateways
|
||||
│ ├── vibes_auth/ # Custom User model, JWT auth
|
||||
│ └── blog/ # Blog posts
|
||||
├── Dockerfiles/ # Docker configurations
|
||||
├── systemd/ # Systemd service files
|
||||
├── scripts/ # Installation and utility scripts
|
||||
└── nginx.example.conf # Nginx configuration template
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Feedback & Issues
|
||||
|
||||
We value your feedback. Please open issues for:
|
||||
|
||||
- Bug reports
|
||||
- Feature suggestions
|
||||
- Questions about usage
|
||||
|
||||
**Issue Tracker:** [Plane](https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban)
|
||||
|
||||
Due to licensing restrictions, we cannot accept pull requests. See the LICENSE file for details.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Schon is released under a custom license. Key points:
|
||||
|
||||
- **Non-commercial use**: Free for personal, academic, and non-commercial purposes
|
||||
- **Commercial use**: Requires written authorization or automatic 8% royalty
|
||||
|
||||
See the [LICENSE](LICENSE) file for complete terms.
|
||||
|
||||
---
|
||||
- Track and report issues here: https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=list
|
||||
- Pull requests are welcome. Please keep changes minimal and focused.
|
||||
|
||||
## Contact
|
||||
|
||||
**Author:** Egor "fureunoir" Gorbunov
|
||||
- Author: Egor "fureunoir" Gorbunov
|
||||
- Email: contact@fureunoir.com
|
||||
- Telegram: https://t.me/fureunoir
|
||||
|
||||
- Email: [contact@fureunoir.com](mailto:contact@fureunoir.com)
|
||||
- Telegram: [@fureunoir](https://t.me/fureunoir)
|
||||
## License
|
||||
|
||||
---
|
||||
This project is licensed under the terms of the LICENSE file included in this repository.
|
||||
|
||||
<p align="center">
|
||||
<sub>Built with care by the Wiseless Team</sub>
|
||||
</p>
|
||||

|
||||
|
|
@ -1,7 +0,0 @@
|
|||
services:
|
||||
database:
|
||||
ports:
|
||||
- "5432:5432"
|
||||
elasticsearch:
|
||||
ports:
|
||||
- "9200:9200"
|
||||
|
|
@ -32,6 +32,8 @@ services:
|
|||
restart: always
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data/
|
||||
ports:
|
||||
- "5432:5432"
|
||||
env_file:
|
||||
- .env
|
||||
logging: *default-logging
|
||||
|
|
@ -88,22 +90,21 @@ services:
|
|||
|
||||
elasticsearch:
|
||||
container_name: elasticsearch
|
||||
image: git.wiseless.xyz/fureunoir/schon-elasticsearch:9.3.1
|
||||
image: wiseless/elasticsearch-maxed:8.16.6
|
||||
restart: always
|
||||
environment:
|
||||
- discovery.type=single-node
|
||||
- ES_JAVA_OPTS=-Xms512m -Xmx512m
|
||||
- xpack.security.enabled=true
|
||||
- xpack.security.http.ssl.enabled=false
|
||||
- xpack.security.transport.ssl.enabled=false
|
||||
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
|
||||
- xpack.security.enabled=false
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "9200:9200"
|
||||
volumes:
|
||||
- es-data:/usr/share/elasticsearch/data
|
||||
logging: *default-logging
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "-f", "-u", "elastic:${ELASTIC_PASSWORD}", "http://localhost:9200/_cluster/health" ]
|
||||
test: [ "CMD", "curl", "-f", "http://localhost:9200" ]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
|
@ -117,6 +118,8 @@ services:
|
|||
- .env
|
||||
command:
|
||||
- "--es.uri=http://elastic:${ELASTIC_PASSWORD}@elasticsearch:9200"
|
||||
ports:
|
||||
- "9114:9114"
|
||||
depends_on:
|
||||
elasticsearch:
|
||||
condition: service_healthy
|
||||
|
|
@ -144,7 +147,7 @@ services:
|
|||
condition: service_healthy
|
||||
logging: *default-logging
|
||||
healthcheck:
|
||||
test: [ "CMD-SHELL", "celery -A schon status | grep -q 'OK'" ]
|
||||
test: [ "CMD-SHELL", "celery -A evibes status | grep -q 'OK'" ]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
|
@ -172,7 +175,7 @@ services:
|
|||
condition: service_healthy
|
||||
logging: *default-logging
|
||||
healthcheck:
|
||||
test: [ "CMD-SHELL", "celery -A schon status | grep -q 'OK'" ]
|
||||
test: [ "CMD-SHELL", "celery -A evibes status | grep -q 'OK'" ]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
|
@ -207,12 +210,45 @@ services:
|
|||
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- ./monitoring/web.yml:/etc/prometheus/web.yml:ro
|
||||
- prometheus-data:/prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
command:
|
||||
- --config.file=/etc/prometheus/prometheus.yml
|
||||
- --web.config.file=/etc/prometheus/web.yml
|
||||
logging: *default-logging
|
||||
|
||||
storefront:
|
||||
container_name: storefront
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfiles/storefront.Dockerfile
|
||||
args:
|
||||
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://app:8000}
|
||||
- NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL:-http://localhost:3000}
|
||||
- NEXT_PUBLIC_PROJECT_NAME=${EVIBES_PROJECT_NAME}
|
||||
- NEXT_PUBLIC_BASE_DOMAIN=${EVIBES_BASE_DOMAIN}
|
||||
- EVIBES_BASE_DOMAIN=${EVIBES_BASE_DOMAIN}
|
||||
- EVIBES_PROJECT_NAME=${EVIBES_PROJECT_NAME}
|
||||
restart: always
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://app:8000}
|
||||
- NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL:-http://localhost:3000}
|
||||
- NEXT_PUBLIC_PROJECT_NAME=${EVIBES_PROJECT_NAME}
|
||||
- NEXT_PUBLIC_BASE_DOMAIN=${EVIBES_BASE_DOMAIN}
|
||||
ports:
|
||||
- "9090:9090"
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
app:
|
||||
condition: service_started
|
||||
logging: *default-logging
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
|
||||
|
||||
volumes:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
from django.contrib.admin import register
|
||||
from django.db.models import TextField
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_summernote.admin import SummernoteModelAdminMixin
|
||||
from unfold.admin import ModelAdmin
|
||||
from unfold_markdown import MarkdownWidget
|
||||
|
||||
|
|
@ -10,7 +9,9 @@ from engine.core.admin import ActivationActionsMixin, FieldsetsMixin
|
|||
|
||||
|
||||
@register(Post)
|
||||
class PostAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class PostAdmin(
|
||||
SummernoteModelAdminMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
): # type: ignore [misc, type-arg]
|
||||
list_display = ("title", "author", "slug", "created", "modified")
|
||||
list_filter = ("author", "tags", "created", "modified")
|
||||
search_fields = ("title", "content", "slug")
|
||||
|
|
@ -23,34 +24,23 @@ class PostAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
"slug",
|
||||
"modified",
|
||||
"created",
|
||||
"blogpic_preview",
|
||||
)
|
||||
|
||||
summernote_fields = ("content",)
|
||||
general_fields = [
|
||||
"title",
|
||||
"author",
|
||||
"content",
|
||||
"file",
|
||||
"blogpic",
|
||||
"blogpic_preview",
|
||||
]
|
||||
relation_fields = [
|
||||
"author",
|
||||
"tags",
|
||||
]
|
||||
|
||||
def blogpic_preview(self, obj: Post):
|
||||
if obj.blogpic:
|
||||
return format_html(
|
||||
'<img src="{}" style="max-width:400px;max-height:300px;object-fit:contain">',
|
||||
obj.blogpic.url,
|
||||
)
|
||||
return "—"
|
||||
|
||||
blogpic_preview.short_description = _("picture preview") # ty:ignore[unresolved-attribute]
|
||||
|
||||
|
||||
@register(PostTag)
|
||||
class PostTagAdmin(ModelAdmin):
|
||||
class PostTagAdmin(ModelAdmin): # type: ignore [type-arg]
|
||||
list_display = ("tag_name", "name")
|
||||
search_fields = ("tag_name", "name")
|
||||
ordering = ("tag_name",)
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@ class BlogConfig(AppConfig):
|
|||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def ready(self) -> None:
|
||||
import engine.blog.elasticsearch.documents # noqa: F401
|
||||
import engine.blog.elasticsearch.documents
|
||||
import engine.blog.signals # noqa: F401
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from engine.core.elasticsearch import (
|
|||
from engine.core.elasticsearch.documents import BaseDocument
|
||||
|
||||
|
||||
class PostDocument(ActiveOnlyMixin, BaseDocument):
|
||||
class PostDocument(ActiveOnlyMixin, BaseDocument): # type: ignore [misc]
|
||||
title = fields.TextField(
|
||||
attr="title",
|
||||
analyzer="standard",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from engine.blog.models import Post
|
|||
from engine.core.filters import CaseInsensitiveListFilter
|
||||
|
||||
|
||||
class PostFilter(FilterSet):
|
||||
class PostFilter(FilterSet): # type: ignore [misc]
|
||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||
slug = CharFilter(field_name="slug", lookup_expr="exact")
|
||||
author = UUIDFilter(field_name="author__uuid", lookup_expr="exact")
|
||||
|
|
|
|||
|
|
@ -1,26 +1,21 @@
|
|||
from django.http import HttpRequest
|
||||
from graphene import List, String, relay
|
||||
import graphene
|
||||
from graphene import relay
|
||||
from graphene_django import DjangoObjectType
|
||||
|
||||
from engine.blog.models import Post, PostTag
|
||||
from engine.core.utils.markdown import render_markdown
|
||||
|
||||
|
||||
class PostType(DjangoObjectType):
|
||||
tags = List(lambda: PostTagType)
|
||||
content = String()
|
||||
blogpic = String()
|
||||
tags = graphene.List(lambda: PostTagType)
|
||||
content = graphene.String()
|
||||
|
||||
class Meta:
|
||||
model = Post
|
||||
fields = ["tags", "content", "title", "slug", "blogpic"]
|
||||
fields = ["tags", "content", "title", "slug"]
|
||||
interfaces = (relay.Node,)
|
||||
|
||||
def resolve_content(self: Post, _info: HttpRequest) -> str:
|
||||
return render_markdown(self.content or "")
|
||||
|
||||
def resolve_blogpic(self: Post, info: HttpRequest) -> str:
|
||||
return info.build_absolute_uri(self.blogpic.url) if self.blogpic else ""
|
||||
def resolve_content(self: Post, _info):
|
||||
return self.content.html.replace("\n", "<br/>")
|
||||
|
||||
|
||||
class PostTagType(DjangoObjectType):
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "معاينة الصورة"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "المدونة"
|
||||
|
|
@ -29,38 +25,29 @@ msgstr "سرد جميع المشاركات (للقراءة فقط)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "استرداد منشور واحد (للقراءة فقط)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"يمثل نموذج منشور المدونة. تحدد فئة المشاركة بنية وسلوك مشاركة المدونة. "
|
||||
"وتتضمن سمات للمؤلف والعنوان والمحتوى ومرفق الملف الاختياري والسبيكة "
|
||||
"والعلامات المرتبطة بها. يفرض الصنف قيودًا مثل طلب إما محتوى أو مرفق ملف ولكن"
|
||||
" ليس كلاهما في نفس الوقت. كما أنها تدعم إنشاء سبيكة تلقائية بناءً على "
|
||||
"العنوان."
|
||||
"والعلامات المرتبطة بها. يفرض الصنف قيودًا مثل طلب إما محتوى أو مرفق ملف ولكن "
|
||||
"ليس كلاهما في نفس الوقت. كما أنها تدعم إنشاء سبيكة تلقائية بناءً على العنوان."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "عنوان المنشور"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "العنوان"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "المحتوى"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "نشر المحتوى"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "هي صفحة ثابتة"
|
||||
|
||||
|
|
@ -69,44 +56,45 @@ msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
|||
msgstr ""
|
||||
"هل هذا منشور لصفحة ذات عنوان URL ثابت (على سبيل المثال '/مساعدة/التسليم'؟)"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "المنشور"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "المنشورات"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
msgstr "يجب توفير ملف تخفيض أو محتوى تخفيض - متبادل الاستبعاد"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr "يجب توفير ملف ترميز أو محتوى ترميز مخفض - متنافيان"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "اسم العلامة"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "اسم سهل الاستخدام لعلامة المنشور"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "اسم عرض العلامة"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "علامة المشاركة"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "علامات المشاركة"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Náhled obrázku"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,87 +25,80 @@ msgstr "Seznam všech příspěvků (pouze pro čtení)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Získání jednoho příspěvku (pouze pro čtení)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Představuje model příspěvku na blogu. Třída Post definuje strukturu a "
|
||||
"chování příspěvku na blogu. Obsahuje atributy pro autora, název, obsah, "
|
||||
"volitelnou přílohu, slug a přidružené značky. Třída vynucuje omezení, jako "
|
||||
"je požadavek na obsah nebo přílohu souboru, ale ne obojí současně. Podporuje"
|
||||
" také automatické generování slugu na základě názvu."
|
||||
"je požadavek na obsah nebo přílohu souboru, ale ne obojí současně. Podporuje "
|
||||
"také automatické generování slugu na základě názvu."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Název příspěvku"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Název"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "obsah"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "obsah příspěvku"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "je statická stránka"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"je to příspěvek pro stránku se statickou adresou URL (např. "
|
||||
"`/help/delivery`)?"
|
||||
"je to příspěvek pro stránku se statickou adresou URL (např. `/help/"
|
||||
"delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Příspěvek"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Příspěvky"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Soubory Markdown nejsou podporovány - místo toho použijte obsah Markdown!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"musí být poskytnut soubor markdown nebo obsah markdown - vzájemně se "
|
||||
"vylučují."
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "interní identifikátor tagu pro tag příspěvku"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Název štítku"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Uživatelsky přívětivý název pro značku příspěvku"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Zobrazení názvu štítku"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Označení příspěvku"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Štítky příspěvků"
|
||||
|
||||
|
|
@ -122,8 +111,8 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"Zapouzdřuje operace pro správu a načítání entit Post v sadě zobrazení modelu"
|
||||
" pouze pro čtení. Tato třída je přizpůsobena pro práci s aktivními objekty "
|
||||
"Zapouzdřuje operace pro správu a načítání entit Post v sadě zobrazení modelu "
|
||||
"pouze pro čtení. Tato třída je přizpůsobena pro práci s aktivními objekty "
|
||||
"Post a umožňuje filtrování na základě definovaných filtrů. Integruje se s "
|
||||
"backendovým systémem filtrování Djanga a zajišťuje soulad operací s "
|
||||
"definovanými oprávněními. Sada zobrazení obsahuje také dodatečnou "
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Billedforhåndsvisning"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,39 +25,31 @@ msgstr "Vis alle indlæg (skrivebeskyttet)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Hent et enkelt indlæg (skrivebeskyttet)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Repræsenterer en blogindlægsmodel. Post-klassen definerer strukturen og "
|
||||
"adfærden i et blogindlæg. Den indeholder attributter for forfatter, titel, "
|
||||
"indhold, valgfri vedhæftet fil, slug og tilknyttede tags. Klassen håndhæver "
|
||||
"begrænsninger som f.eks. at kræve enten indhold eller en vedhæftet fil, men "
|
||||
"ikke begge dele på samme tid. Den understøtter også automatisk generering af"
|
||||
" slugs baseret på titlen."
|
||||
"ikke begge dele på samme tid. Den understøtter også automatisk generering af "
|
||||
"slugs baseret på titlen."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Indlæggets titel"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "indhold"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "indhold"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "er en statisk side"
|
||||
|
||||
|
|
@ -70,44 +58,45 @@ msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
|||
msgstr ""
|
||||
"Er dette et indlæg til en side med statisk URL (f.eks. `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Indlæg"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Indlæg"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "filoverførsler understøttes endnu ikke – brug i stedet indhold"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "Markdown-filer understøttes ikke - brug markdown-indhold i stedet!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"en markdown-fil eller markdown-indhold skal leveres - gensidigt udelukkende"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "intern tag-identifikator for indlægs-tagget"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Tag-navn"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Brugervenligt navn til posttagget"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Navn på tag-visning"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Tag til indlæg"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Tags til indlæg"
|
||||
|
||||
|
|
@ -124,6 +113,5 @@ msgstr ""
|
|||
"skrivebeskyttet modelvisningssæt. Denne klasse er skræddersyet til at "
|
||||
"håndtere Post-objekter, der er aktive, og tillader filtrering baseret på "
|
||||
"definerede filtre. Den integreres med Djangos backend-filtreringssystem og "
|
||||
"sikrer, at handlingerne er i overensstemmelse med de definerede tilladelser."
|
||||
" Visningssættet indeholder også en ekstra konfiguration af tilladelsen "
|
||||
"'hent'."
|
||||
"sikrer, at handlingerne er i overensstemmelse med de definerede tilladelser. "
|
||||
"Visningssættet indeholder også en ekstra konfiguration af tilladelsen 'hent'."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Bildvorschau"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Alle Beiträge auflisten (schreibgeschützt)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Einen einzelnen Beitrag abrufen (schreibgeschützt)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Stellt ein Blogpost-Modell dar. Die Klasse Post definiert die Struktur und "
|
||||
"das Verhalten eines Blogeintrags. Sie enthält Attribute für Autor, Titel, "
|
||||
|
|
@ -46,73 +42,66 @@ msgstr ""
|
|||
"unterstützt auch die automatische Slug-Generierung auf der Grundlage des "
|
||||
"Titels."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Titel des Beitrags"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "Inhalt"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "Beitragsinhalte"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "ist eine statische Seite"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"Ist dies ein Beitrag für eine Seite mit statischer URL (z. B. "
|
||||
"`/help/delivery`)?"
|
||||
"Ist dies ein Beitrag für eine Seite mit statischer URL (z. B. `/help/"
|
||||
"delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Beitrag"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Beiträge"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Markdown-Dateien werden nicht unterstützt - verwenden Sie stattdessen "
|
||||
"Markdown-Inhalte!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"eine Markdown-Datei oder ein Markdown-Inhalt muss bereitgestellt werden - "
|
||||
"beide schließen sich gegenseitig aus"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "interner Tag-Bezeichner für den Post-Tag"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Tag name"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Benutzerfreundlicher Name für das Post-Tag"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Tag-Anzeigename"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Tag eintragen"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Tags eintragen"
|
||||
|
||||
|
|
@ -130,5 +119,5 @@ msgstr ""
|
|||
"aktiver Post-Objekte zugeschnitten und ermöglicht die Filterung auf der "
|
||||
"Grundlage definierter Filter. Sie integriert sich in das Backend-"
|
||||
"Filtersystem von Django und stellt sicher, dass die Operationen mit den "
|
||||
"definierten Berechtigungen übereinstimmen. Das View Set beinhaltet auch eine"
|
||||
" zusätzliche 'retrieve' Berechtigungskonfiguration."
|
||||
"definierten Berechtigungen übereinstimmen. Das View Set beinhaltet auch eine "
|
||||
"zusätzliche 'retrieve' Berechtigungskonfiguration."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
# EVIBES GETTEXT TRANSLATIONS
|
||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||
# This file is distributed under the same license as the EVIBES package.
|
||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +17,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Picture preview"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,39 +29,31 @@ msgstr "List all posts (read-only)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Retrieve a single post (read-only)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Post's title"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Title"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "content"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "post content"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "is static page"
|
||||
|
||||
|
|
@ -69,44 +61,45 @@ msgstr "is static page"
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Posts"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "internal tag identifier for the post tag"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Tag name"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "User-friendly name for the post tag"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Tag display name"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Post tags"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Picture preview"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,39 +25,31 @@ msgstr "List all posts (read-only)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Retrieve a single post (read-only)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Post's title"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Title"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "content"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "post content"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "is static page"
|
||||
|
||||
|
|
@ -69,44 +57,45 @@ msgstr "is static page"
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Posts"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "internal tag identifier for the post tag"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Tag name"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "User-friendly name for the post tag"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Tag display name"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Post tags"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Vista previa de la imagen"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Listar todos los mensajes (sólo lectura)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Recuperar una única entrada (sólo lectura)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Representa un modelo de entrada de blog. La clase Post define la estructura "
|
||||
"y el comportamiento de una entrada de blog. Incluye atributos para autor, "
|
||||
|
|
@ -45,72 +41,65 @@ msgstr ""
|
|||
"adjunto, pero no ambos simultáneamente. También admite la generación "
|
||||
"automática de slug a partir del título."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Título del mensaje"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Título"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "contenido"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "publicar contenido"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "es una página estática"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"¿se trata de una entrada para una página con URL estática (por ejemplo, "
|
||||
"`/help/delivery`)?"
|
||||
"¿se trata de una entrada para una página con URL estática (por ejemplo, `/"
|
||||
"help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Publicar en"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Puestos"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"No se admiten archivos Markdown - ¡utiliza contenido Markdown en su lugar!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"se debe proporcionar un archivo markdown o contenido markdown - mutuamente "
|
||||
"excluyentes"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identificador interno de la etiqueta post"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Nombre de la etiqueta"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Nombre de la etiqueta"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Etiqueta postal"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Etiquetas"
|
||||
|
||||
|
|
@ -126,7 +115,7 @@ msgstr ""
|
|||
"Encapsula operaciones para gestionar y recuperar entidades Post en un "
|
||||
"conjunto de vistas de modelo de sólo lectura. Esta clase está adaptada para "
|
||||
"manejar objetos Post que están activos y permite el filtrado basado en "
|
||||
"filtros definidos. Se integra con el sistema de filtrado backend de Django y"
|
||||
" asegura que las operaciones se alinean con los permisos definidos. El "
|
||||
"filtros definidos. Se integra con el sistema de filtrado backend de Django y "
|
||||
"asegura que las operaciones se alinean con los permisos definidos. El "
|
||||
"conjunto de vistas también incluye una configuración adicional de permisos "
|
||||
"de \"recuperación\"."
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
|
@ -16,10 +16,6 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr ""
|
||||
|
|
@ -32,7 +28,7 @@ msgstr ""
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
|
|
@ -42,23 +38,15 @@ msgid ""
|
|||
"title."
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -66,43 +54,44 @@ msgstr ""
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Aperçu de l'image"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Liste de tous les messages (en lecture seule)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Récupérer un seul message (en lecture seule)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Représente un modèle de billet de blog. La classe Post définit la structure "
|
||||
"et le comportement d'un billet de blog. Elle comprend des attributs pour "
|
||||
|
|
@ -46,73 +42,66 @@ msgstr ""
|
|||
"simultanément. Elle prend également en charge la génération automatique "
|
||||
"d'une balise en fonction du titre."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Titre du message"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Titre"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "contenu"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "contenu de publication"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "est une page statique"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"s'agit-il d'un message pour une page dont l'URL est statique (par exemple "
|
||||
"`/help/delivery`) ?"
|
||||
"s'agit-il d'un message pour une page dont l'URL est statique (par exemple `/"
|
||||
"help/delivery`) ?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Poste"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Postes"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Les fichiers Markdown ne sont pas pris en charge - utilisez plutôt du "
|
||||
"contenu Markdown !"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent"
|
||||
" mutuellement"
|
||||
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent "
|
||||
"mutuellement"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identifiant interne de la balise post"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Nom du jour"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nom convivial pour la balise post"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Nom d'affichage de l'étiquette"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Tag de poste"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Tags de la poste"
|
||||
|
||||
|
|
@ -125,8 +114,8 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"Encapsule les opérations de gestion et d'extraction des entités Post dans un"
|
||||
" ensemble de vues de modèle en lecture seule. Cette classe est conçue pour "
|
||||
"Encapsule les opérations de gestion et d'extraction des entités Post dans un "
|
||||
"ensemble de vues de modèle en lecture seule. Cette classe est conçue pour "
|
||||
"gérer les objets Post qui sont actifs et permet un filtrage basé sur des "
|
||||
"filtres définis. Elle s'intègre au système de filtrage du backend de Django "
|
||||
"et garantit que les opérations s'alignent sur les permissions définies. Le "
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "תצוגה מקדימה של תמונה"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "בלוג"
|
||||
|
|
@ -29,37 +25,29 @@ msgstr "הצג את כל ההודעות (לקריאה בלבד)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "איתור פוסט בודד (לקריאה בלבד)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"מייצג מודל של פוסט בבלוג. מחלקת Post מגדירה את המבנה וההתנהגות של פוסט "
|
||||
"בבלוג. היא כוללת תכונות עבור מחבר, כותרת, תוכן, קובץ מצורף אופציונלי, slug "
|
||||
"ותגיות נלוות. המחלקה אוכפת אילוצים כגון דרישה לתוכן או לקובץ מצורף, אך לא "
|
||||
"לשניהם בו-זמנית. היא תומכת גם ביצירה אוטומטית של slug על סמך הכותרת."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "כותרת הפוסט"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "כותרת"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "תוכן"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "תוכן הפוסט"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "הוא דף סטטי"
|
||||
|
||||
|
|
@ -67,43 +55,44 @@ msgstr "הוא דף סטטי"
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr "האם זו הודעה לדף עם כתובת URL סטטית (למשל `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "פוסט"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "פוסטים"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "העלאת קבצים אינה נתמכת עדיין - השתמש בתוכן במקום זאת"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "קובצי Markdown אינם נתמכים עדיין - השתמש בתוכן Markdown במקום!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr "יש לספק קובץ markdown או תוכן markdown - באופן בלעדי"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "מזהה תגיות פנימי עבור תגיות הפוסט"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "שם היום"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "שם ידידותי למשתמש עבור תגיות הפוסט"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "שם תצוגה של התג"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "תגית פוסט"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "תגיות פוסט"
|
||||
|
||||
|
|
@ -116,7 +105,7 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"מכיל פעולות לניהול ואחזור ישויות Post במערך תצוגה של מודל לקריאה בלבד. מחלקה"
|
||||
" זו מותאמת לטיפול באובייקטי Post פעילים ומאפשרת סינון על בסיס מסננים "
|
||||
"מוגדרים. היא משתלבת במערכת הסינון האחורית של Django ומבטיחה שהפעולות תואמות "
|
||||
"את ההרשאות המוגדרות. מערך התצוגה כולל גם תצורת הרשאה נוספת ל'אחזור'."
|
||||
"מכיל פעולות לניהול ואחזור ישויות Post במערך תצוגה של מודל לקריאה בלבד. מחלקה "
|
||||
"זו מותאמת לטיפול באובייקטי Post פעילים ומאפשרת סינון על בסיס מסננים מוגדרים. "
|
||||
"היא משתלבת במערכת הסינון האחורית של Django ומבטיחה שהפעולות תואמות את "
|
||||
"ההרשאות המוגדרות. מערך התצוגה כולל גם תצורת הרשאה נוספת ל'אחזור'."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
# EVIBES GETTEXT TRANSLATIONS
|
||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||
# This file is distributed under the same license as the EVIBES package.
|
||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -12,10 +16,6 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr ""
|
||||
|
|
@ -28,7 +28,7 @@ msgstr ""
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
|
|
@ -38,23 +38,15 @@ msgid ""
|
|||
"title."
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -62,43 +54,44 @@ msgstr ""
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
|
@ -16,10 +16,6 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr ""
|
||||
|
|
@ -32,7 +28,7 @@ msgstr ""
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
|
|
@ -42,23 +38,15 @@ msgid ""
|
|||
"title."
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -66,43 +54,44 @@ msgstr ""
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Pratinjau gambar"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,89 +25,82 @@ msgstr "Daftar semua postingan (hanya-baca)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Mengambil satu postingan (hanya-baca)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Mewakili model posting blog. Kelas Post mendefinisikan struktur dan perilaku"
|
||||
" postingan blog. Kelas ini mencakup atribut untuk penulis, judul, konten, "
|
||||
"Mewakili model posting blog. Kelas Post mendefinisikan struktur dan perilaku "
|
||||
"postingan blog. Kelas ini mencakup atribut untuk penulis, judul, konten, "
|
||||
"lampiran file opsional, slug, dan tag yang terkait. Kelas ini memberlakukan "
|
||||
"batasan seperti membutuhkan konten atau lampiran file, tetapi tidak keduanya"
|
||||
" secara bersamaan. Kelas ini juga mendukung pembuatan slug otomatis "
|
||||
"batasan seperti membutuhkan konten atau lampiran file, tetapi tidak keduanya "
|
||||
"secara bersamaan. Kelas ini juga mendukung pembuatan slug otomatis "
|
||||
"berdasarkan judul."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Judul postingan"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Judul"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "konten"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "posting konten"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "adalah halaman statis"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"apakah ini adalah postingan untuk halaman dengan URL statis (misalnya "
|
||||
"`/help/pengiriman`)?"
|
||||
"apakah ini adalah postingan untuk halaman dengan URL statis (misalnya `/help/"
|
||||
"pengiriman`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Pos"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Posting"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"File penurunan harga tidak didukung - gunakan konten penurunan harga sebagai"
|
||||
" gantinya!"
|
||||
"File penurunan harga tidak didukung - gunakan konten penurunan harga sebagai "
|
||||
"gantinya!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"file penurunan harga atau konten penurunan harga harus disediakan - tidak "
|
||||
"boleh ada yang sama"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "pengidentifikasi tag internal untuk tag pos"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Nama tag"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nama yang mudah digunakan untuk tag postingan"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Nama tampilan tag"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Tag pos"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Tag pos"
|
||||
|
||||
|
|
@ -124,8 +113,8 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"Mengenkapsulasi operasi untuk mengelola dan mengambil entitas Post dalam set"
|
||||
" tampilan model hanya-baca. Kelas ini dirancang untuk menangani objek Post "
|
||||
"Mengenkapsulasi operasi untuk mengelola dan mengambil entitas Post dalam set "
|
||||
"tampilan model hanya-baca. Kelas ini dirancang untuk menangani objek Post "
|
||||
"yang aktif dan memungkinkan penyaringan berdasarkan filter yang ditentukan. "
|
||||
"Kelas ini terintegrasi dengan sistem penyaringan backend Django dan "
|
||||
"memastikan operasi sesuai dengan izin yang ditentukan. Kumpulan view juga "
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Anteprima immagine"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,89 +25,80 @@ msgstr "Elenco di tutti i messaggi (solo lettura)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Recuperare un singolo post (solo lettura)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Rappresenta il modello di un post di un blog. La classe Post definisce la "
|
||||
"struttura e il comportamento di un post del blog. Include gli attributi per "
|
||||
"l'autore, il titolo, il contenuto, l'allegato opzionale, lo slug e i tag "
|
||||
"associati. La classe impone dei vincoli, come la richiesta di un contenuto o"
|
||||
" di un file allegato, ma non di entrambi contemporaneamente. Supporta anche "
|
||||
"associati. La classe impone dei vincoli, come la richiesta di un contenuto o "
|
||||
"di un file allegato, ma non di entrambi contemporaneamente. Supporta anche "
|
||||
"la generazione automatica dello slug in base al titolo."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Titolo del post"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Titolo"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "contenuto"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "pubblicare contenuti"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "è una pagina statica"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"Si tratta di un post per una pagina con URL statico (ad esempio "
|
||||
"`/help/delivery`)?"
|
||||
"Si tratta di un post per una pagina con URL statico (ad esempio `/help/"
|
||||
"delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Posta"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Messaggi"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr ""
|
||||
"Il caricamento dei file non è ancora supportato: utilizzare invece i "
|
||||
"contenuti."
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "I file Markdown non sono supportati: usa invece i contenuti Markdown!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"deve essere fornito un file markdown o un contenuto markdown - si escludono "
|
||||
"a vicenda"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identificatore interno del tag post"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Nome del tag"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nome intuitivo per il tag del post"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Nome del tag"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Tag dei post"
|
||||
|
||||
|
|
@ -126,8 +113,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Incapsula le operazioni per gestire e recuperare le entità Post in un "
|
||||
"insieme di viste del modello di sola lettura. Questa classe è fatta su "
|
||||
"misura per gestire gli oggetti Post che sono attivi e consente il filtraggio"
|
||||
" in base ai filtri definiti. Si integra con il sistema di filtraggio del "
|
||||
"misura per gestire gli oggetti Post che sono attivi e consente il filtraggio "
|
||||
"in base ai filtri definiti. Si integra con il sistema di filtraggio del "
|
||||
"backend di Django e garantisce che le operazioni siano in linea con i "
|
||||
"permessi definiti. L'insieme di viste include anche un'ulteriore "
|
||||
"configurazione di permessi 'retrieve'."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "画像プレビュー"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "ブログ"
|
||||
|
|
@ -29,35 +25,30 @@ msgstr "すべての投稿をリストアップする(読み取り専用)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "単一の投稿を取得する(読み取り専用)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"ブログ記事のモデルを表します。Post "
|
||||
"クラスはブログ記事の構造と動作を定義します。著者、タイトル、内容、オプションの添付ファイル、スラッグ、関連タグの属性を含みます。このクラスは、内容か添付ファイルのどちらかを要求するが、両方は同時に要求しないといった制約を強制します。また、タイトルに基づくスラッグの自動生成もサポートしています。"
|
||||
"ブログ記事のモデルを表します。Post クラスはブログ記事の構造と動作を定義しま"
|
||||
"す。著者、タイトル、内容、オプションの添付ファイル、スラッグ、関連タグの属性"
|
||||
"を含みます。このクラスは、内容か添付ファイルのどちらかを要求するが、両方は同"
|
||||
"時に要求しないといった制約を強制します。また、タイトルに基づくスラッグの自動"
|
||||
"生成もサポートしています。"
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "投稿タイトル"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "タイトル"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "内容"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "投稿内容"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "は静的ページ"
|
||||
|
||||
|
|
@ -65,43 +56,48 @@ msgstr "は静的ページ"
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr "これは静的URLのページ(例:`/help/delivery`)への投稿ですか?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "ポスト"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "投稿"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテンツを使用してください!"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテ"
|
||||
"ンツを使用してください!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
msgstr "マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならない。"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならな"
|
||||
"い。"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "投稿タグの内部タグ識別子"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "タグ名"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "投稿タグのユーザーフレンドリーな名前"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "タグ表示名"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "投稿タグ"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "投稿タグ"
|
||||
|
||||
|
|
@ -114,7 +110,9 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"読み取り専用のモデルビューセットにおける Post エンティティの管理と取得のための操作をカプセル化します。このクラスは、アクティブな Post "
|
||||
"オブジェクトを扱い、定義されたフィルタに基 づいてフィルタリングできるように調整されています。Django "
|
||||
"のバックエンドのフィルタリングシステムと統合し、定義されたパーミッションに沿った操作を保証します。ビューセットには、追加の 'retrieve' "
|
||||
"権限設定も含まれます。"
|
||||
"読み取り専用のモデルビューセットにおける Post エンティティの管理と取得のため"
|
||||
"の操作をカプセル化します。このクラスは、アクティブな Post オブジェクトを扱"
|
||||
"い、定義されたフィルタに基 づいてフィルタリングできるように調整されています。"
|
||||
"Django のバックエンドのフィルタリングシステムと統合し、定義されたパーミッショ"
|
||||
"ンに沿った操作を保証します。ビューセットには、追加の 'retrieve' 権限設定も含"
|
||||
"まれます。"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
# EVIBES GETTEXT TRANSLATIONS
|
||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||
# This file is distributed under the same license as the EVIBES package.
|
||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -12,10 +16,6 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr ""
|
||||
|
|
@ -28,7 +28,7 @@ msgstr ""
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
|
|
@ -38,23 +38,15 @@ msgid ""
|
|||
"title."
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -62,43 +54,44 @@ msgstr ""
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr ""
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "사진 미리보기"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "블로그"
|
||||
|
|
@ -29,36 +25,30 @@ msgstr "모든 게시물 나열(읽기 전용)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "단일 게시물 검색(읽기 전용)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"블로그 글 모델을 나타냅니다. Post 클래스는 블로그 글의 구조와 동작을 정의합니다. 여기에는 작성자, 제목, 콘텐츠, 선택적 파일 "
|
||||
"첨부, 슬러그 및 관련 태그에 대한 속성이 포함됩니다. 이 클래스는 콘텐츠 또는 파일 첨부 중 하나만 요구하고 둘 다 동시에 요구하지 "
|
||||
"않는 등의 제약 조건을 적용합니다. 또한 제목에 따른 자동 슬러그 생성도 지원합니다."
|
||||
"블로그 글 모델을 나타냅니다. Post 클래스는 블로그 글의 구조와 동작을 정의합니"
|
||||
"다. 여기에는 작성자, 제목, 콘텐츠, 선택적 파일 첨부, 슬러그 및 관련 태그에 대"
|
||||
"한 속성이 포함됩니다. 이 클래스는 콘텐츠 또는 파일 첨부 중 하나만 요구하고 "
|
||||
"둘 다 동시에 요구하지 않는 등의 제약 조건을 적용합니다. 또한 제목에 따른 자"
|
||||
"동 슬러그 생성도 지원합니다."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "게시물 제목"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "제목"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "콘텐츠"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "게시물 내용"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "는 정적 페이지입니다."
|
||||
|
||||
|
|
@ -66,43 +56,45 @@ msgstr "는 정적 페이지입니다."
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr "정적 URL(예: `/help/delivery`)이 있는 페이지의 게시물인가요?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "게시물"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "게시물"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "마크다운 파일은 지원되지 않습니다 예 - 대신 마크다운 콘텐츠를 사용하세요!"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"마크다운 파일은 지원되지 않습니다 예 - 대신 마크다운 콘텐츠를 사용하세요!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
msgstr "마크다운 파일 또는 마크다운 콘텐츠를 제공해야 합니다 - 상호 배타적"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr "마크다운 파일 또는 마크다운 콘텐츠가 제공되어야 합니다."
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "게시물 태그의 내부 태그 식별자"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "태그 이름"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "게시물 태그의 사용자 친화적인 이름"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "태그 표시 이름"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "게시물 태그"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "게시물 태그"
|
||||
|
||||
|
|
@ -115,6 +107,8 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"읽기 전용 모델 보기 집합에서 Post 엔티티를 관리하고 검색하기 위한 작업을 캡슐화합니다. 이 클래스는 활성 상태인 Post 개체를 "
|
||||
"처리하도록 맞춤화되어 있으며 정의된 필터를 기반으로 필터링을 허용합니다. 이 클래스는 장고의 백엔드 필터링 시스템과 통합되며 정의된 "
|
||||
"권한에 따라 작업이 이루어지도록 합니다. 보기 세트에는 추가 '검색' 권한 구성도 포함되어 있습니다."
|
||||
"읽기 전용 모델 보기 집합에서 Post 엔티티를 관리하고 검색하기 위한 작업을 캡슐"
|
||||
"화합니다. 이 클래스는 활성 상태인 Post 개체를 처리하도록 맞춤화되어 있으며 정"
|
||||
"의된 필터를 기반으로 필터링을 허용합니다. 이 클래스는 장고의 백엔드 필터링 시"
|
||||
"스템과 통합되며 정의된 권한에 따라 작업이 이루어지도록 합니다. 보기 세트에는 "
|
||||
"추가 '검색' 권한 구성도 포함되어 있습니다."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Afbeelding preview"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Alle berichten weergeven (alleen-lezen)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Een enkel bericht ophalen (alleen-lezen)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Vertegenwoordigt een blogpostmodel. De klasse Post definieert de structuur "
|
||||
"en het gedrag van een blogbericht. Ze bevat attributen voor auteur, titel, "
|
||||
|
|
@ -45,73 +41,66 @@ msgstr ""
|
|||
"maar niet beide tegelijk. Het ondersteunt ook het automatisch genereren van "
|
||||
"slugs op basis van de titel."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Titel van de post"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "inhoud"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "berichtinhoud"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "is statische pagina"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"Is dit een bericht voor een pagina met een statische URL (bijv. "
|
||||
"`/help/delivery`)?"
|
||||
"Is dit een bericht voor een pagina met een statische URL (bijv. `/help/"
|
||||
"delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Plaats"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Berichten"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Markdown-bestanden worden niet ondersteund - gebruik in plaats daarvan "
|
||||
"markdown-inhoud!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds"
|
||||
" exclusief"
|
||||
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds "
|
||||
"exclusief"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "interne tagidentifier voor de posttag"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Tag naam"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Gebruiksvriendelijke naam voor de posttag"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Tag weergavenaam"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Post tags"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Bildeforhåndsvisning"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blogg"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Liste over alle innlegg (skrivebeskyttet)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Hent et enkelt innlegg (skrivebeskyttet)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Representerer en blogginnleggsmodell. Post-klassen definerer strukturen og "
|
||||
"virkemåten til et blogginnlegg. Den inneholder attributter for forfatter, "
|
||||
|
|
@ -45,23 +41,15 @@ msgstr ""
|
|||
"må være med, men ikke begge deler samtidig. Den støtter også automatisk "
|
||||
"generering av slug basert på tittelen."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Innleggets tittel"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Title"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "innhold"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "innleggsinnhold"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "er statisk side"
|
||||
|
||||
|
|
@ -70,44 +58,45 @@ msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
|||
msgstr ""
|
||||
"er dette et innlegg for en side med statisk URL (f.eks. `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Innlegg"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "filopplasting støttes ikke ennå – bruk innhold i stedet"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "Markdown-filer støttes ikke - bruk markdown-innhold i stedet!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"en markdown-fil eller markdown-innhold må oppgis - gjensidig utelukkende"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "intern tagg-identifikator for innleggstaggen"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Tagg navn"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Brukervennlig navn for innleggstaggen"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Visningsnavn for taggen"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Tagger for innlegg"
|
||||
|
||||
|
|
@ -125,5 +114,5 @@ msgstr ""
|
|||
"håndtere Post-objekter som er aktive, og tillater filtrering basert på "
|
||||
"definerte filtre. Den integreres med Djangos backend-filtreringssystem og "
|
||||
"sørger for at operasjonene er i tråd med de definerte tillatelsene. "
|
||||
"Visningssettet inkluderer også en ekstra konfigurasjon for "
|
||||
"\"hent\"-tillatelse."
|
||||
"Visningssettet inkluderer også en ekstra konfigurasjon for \"hent\"-"
|
||||
"tillatelse."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Podgląd obrazu"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Lista wszystkich postów (tylko do odczytu)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Pobieranie pojedynczego wpisu (tylko do odczytu)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Reprezentuje model wpisu na blogu. Klasa Post definiuje strukturę i "
|
||||
"zachowanie wpisu na blogu. Zawiera atrybuty autora, tytułu, treści, "
|
||||
|
|
@ -45,72 +41,64 @@ msgstr ""
|
|||
"nie obu jednocześnie. Obsługuje również automatyczne generowanie slug na "
|
||||
"podstawie tytułu."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Tytuł postu"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Tytuł"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "treść"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "treść postu"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "jest stroną statyczną"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"Czy jest to post dla strony ze statycznym adresem URL (np. "
|
||||
"`/help/delivery`)?"
|
||||
"Czy jest to post dla strony ze statycznym adresem URL (np. `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Posty"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Pliki Markdown nie są obsługiwane - zamiast tego użyj zawartości Markdown!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"należy dostarczyć plik markdown lub zawartość markdown - wzajemnie się "
|
||||
"wykluczające"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "wewnętrzny identyfikator tagu posta"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Nazwa tagu"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Wyświetlana nazwa znacznika"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Tag posta"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Tagi postów"
|
||||
|
||||
|
|
@ -124,8 +112,8 @@ msgid ""
|
|||
"permission configuration."
|
||||
msgstr ""
|
||||
"Enkapsuluje operacje zarządzania i pobierania encji Post w zestawie widoków "
|
||||
"modelu tylko do odczytu. Klasa ta jest dostosowana do obsługi obiektów Post,"
|
||||
" które są aktywne i pozwala na filtrowanie w oparciu o zdefiniowane filtry. "
|
||||
"modelu tylko do odczytu. Klasa ta jest dostosowana do obsługi obiektów Post, "
|
||||
"które są aktywne i pozwala na filtrowanie w oparciu o zdefiniowane filtry. "
|
||||
"Integruje się z backendowym systemem filtrowania Django i zapewnia zgodność "
|
||||
"operacji ze zdefiniowanymi uprawnieniami. Zestaw widoków zawiera również "
|
||||
"dodatkową konfigurację uprawnień \"retrieve\"."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Pré-visualização da imagem"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,88 +25,80 @@ msgstr "Listar todas as postagens (somente leitura)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Recuperar um único post (somente leitura)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Representa um modelo de post de blog. A classe Post define a estrutura e o "
|
||||
"comportamento de um post de blog. Ela inclui atributos para autor, título, "
|
||||
"conteúdo, anexo de arquivo opcional, slug e tags associadas. A classe impõe "
|
||||
"restrições, como exigir conteúdo ou um anexo de arquivo, mas não ambos "
|
||||
"simultaneamente. Ela também oferece suporte à geração automática de slug com"
|
||||
" base no título."
|
||||
"simultaneamente. Ela também oferece suporte à geração automática de slug com "
|
||||
"base no título."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Título da postagem"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Título"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "conteúdo"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "conteúdo da publicação"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "é uma página estática"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"Essa é uma postagem para uma página com URL estático (por exemplo, "
|
||||
"`/help/delivery`)?"
|
||||
"Essa é uma postagem para uma página com URL estático (por exemplo, `/help/"
|
||||
"delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Postar"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Publicações"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Os arquivos markdown não são suportados - use conteúdo markdown em vez "
|
||||
"disso!"
|
||||
"Os arquivos markdown não são suportados - use conteúdo markdown em vez disso!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"um arquivo ou conteúdo de markdown deve ser fornecido - mutuamente exclusivo"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identificador de tag interno para a tag de postagem"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Nome da etiqueta"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nome de fácil utilização para a tag de postagem"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Nome de exibição da tag"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Etiqueta de postagem"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Tags de postagem"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Previzualizare imagine"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Listează toate postările (doar pentru citire)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Recuperează o singură postare (read-only)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Reprezintă un model de postare pe blog. Clasa Post definește structura și "
|
||||
"comportamentul unei postări pe blog. Aceasta include atribute pentru autor, "
|
||||
|
|
@ -45,73 +41,65 @@ msgstr ""
|
|||
"fișier atașat, dar nu ambele simultan. De asemenea, acceptă generarea "
|
||||
"automată a slug-ului pe baza titlului."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Titlul postului"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Titlul"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "conținut"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "conținutul postării"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "este o pagină statică"
|
||||
|
||||
#: engine/blog/models.py:70
|
||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr ""
|
||||
"este aceasta o postare pentru o pagină cu URL static (de exemplu "
|
||||
"`/help/delivery`)?"
|
||||
"este aceasta o postare pentru o pagină cu URL static (de exemplu `/help/"
|
||||
"delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Mesaje"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Fișierele Markdown nu sunt acceptate - utilizați în schimb conținut "
|
||||
"Markdown!"
|
||||
"Fișierele Markdown nu sunt acceptate - utilizați în schimb conținut Markdown!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"trebuie furnizat un fișier markdown sau conținut markdown - se exclud "
|
||||
"reciproc"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identificator intern de etichetă pentru eticheta postului"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Nume etichetă"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nume ușor de utilizat pentru eticheta postului"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Nume afișare etichetă"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Etichetă post"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Etichete poștale"
|
||||
|
||||
|
|
@ -124,8 +112,8 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"Încapsulează operațiunile de gestionare și extragere a entităților Post "
|
||||
"într-un set de vizualizări de model numai pentru citire. Această clasă este "
|
||||
"Încapsulează operațiunile de gestionare și extragere a entităților Post într-"
|
||||
"un set de vizualizări de model numai pentru citire. Această clasă este "
|
||||
"adaptată pentru a gestiona obiectele Post care sunt active și permite "
|
||||
"filtrarea pe baza filtrelor definite. Se integrează cu sistemul de filtrare "
|
||||
"din backend al Django și asigură alinierea operațiunilor cu permisiunile "
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Предварительный просмотр изображения"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Блог"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Список всех сообщений (только для чтени
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Получение одного сообщения (только для чтения)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Представляет модель записи в блоге. Класс Post определяет структуру и "
|
||||
"поведение записи в блоге. Он включает атрибуты автора, заголовка, "
|
||||
|
|
@ -45,23 +41,15 @@ msgstr ""
|
|||
"вложение файла, но не то и другое одновременно. Он также поддерживает "
|
||||
"автоматическую генерацию slug на основе заголовка."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Заголовок сообщения"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Название"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "содержание"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "содержание публикации"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "это статическая страница"
|
||||
|
||||
|
|
@ -70,47 +58,48 @@ msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
|||
msgstr ""
|
||||
"Это сообщение для страницы со статическим URL (например, `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Пост"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Посты"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
|
||||
"содержимое в формате Markdown!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"необходимо предоставить файл разметки или содержимое разметки - "
|
||||
"взаимоисключающие варианты"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "внутренний идентификатор тега для тега post"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Название тега"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Удобное для пользователя название тега поста"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Отображаемое имя тега"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Тэг поста"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Тэги постов"
|
||||
|
||||
|
|
@ -125,8 +114,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Инкапсулирует операции по управлению и получению объектов Post в наборе "
|
||||
"представлений модели, доступном только для чтения. Этот класс предназначен "
|
||||
"для работы с активными объектами Post и позволяет осуществлять фильтрацию на"
|
||||
" основе заданных фильтров. Он интегрируется с системой фильтрации бэкенда "
|
||||
"для работы с активными объектами Post и позволяет осуществлять фильтрацию на "
|
||||
"основе заданных фильтров. Он интегрируется с системой фильтрации бэкенда "
|
||||
"Django и обеспечивает соответствие операций заданным разрешениям. Набор "
|
||||
"представлений также включает дополнительную конфигурацию разрешения "
|
||||
"'retrieve'."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Bildförhandsvisning"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blogg"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Lista alla inlägg (skrivskyddad)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Hämta ett enskilt inlägg (skrivskyddat)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Representerar en modell för blogginlägg. Klassen Post definierar strukturen "
|
||||
"och beteendet för ett blogginlägg. Den innehåller attribut för författare, "
|
||||
|
|
@ -45,23 +41,15 @@ msgstr ""
|
|||
"filbilaga krävs, men inte båda samtidigt. Den stöder också automatisk "
|
||||
"sluggenerering baserat på titeln."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Inläggets titel"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "innehåll"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "inläggsinnehåll"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "är statisk sida"
|
||||
|
||||
|
|
@ -70,45 +58,46 @@ msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
|||
msgstr ""
|
||||
"är detta ett inlägg för en sida med statisk URL (t.ex. `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Inlägg"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "filuppladdningar stöds ännu inte – använd innehåll istället"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "Markdown-filer stöds inte - använd markdown-innehåll istället!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"en markdown-fil eller markdown-innehåll måste tillhandahållas - ömsesidigt "
|
||||
"uteslutande"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "intern taggidentifierare för inläggstaggen"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Tagg namn"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Användarvänligt namn för inläggstaggen"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Taggens visningsnamn"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Post tagg"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Taggar för inlägg"
|
||||
|
||||
|
|
@ -126,5 +115,5 @@ msgstr ""
|
|||
"objekt som är aktiva och tillåter filtrering baserat på definierade filter. "
|
||||
"Den integreras med Djangos backend-filtreringssystem och säkerställer att "
|
||||
"operationerna överensstämmer med de definierade behörigheterna. "
|
||||
"Vyuppsättningen innehåller också en ytterligare behörighetskonfiguration för"
|
||||
" \"hämta\"."
|
||||
"Vyuppsättningen innehåller också en ytterligare behörighetskonfiguration för "
|
||||
"\"hämta\"."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "ภาพตัวอย่าง"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "บล็อก"
|
||||
|
|
@ -29,40 +25,29 @@ msgstr "แสดงรายการโพสต์ทั้งหมด (อ
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "ดึงโพสต์เดียว (อ่านอย่างเดียว)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"แทนแบบจำลองของโพสต์ในบล็อก คลาส Post "
|
||||
"กำหนดโครงสร้างและพฤติกรรมของโพสต์ในบล็อก "
|
||||
"ประกอบด้วยแอตทริบิวต์สำหรับผู้เขียน, ชื่อเรื่อง, เนื้อหา, ไฟล์แนบ "
|
||||
"(ไม่บังคับ), slug และแท็กที่เกี่ยวข้อง คลาสนี้บังคับใช้ข้อจำกัด เช่น "
|
||||
"ต้องมีเนื้อหาหรือไฟล์แนบอย่างใดอย่างหนึ่ง "
|
||||
"แต่ไม่สามารถมีทั้งสองอย่างพร้อมกันได้ นอกจากนี้ยังรองรับการสร้าง slug "
|
||||
"โดยอัตโนมัติจากชื่อเรื่อง"
|
||||
"แทนแบบจำลองของโพสต์ในบล็อก คลาส Post กำหนดโครงสร้างและพฤติกรรมของโพสต์ในบล็อก "
|
||||
"ประกอบด้วยแอตทริบิวต์สำหรับผู้เขียน, ชื่อเรื่อง, เนื้อหา, ไฟล์แนบ (ไม่บังคับ), slug "
|
||||
"และแท็กที่เกี่ยวข้อง คลาสนี้บังคับใช้ข้อจำกัด เช่น ต้องมีเนื้อหาหรือไฟล์แนบอย่างใดอย่างหนึ่ง "
|
||||
"แต่ไม่สามารถมีทั้งสองอย่างพร้อมกันได้ นอกจากนี้ยังรองรับการสร้าง slug โดยอัตโนมัติจากชื่อเรื่อง"
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "ชื่อโพสต์"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "ชื่อเรื่อง"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "เนื้อหา"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "โพสต์เนื้อหา"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "เป็นหน้าคงที่"
|
||||
|
||||
|
|
@ -70,45 +55,44 @@ msgstr "เป็นหน้าคงที่"
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr "นี่คือโพสต์สำหรับหน้าที่มี URL แบบคงที่ (เช่น `/help/delivery`)?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "โพสต์"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "โพสต์"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "ยังไม่รองรับการอัปโหลดไฟล์ - กรุณาใช้เนื้อหาแทน"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "ไฟล์มาร์กดาวน์ยังไม่รองรับในตอนนี้ - กรุณาใช้เนื้อหาแบบมาร์กดาวน์แทน!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"ไฟล์มาร์กดาวน์หรือเนื้อหาแบบมาร์กดาวน์ต้องได้รับการจัดเตรียมไว้ - "
|
||||
"ไม่สามารถใช้ร่วมกันได้"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr "ไฟล์มาร์กดาวน์หรือเนื้อหาแบบมาร์กดาวน์ต้องได้รับการจัดเตรียมไว้ - ไม่สามารถใช้ร่วมกันได้"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "ตัวระบุแท็กภายในสำหรับแท็กโพสต์"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "ชื่อวัน"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "ชื่อที่ใช้งานได้ง่ายสำหรับแท็กโพสต์"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "แสดงชื่อแท็ก"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "โพสต์แท็ก"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "ป้ายกำกับโพสต์"
|
||||
|
||||
|
|
@ -121,9 +105,8 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"รวบรวมการดำเนินการสำหรับการจัดการและดึงข้อมูลเอนทิตีโพสต์ในชุดมุมมองแบบอ่านอย่างเดียว"
|
||||
" "
|
||||
"คลาสนี้ถูกออกแบบมาเพื่อจัดการกับวัตถุโพสต์ที่ใช้งานอยู่และอนุญาตให้มีการกรองตามตัวกรองที่กำหนดไว้"
|
||||
" มันผสานรวมกับระบบการกรองแบ็กเอนด์ของ Django "
|
||||
"และทำให้แน่ใจว่าการดำเนินการสอดคล้องกับสิทธิ์ที่กำหนดไว้ "
|
||||
"ชุดมุมมองยังรวมถึงการกำหนดค่าสิทธิ์ 'ดึงข้อมูล' เพิ่มเติมด้วย"
|
||||
"รวบรวมการดำเนินการสำหรับการจัดการและดึงข้อมูลเอนทิตีโพสต์ในชุดมุมมองแบบอ่านอย่างเดียว "
|
||||
"คลาสนี้ถูกออกแบบมาเพื่อจัดการกับวัตถุโพสต์ที่ใช้งานอยู่และอนุญาตให้มีการกรองตามตัวกรองที่กำหนดไว้ "
|
||||
"มันผสานรวมกับระบบการกรองแบ็กเอนด์ของ Django "
|
||||
"และทำให้แน่ใจว่าการดำเนินการสอดคล้องกับสิทธิ์ที่กำหนดไว้ ชุดมุมมองยังรวมถึงการกำหนดค่าสิทธิ์ "
|
||||
"'ดึงข้อมูล' เพิ่มเติมด้วย"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Resim önizlemesi"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,39 +25,31 @@ msgstr "Tüm gönderileri listele (salt okunur)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Tek bir gönderiyi al (salt okunur)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Bir blog yazısı modelini temsil eder. Post sınıfı, bir blog gönderisinin "
|
||||
"yapısını ve davranışını tanımlar. Yazar, başlık, içerik, isteğe bağlı dosya "
|
||||
"eki, slug ve ilişkili etiketler için öznitelikler içerir. Sınıf, içerik veya"
|
||||
" dosya eki gerektirme ancak her ikisini aynı anda gerektirmeme gibi "
|
||||
"eki, slug ve ilişkili etiketler için öznitelikler içerir. Sınıf, içerik veya "
|
||||
"dosya eki gerektirme ancak her ikisini aynı anda gerektirmeme gibi "
|
||||
"kısıtlamalar uygular. Ayrıca başlığa dayalı otomatik slug oluşturmayı da "
|
||||
"destekler."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Gönderinin başlığı"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Başlık"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "içerik"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "yazı içeriği"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "statik sayfadır"
|
||||
|
||||
|
|
@ -71,47 +59,47 @@ msgstr ""
|
|||
"Bu, statik URL'ye sahip bir sayfa (örneğin `/help/delivery`) için bir "
|
||||
"gönderi mi?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Posta"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Mesajlar"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Markdown dosyaları desteklenmiyor yer - bunun yerine markdown içeriği "
|
||||
"kullanın!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"bir markdown dosyası veya markdown içeriği sağlanmalıdır - birbirini "
|
||||
"dışlayan"
|
||||
"bir markdown dosyası veya markdown içeriği sağlanmalıdır - birbirini dışlayan"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "gönderi etiketi için dahili etiket tanımlayıcısı"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Etiket adı"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Gönderi etiketi için kullanıcı dostu ad"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Etiket görünen adı"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Mesaj etiketi"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Gönderi etiketleri"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "Xem trước hình ảnh"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
|
@ -29,14 +25,14 @@ msgstr "Danh sách tất cả các bài đăng (chỉ đọc)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "Lấy một bài đăng duy nhất (chỉ đọc)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"Đại diện cho mô hình bài viết blog. Lớp Post định nghĩa cấu trúc và hành vi "
|
||||
"của một bài viết blog. Nó bao gồm các thuộc tính cho tác giả, tiêu đề, nội "
|
||||
|
|
@ -44,23 +40,15 @@ msgstr ""
|
|||
"ràng buộc như yêu cầu phải có nội dung hoặc tệp đính kèm nhưng không cả hai "
|
||||
"cùng lúc. Nó cũng hỗ trợ tạo slug tự động dựa trên tiêu đề."
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "Tiêu đề bài đăng"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "Tiêu đề"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "nội dung"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "Nội dung bài đăng"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "là trang tĩnh"
|
||||
|
||||
|
|
@ -70,46 +58,47 @@ msgstr ""
|
|||
"Đây có phải là bài đăng cho một trang có URL tĩnh (ví dụ: `/help/delivery`) "
|
||||
"không?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "Bài đăng"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "Bài đăng"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Tệp Markdown hiện chưa được hỗ trợ - hãy sử dụng nội dung Markdown thay thế!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"Phải cung cấp tệp Markdown hoặc nội dung Markdown - hai tùy chọn này là "
|
||||
"tương phản nhau."
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "Mã định danh thẻ nội bộ cho thẻ bài viết"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "Tên ngày"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Tên thân thiện với người dùng cho thẻ bài viết"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "Hiển thị tên thẻ"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "Thẻ bài viết"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "Thẻ bài viết"
|
||||
|
||||
|
|
@ -124,7 +113,6 @@ msgid ""
|
|||
msgstr ""
|
||||
"Đóng gói các thao tác quản lý và truy xuất các thực thể Post trong một bộ "
|
||||
"xem mô hình chỉ đọc. Lớp này được thiết kế để xử lý các đối tượng Post đang "
|
||||
"hoạt động và cho phép lọc dựa trên các bộ lọc đã định nghĩa. Nó tích hợp với"
|
||||
" hệ thống lọc phía sau của Django và đảm bảo các thao tác tuân thủ các quyền"
|
||||
" hạn đã định nghĩa. Bộ xem cũng bao gồm một cấu hình quyền 'retrieve' bổ "
|
||||
"sung."
|
||||
"hoạt động và cho phép lọc dựa trên các bộ lọc đã định nghĩa. Nó tích hợp với "
|
||||
"hệ thống lọc phía sau của Django và đảm bảo các thao tác tuân thủ các quyền "
|
||||
"hạn đã định nghĩa. Bộ xem cũng bao gồm một cấu hình quyền 'retrieve' bổ sung."
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SCHON 2026.1\n"
|
||||
"Project-Id-Version: EVIBES 2025.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-05 16:16+0300\n"
|
||||
"POT-Creation-Date: 2025-12-10 21:44+0300\n"
|
||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
@ -13,10 +13,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: engine/blog/admin.py:49
|
||||
msgid "picture preview"
|
||||
msgstr "图片预览"
|
||||
|
||||
#: engine/blog/apps.py:8
|
||||
msgid "blog"
|
||||
msgstr "博客"
|
||||
|
|
@ -29,34 +25,28 @@ msgstr "列出所有帖子(只读)"
|
|||
msgid "retrieve a single post (read-only)"
|
||||
msgstr "检索单个帖子(只读)"
|
||||
|
||||
#: engine/blog/models.py:22
|
||||
#: engine/blog/models.py:13
|
||||
msgid ""
|
||||
"Represents a blog post model. The Post class defines the structure and "
|
||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||
"optional file attachment, slug, and associated tags. The class enforces "
|
||||
"constraints such as requiring either content or a file attachment but not "
|
||||
"both simultaneously. It also supports automatic slug generation based on the"
|
||||
" title."
|
||||
"both simultaneously. It also supports automatic slug generation based on the "
|
||||
"title."
|
||||
msgstr ""
|
||||
"代表博文模型。帖子类定义了博文的结构和行为。它包括作者、标题、内容、可选文件附件、标签和相关标记的属性。该类可强制执行一些限制条件,如要求提供内容或文件附件,但不能同时提供这两种内容。它还支持根据标题自动生成标签。"
|
||||
"代表博文模型。帖子类定义了博文的结构和行为。它包括作者、标题、内容、可选文件"
|
||||
"附件、标签和相关标记的属性。该类可强制执行一些限制条件,如要求提供内容或文件"
|
||||
"附件,但不能同时提供这两种内容。它还支持根据标题自动生成标签。"
|
||||
|
||||
#: engine/blog/models.py:43
|
||||
#: engine/blog/models.py:24
|
||||
msgid "post title"
|
||||
msgstr "帖子标题"
|
||||
|
||||
#: engine/blog/models.py:44
|
||||
#: engine/blog/models.py:24
|
||||
msgid "title"
|
||||
msgstr "标题"
|
||||
|
||||
#: engine/blog/models.py:47
|
||||
msgid "content"
|
||||
msgstr "内容"
|
||||
|
||||
#: engine/blog/models.py:48
|
||||
msgid "post content"
|
||||
msgstr "发布内容"
|
||||
|
||||
#: engine/blog/models.py:68
|
||||
#: engine/blog/models.py:69
|
||||
msgid "is static page"
|
||||
msgstr "是静态页面"
|
||||
|
||||
|
|
@ -64,43 +54,44 @@ msgstr "是静态页面"
|
|||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||
msgstr "这是静态 URL 页面(如 `/help/delivery`)的帖子吗?"
|
||||
|
||||
#: engine/blog/models.py:82
|
||||
#: engine/blog/models.py:77
|
||||
msgid "post"
|
||||
msgstr "职位"
|
||||
|
||||
#: engine/blog/models.py:83
|
||||
#: engine/blog/models.py:78
|
||||
msgid "posts"
|
||||
msgstr "职位"
|
||||
|
||||
#: engine/blog/models.py:88
|
||||
msgid "file uploads are not supported yet - use content instead"
|
||||
msgstr "目前尚不支持文件上传——请改用内容上传功能"
|
||||
#: engine/blog/models.py:82
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "不支持 Markdown 文件,请使用 Markdown 内容!"
|
||||
|
||||
#: engine/blog/models.py:92
|
||||
msgid "a file or content must be provided - mutually exclusive"
|
||||
msgstr "必须提供一个Markdown文件或Markdown内容——两者互斥"
|
||||
#: engine/blog/models.py:84
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr "必须提供标记符文件或标记符内容 - 相互排斥"
|
||||
|
||||
#: engine/blog/models.py:125
|
||||
#: engine/blog/models.py:116
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "职位标签的内部标签标识符"
|
||||
|
||||
#: engine/blog/models.py:126
|
||||
#: engine/blog/models.py:117
|
||||
msgid "tag name"
|
||||
msgstr "标签名称"
|
||||
|
||||
#: engine/blog/models.py:130
|
||||
#: engine/blog/models.py:121
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "方便用户使用的帖子标签名称"
|
||||
|
||||
#: engine/blog/models.py:131
|
||||
#: engine/blog/models.py:122
|
||||
msgid "tag display name"
|
||||
msgstr "标签显示名称"
|
||||
|
||||
#: engine/blog/models.py:139
|
||||
#: engine/blog/models.py:130
|
||||
msgid "post tag"
|
||||
msgstr "职位标签"
|
||||
|
||||
#: engine/blog/models.py:140
|
||||
#: engine/blog/models.py:131
|
||||
msgid "post tags"
|
||||
msgstr "帖子标签"
|
||||
|
||||
|
|
@ -113,5 +104,6 @@ msgid ""
|
|||
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||
"permission configuration."
|
||||
msgstr ""
|
||||
"该类封装了在只读模型视图集中管理和检索 \"帖子 \"实体的操作。该类专门用于处理活动的 \"帖子 \"对象,并允许根据定义的过滤器进行过滤。它与 "
|
||||
"Django 的后台过滤系统集成,确保操作与定义的权限一致。视图集还包括额外的 \"检索 \"权限配置。"
|
||||
"该类封装了在只读模型视图集中管理和检索 \"帖子 \"实体的操作。该类专门用于处理"
|
||||
"活动的 \"帖子 \"对象,并允许根据定义的过滤器进行过滤。它与 Django 的后台过滤"
|
||||
"系统集成,确保操作与定义的权限一致。视图集还包括额外的 \"检索 \"权限配置。"
|
||||
|
|
|
|||
|
|
@ -1,215 +0,0 @@
|
|||
# Generated by Django 5.2.9 on 2026-01-26 12:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("blog", "0007_post_is_static_page"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_ar_ar",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_cs_cz",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_da_dk",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_de_de",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_en_gb",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_en_us",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_es_es",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_fa_ir",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_fr_fr",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_he_il",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_hi_in",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_hr_hr",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_id_id",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_it_it",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_ja_jp",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_kk_kz",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_ko_kr",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_nl_nl",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_no_no",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_pl_pl",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_pt_br",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_ro_ro",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_ru_ru",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_sv_se",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_th_th",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_tr_tr",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_vi_vn",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="content_zh_hans",
|
||||
field=models.TextField(
|
||||
blank=True, help_text="post content", null=True, verbose_name="content"
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
# Generated by Django 5.2.11 on 2026-02-27 15:43
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
import engine.core.utils.db
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("blog", "0008_alter_post_content_alter_post_content_ar_ar_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="post",
|
||||
name="slug",
|
||||
field=engine.core.utils.db.TweakedAutoSlugField(
|
||||
allow_unicode=True,
|
||||
blank=True,
|
||||
editable=False,
|
||||
max_length=88,
|
||||
null=True,
|
||||
overwrite=True,
|
||||
populate_from="title",
|
||||
unique=True,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# Generated by Django 5.2.11 on 2026-03-01 22:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("blog", "0009_alter_post_slug"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="blogpic",
|
||||
field=models.ImageField(blank=True, null=True, upload_to="posts/images/"),
|
||||
),
|
||||
]
|
||||
|
|
@ -5,20 +5,18 @@ from django.db.models import (
|
|||
CharField,
|
||||
FileField,
|
||||
ForeignKey,
|
||||
ImageField,
|
||||
ManyToManyField,
|
||||
TextField,
|
||||
)
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_extensions.db.fields import AutoSlugField
|
||||
from markdown.extensions.toc import TocExtension
|
||||
from markdown_field import MarkdownField
|
||||
|
||||
from engine.core.abstract import NiceModel
|
||||
from engine.core.utils.db import TweakedAutoSlugField, unicode_slugify_function
|
||||
from engine.core.utils.markdown import strip_markdown
|
||||
|
||||
|
||||
class Post(NiceModel):
|
||||
__doc__ = _( # pyright: ignore[reportUnknownVariableType]
|
||||
class Post(NiceModel): # type: ignore [django-manager-missing]
|
||||
__doc__ = _( # type: ignore [assignment]
|
||||
"Represents a blog post model. "
|
||||
"The Post class defines the structure and behavior of a blog post. "
|
||||
"It includes attributes for author, title, content, optional file attachment, slug, and associated tags. "
|
||||
|
|
@ -43,23 +41,46 @@ class Post(NiceModel):
|
|||
help_text=_("post title"),
|
||||
verbose_name=_("title"),
|
||||
)
|
||||
content = TextField(
|
||||
verbose_name=_("content"),
|
||||
help_text=_("post content"),
|
||||
content: MarkdownField = MarkdownField(
|
||||
"content",
|
||||
extensions=[
|
||||
TocExtension(toc_depth=3),
|
||||
"pymdownx.arithmatex",
|
||||
"pymdownx.b64",
|
||||
"pymdownx.betterem",
|
||||
"pymdownx.blocks.admonition",
|
||||
"pymdownx.blocks.caption",
|
||||
"pymdownx.blocks.definition",
|
||||
"pymdownx.blocks.details",
|
||||
"pymdownx.blocks.html",
|
||||
"pymdownx.blocks.tab",
|
||||
"pymdownx.caret",
|
||||
"pymdownx.critic",
|
||||
"pymdownx.emoji",
|
||||
"pymdownx.escapeall",
|
||||
"pymdownx.extra",
|
||||
"pymdownx.fancylists",
|
||||
"pymdownx.highlight",
|
||||
"pymdownx.inlinehilite",
|
||||
"pymdownx.keys",
|
||||
"pymdownx.magiclink",
|
||||
"pymdownx.mark",
|
||||
"pymdownx.pathconverter",
|
||||
"pymdownx.progressbar",
|
||||
"pymdownx.saneheaders",
|
||||
"pymdownx.smartsymbols",
|
||||
"pymdownx.snippets",
|
||||
"pymdownx.striphtml",
|
||||
"pymdownx.superfences",
|
||||
"pymdownx.tasklist",
|
||||
"pymdownx.tilde",
|
||||
],
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
file = FileField(upload_to="posts/", blank=True, null=True)
|
||||
blogpic = ImageField(upload_to="posts/images/", blank=True, null=True)
|
||||
slug = TweakedAutoSlugField(
|
||||
populate_from="title",
|
||||
slugify_function=unicode_slugify_function,
|
||||
allow_unicode=True,
|
||||
unique=True,
|
||||
editable=False,
|
||||
max_length=88,
|
||||
overwrite=True,
|
||||
null=True,
|
||||
slug = AutoSlugField(
|
||||
populate_from="title", allow_unicode=True, unique=True, editable=False
|
||||
)
|
||||
tags = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
|
||||
meta_description = CharField(max_length=150, blank=True, null=True)
|
||||
|
|
@ -74,24 +95,22 @@ class Post(NiceModel):
|
|||
def __str__(self):
|
||||
return f"{self.title} | {self.author.first_name} {self.author.last_name}"
|
||||
|
||||
@cached_property
|
||||
def seo_description(self) -> str:
|
||||
return strip_markdown(self.content or "")[:180]
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("post")
|
||||
verbose_name_plural = _("posts")
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
def save(self, **kwargs):
|
||||
if self.file:
|
||||
raise ValueError(
|
||||
_("file uploads are not supported yet - use content instead")
|
||||
_("markdown files are not supported yet - use markdown content instead")
|
||||
)
|
||||
if not any([self.file, self.content]) or all([self.file, self.content]):
|
||||
raise ValueError(
|
||||
_("a file or content must be provided - mutually exclusive")
|
||||
_(
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
)
|
||||
super().save(*args, **kwargs)
|
||||
)
|
||||
super().save(**kwargs)
|
||||
|
||||
|
||||
class PostTag(NiceModel):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ from rest_framework.fields import SerializerMethodField
|
|||
from rest_framework.serializers import ModelSerializer
|
||||
|
||||
from engine.blog.models import Post, PostTag
|
||||
from engine.core.utils.markdown import render_markdown
|
||||
|
||||
|
||||
class PostTagSerializer(ModelSerializer):
|
||||
|
|
@ -20,4 +19,4 @@ class PostSerializer(ModelSerializer):
|
|||
fields = "__all__"
|
||||
|
||||
def get_content(self, obj: Post) -> str:
|
||||
return render_markdown(obj.content or "")
|
||||
return obj.content.html.replace("\n", "<br/>")
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ from engine.blog.docs.drf.viewsets import POST_SCHEMA
|
|||
from engine.blog.filters import PostFilter
|
||||
from engine.blog.models import Post
|
||||
from engine.blog.serializers import PostSerializer
|
||||
from engine.core.permissions import SchonPermission
|
||||
from engine.core.permissions import EvibesPermission
|
||||
|
||||
|
||||
@extend_schema_view(**POST_SCHEMA)
|
||||
class PostViewSet(ReadOnlyModelViewSet):
|
||||
__doc__ = _(
|
||||
class PostViewSet(ReadOnlyModelViewSet): # type: ignore [type-arg]
|
||||
__doc__ = _( # type: ignore [assignment]
|
||||
"Encapsulates operations for managing and retrieving Post entities in a read-only model view set. "
|
||||
"This class is tailored to handle Post objects that are active and allows filtration based on defined "
|
||||
"filters. It integrates with Django's backend filtering system and ensures operations align with the "
|
||||
|
|
@ -20,7 +20,7 @@ class PostViewSet(ReadOnlyModelViewSet):
|
|||
)
|
||||
|
||||
serializer_class = PostSerializer
|
||||
permission_classes = (SchonPermission,)
|
||||
permission_classes = (EvibesPermission,)
|
||||
queryset = Post.objects.filter(is_active=True)
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_class = PostFilter
|
||||
|
|
|
|||
51
engine/blog/widgets.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
from typing import Any
|
||||
|
||||
from django import forms
|
||||
from django.forms.renderers import BaseRenderer
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
|
||||
class MarkdownEditorWidget(forms.Textarea):
|
||||
class Media:
|
||||
css = {
|
||||
"all": (
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/easymde/2.14.0/easymde.min.css",
|
||||
)
|
||||
}
|
||||
js = ("https://cdnjs.cloudflare.com/ajax/libs/easymde/2.14.0/easymde.min.js",)
|
||||
|
||||
def render(
|
||||
self,
|
||||
name: str,
|
||||
value: str,
|
||||
attrs: dict[Any, Any] | None = None,
|
||||
renderer: BaseRenderer | None = None,
|
||||
):
|
||||
if not attrs:
|
||||
attrs = {}
|
||||
attrs["class"] = "markdown-editor"
|
||||
textarea_html = super().render(name, value, attrs, renderer)
|
||||
textarea_id = attrs.get("id", f"id_{name}")
|
||||
init_js = f"""
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {{
|
||||
var el = document.getElementById("{textarea_id}");
|
||||
if (!el || !window.EasyMDE) return;
|
||||
new EasyMDE({{
|
||||
element: el,
|
||||
spellChecker: false,
|
||||
renderingConfig: {{ singleLineBreaks: false }},
|
||||
autoDownloadFontAwesome: false,
|
||||
toolbar: [
|
||||
"bold","italic","heading","|",
|
||||
"quote","unordered-list","ordered-list","|",
|
||||
"link","image","|",
|
||||
"preview","side-by-side","fullscreen","|",
|
||||
"guide"
|
||||
]
|
||||
}});
|
||||
}});
|
||||
</script>
|
||||
"""
|
||||
# noinspection DjangoSafeString
|
||||
return mark_safe(textarea_html + init_js)
|
||||
|
|
@ -24,20 +24,20 @@ class NiceModel(Model):
|
|||
)
|
||||
created = CreationDateTimeField(
|
||||
_("created"), help_text=_("when the object first appeared on the database")
|
||||
)
|
||||
) # type: ignore [no-untyped-call]
|
||||
modified = ModificationDateTimeField(
|
||||
_("modified"), help_text=_("when the object was last modified")
|
||||
)
|
||||
) # type: ignore [no-untyped-call]
|
||||
|
||||
def save(
|
||||
def save( # type: ignore [override]
|
||||
self,
|
||||
*args,
|
||||
*,
|
||||
force_insert: bool = False,
|
||||
force_update: bool = False,
|
||||
using: str | None = None,
|
||||
update_fields: Collection[str] | None = None,
|
||||
update_modified: bool = True,
|
||||
) -> None: # ty:ignore[invalid-method-override]
|
||||
) -> None:
|
||||
self.update_modified = update_modified
|
||||
return super().save(
|
||||
force_insert=force_insert,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
from contextlib import suppress
|
||||
from typing import Any, Callable, ClassVar, Type
|
||||
from typing import Any, ClassVar, Type
|
||||
|
||||
from constance.admin import Config
|
||||
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
||||
from django.apps import AppConfig, apps
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin import register, site
|
||||
from django.contrib.gis.admin import GISModelAdmin
|
||||
from django.contrib.messages import constants as messages
|
||||
from django.db.models import Model, TextField
|
||||
from django.db.models import Model
|
||||
from django.db.models.query import QuerySet
|
||||
from django.http import HttpRequest
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_celery_beat.admin import ClockedScheduleAdmin as BaseClockedScheduleAdmin
|
||||
from django_celery_beat.admin import CrontabScheduleAdmin as BaseCrontabScheduleAdmin
|
||||
|
|
@ -33,9 +31,7 @@ from mptt.admin import DraggableMPTTAdmin
|
|||
from unfold.admin import ModelAdmin, TabularInline
|
||||
from unfold.contrib.import_export.forms import ExportForm, ImportForm
|
||||
from unfold.decorators import action
|
||||
from unfold.typing import FieldsetsType
|
||||
from unfold.widgets import UnfoldAdminSelectWidget, UnfoldAdminTextInputWidget
|
||||
from unfold_markdown import MarkdownWidget
|
||||
|
||||
from engine.core.forms import (
|
||||
CRMForm,
|
||||
|
|
@ -57,7 +53,6 @@ from engine.core.models import (
|
|||
Order,
|
||||
OrderCrmLink,
|
||||
OrderProduct,
|
||||
PastedImage,
|
||||
Product,
|
||||
ProductImage,
|
||||
ProductTag,
|
||||
|
|
@ -75,7 +70,9 @@ class FieldsetsMixin:
|
|||
additional_fields: list[str] | None = []
|
||||
model: ClassVar[Type[Model]]
|
||||
|
||||
def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> FieldsetsType:
|
||||
def get_fieldsets(
|
||||
self, request: HttpRequest, obj: Any = None
|
||||
) -> list[tuple[str, dict[str, list[str]]]]:
|
||||
if request:
|
||||
pass
|
||||
|
||||
|
|
@ -85,8 +82,8 @@ class FieldsetsMixin:
|
|||
fieldsets = []
|
||||
|
||||
def add_translations_fieldset(
|
||||
fss: FieldsetsType,
|
||||
) -> FieldsetsType:
|
||||
fss: list[tuple[str, dict[str, list[str]]]],
|
||||
) -> list[tuple[str, dict[str, list[str]]]]:
|
||||
with suppress(NotRegistered):
|
||||
transoptions = translator.get_options_for_model(self.model)
|
||||
translation_fields = []
|
||||
|
|
@ -98,7 +95,7 @@ class FieldsetsMixin:
|
|||
_("translations"),
|
||||
{"classes": ["tab"], "fields": translation_fields},
|
||||
)
|
||||
]
|
||||
] # type: ignore [list-item]
|
||||
return fss
|
||||
|
||||
if self.general_fields:
|
||||
|
|
@ -143,13 +140,12 @@ class FieldsetsMixin:
|
|||
ts.append(name)
|
||||
if ts:
|
||||
fieldsets.append((_("timestamps"), {"classes": ["tab"], "fields": ts}))
|
||||
fieldsets = add_translations_fieldset(fieldsets)
|
||||
return fieldsets
|
||||
fieldsets = add_translations_fieldset(fieldsets) # type: ignore [arg-type, assignment]
|
||||
return fieldsets # type: ignore [return-value]
|
||||
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
class ActivationActionsMixin:
|
||||
message_user: Callable
|
||||
actions_on_top = True
|
||||
actions_on_bottom = True
|
||||
actions = [
|
||||
|
|
@ -159,23 +155,23 @@ class ActivationActionsMixin:
|
|||
]
|
||||
|
||||
@action(
|
||||
description=_("Activate selected %(verbose_name_plural)s"), # ty:ignore[invalid-argument-type]
|
||||
description=_("activate selected %(verbose_name_plural)s").lower(),
|
||||
permissions=["change"],
|
||||
)
|
||||
def activate_selected(self, request: HttpRequest, queryset: QuerySet[Any]) -> None:
|
||||
try:
|
||||
queryset.update(is_active=True)
|
||||
self.message_user(
|
||||
self.message_user( # type: ignore [attr-defined]
|
||||
request=request,
|
||||
message=_("selected items have been activated.").lower().title(),
|
||||
message=_("selected items have been activated.").lower(),
|
||||
level=messages.SUCCESS,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||
self.message_user(request=request, message=str(e), level=messages.ERROR) # type: ignore [attr-defined]
|
||||
|
||||
@action(
|
||||
description=_("Deactivate selected %(verbose_name_plural)s"), # ty:ignore[invalid-argument-type]
|
||||
description=_("deactivate selected %(verbose_name_plural)s").lower(),
|
||||
permissions=["change"],
|
||||
)
|
||||
def deactivate_selected(
|
||||
|
|
@ -183,17 +179,17 @@ class ActivationActionsMixin:
|
|||
) -> None:
|
||||
try:
|
||||
queryset.update(is_active=False)
|
||||
self.message_user(
|
||||
self.message_user( # type: ignore [attr-defined]
|
||||
request=request,
|
||||
message=_("selected items have been deactivated.").lower().title(),
|
||||
message=_("selected items have been deactivated.").lower(),
|
||||
level=messages.SUCCESS,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||
self.message_user(request=request, message=str(e), level=messages.ERROR) # type: ignore [attr-defined]
|
||||
|
||||
|
||||
class AttributeValueInline(TabularInline):
|
||||
class AttributeValueInline(TabularInline): # type: ignore [type-arg]
|
||||
model = AttributeValue
|
||||
extra = 0
|
||||
autocomplete_fields = ["attribute"]
|
||||
|
|
@ -205,7 +201,7 @@ class AttributeValueInline(TabularInline):
|
|||
return super().get_queryset(request).select_related("attribute", "product")
|
||||
|
||||
|
||||
class ProductImageInline(TabularInline):
|
||||
class ProductImageInline(TabularInline): # type: ignore [type-arg]
|
||||
model = ProductImage
|
||||
extra = 0
|
||||
tab = True
|
||||
|
|
@ -216,7 +212,7 @@ class ProductImageInline(TabularInline):
|
|||
return super().get_queryset(request).select_related("product")
|
||||
|
||||
|
||||
class StockInline(TabularInline):
|
||||
class StockInline(TabularInline): # type: ignore [type-arg]
|
||||
model = Stock
|
||||
extra = 0
|
||||
form = StockForm
|
||||
|
|
@ -228,7 +224,7 @@ class StockInline(TabularInline):
|
|||
return super().get_queryset(request).select_related("vendor", "product")
|
||||
|
||||
|
||||
class OrderProductInline(TabularInline):
|
||||
class OrderProductInline(TabularInline): # type: ignore [type-arg]
|
||||
model = OrderProduct
|
||||
extra = 0
|
||||
readonly_fields = ("product", "quantity", "buy_price")
|
||||
|
|
@ -246,7 +242,7 @@ class OrderProductInline(TabularInline):
|
|||
)
|
||||
|
||||
|
||||
class CategoryChildrenInline(TabularInline):
|
||||
class CategoryChildrenInline(TabularInline): # type: ignore [type-arg]
|
||||
model = Category
|
||||
fk_name = "parent"
|
||||
extra = 0
|
||||
|
|
@ -259,9 +255,9 @@ class CategoryChildrenInline(TabularInline):
|
|||
@register(AttributeGroup)
|
||||
class AttributeGroupAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = AttributeGroup
|
||||
model = AttributeGroup # type: ignore [misc]
|
||||
list_display = (
|
||||
"name",
|
||||
"modified",
|
||||
|
|
@ -285,9 +281,9 @@ class AttributeGroupAdmin(
|
|||
@register(Attribute)
|
||||
class AttributeAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Attribute
|
||||
model = Attribute # type: ignore [misc]
|
||||
list_display = (
|
||||
"name",
|
||||
"group",
|
||||
|
|
@ -324,9 +320,9 @@ class AttributeAdmin(
|
|||
|
||||
|
||||
@register(AttributeValue)
|
||||
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = AttributeValue
|
||||
model = AttributeValue # type: ignore [misc]
|
||||
list_display = (
|
||||
"attribute",
|
||||
"value",
|
||||
|
|
@ -369,7 +365,6 @@ class CategoryAdmin(
|
|||
):
|
||||
# noinspection PyClassVar
|
||||
model = Category
|
||||
formfield_overrides = {TextField: {"widget": MarkdownWidget}}
|
||||
list_display = (
|
||||
"indented_title",
|
||||
"parent",
|
||||
|
|
@ -418,16 +413,18 @@ class CategoryAdmin(
|
|||
@register(Brand)
|
||||
class BrandAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Brand
|
||||
formfield_overrides = {TextField: {"widget": MarkdownWidget}}
|
||||
model = Brand # type: ignore [misc]
|
||||
list_display = (
|
||||
"name",
|
||||
"priority",
|
||||
"is_active",
|
||||
)
|
||||
list_filter = ("is_active",)
|
||||
list_filter = (
|
||||
"categories",
|
||||
"is_active",
|
||||
)
|
||||
search_fields = (
|
||||
"uuid",
|
||||
"name",
|
||||
|
|
@ -454,29 +451,22 @@ class ProductAdmin(
|
|||
ActivationActionsMixin,
|
||||
ModelAdmin,
|
||||
ImportExportModelAdmin,
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Product
|
||||
formfield_overrides = {TextField: {"widget": MarkdownWidget}}
|
||||
actions = ActivationActionsMixin.actions + [
|
||||
"export_to_marketplaces",
|
||||
"ban_from_marketplaces",
|
||||
]
|
||||
model = Product # type: ignore [misc]
|
||||
list_display = (
|
||||
"sku",
|
||||
"name",
|
||||
"is_active",
|
||||
"export_to_marketplaces",
|
||||
"has_images",
|
||||
"category",
|
||||
"brand",
|
||||
"price",
|
||||
"rating",
|
||||
"modified",
|
||||
)
|
||||
list_filter = (
|
||||
"is_active",
|
||||
"is_digital",
|
||||
"is_updatable",
|
||||
"stocks__vendor",
|
||||
"tags__name",
|
||||
"created",
|
||||
|
|
@ -499,7 +489,6 @@ class ProductAdmin(
|
|||
"uuid",
|
||||
"modified",
|
||||
"created",
|
||||
"video_preview",
|
||||
)
|
||||
autocomplete_fields = (
|
||||
"category",
|
||||
|
|
@ -519,80 +508,12 @@ class ProductAdmin(
|
|||
"name",
|
||||
"partnumber",
|
||||
"is_digital",
|
||||
"export_to_marketplaces",
|
||||
]
|
||||
relation_fields = [
|
||||
"category",
|
||||
"brand",
|
||||
"tags",
|
||||
]
|
||||
additional_fields = [
|
||||
"is_updatable",
|
||||
"video",
|
||||
"video_preview",
|
||||
]
|
||||
|
||||
def video_preview(self, obj: Product):
|
||||
if obj.video:
|
||||
return format_html(
|
||||
'<video controls style="max-width:100%;max-height:360px">'
|
||||
'<source src="{}">'
|
||||
"</video>",
|
||||
obj.video.url,
|
||||
)
|
||||
return "—"
|
||||
|
||||
video_preview.short_description = _("video preview") # ty:ignore[unresolved-attribute]
|
||||
|
||||
def has_images(self, obj: Product) -> bool:
|
||||
return obj.has_images
|
||||
|
||||
has_images.boolean = True # ty:ignore[unresolved-attribute]
|
||||
has_images.short_description = _("has images") # ty:ignore[unresolved-attribute]
|
||||
|
||||
@action(
|
||||
description=_("Export selected %(verbose_name_plural)s to marketplaces' feeds"), # ty:ignore[invalid-argument-type]
|
||||
permissions=["change"],
|
||||
)
|
||||
def export_to_marketplaces(
|
||||
self, request: HttpRequest, queryset: QuerySet[Any]
|
||||
) -> None:
|
||||
try:
|
||||
queryset.update(export_to_marketplaces=True)
|
||||
self.message_user(
|
||||
request=request,
|
||||
message=_(
|
||||
"selected %(verbose_name_plural)s have been marked for export."
|
||||
)
|
||||
.lower()
|
||||
.title(),
|
||||
level=messages.SUCCESS,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||
|
||||
@action(
|
||||
description=_("Ban selected %(verbose_name_plural)s from marketplaces' feeds"), # ty:ignore[invalid-argument-type]
|
||||
permissions=["change"],
|
||||
)
|
||||
def ban_from_marketplaces(
|
||||
self, request: HttpRequest, queryset: QuerySet[Any]
|
||||
) -> None:
|
||||
try:
|
||||
queryset.update(export_to_marketplaces=False)
|
||||
self.message_user(
|
||||
request=request,
|
||||
message=_(
|
||||
"selected %(verbose_name_plural)s have been banned from export."
|
||||
)
|
||||
.lower()
|
||||
.title(),
|
||||
level=messages.SUCCESS,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||
|
||||
def get_queryset(self, request):
|
||||
return (
|
||||
|
|
@ -611,9 +532,9 @@ class ProductAdmin(
|
|||
@register(ProductTag)
|
||||
class ProductTagAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = ProductTag
|
||||
model = ProductTag # type: ignore [misc]
|
||||
list_display = ("tag_name",)
|
||||
search_fields = ("tag_name",)
|
||||
readonly_fields = (
|
||||
|
|
@ -631,9 +552,9 @@ class ProductTagAdmin(
|
|||
@register(CategoryTag)
|
||||
class CategoryTagAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = CategoryTag
|
||||
model = CategoryTag # type: ignore [misc]
|
||||
list_display = (
|
||||
"name",
|
||||
"tag_name",
|
||||
|
|
@ -659,9 +580,9 @@ class CategoryTagAdmin(
|
|||
@register(Vendor)
|
||||
class VendorAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Vendor
|
||||
model = Vendor # type: ignore [misc]
|
||||
list_display = (
|
||||
"name",
|
||||
"markup_percent",
|
||||
|
|
@ -701,9 +622,9 @@ class VendorAdmin(
|
|||
@register(Feedback)
|
||||
class FeedbackAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Feedback
|
||||
model = Feedback # type: ignore [misc]
|
||||
list_display = (
|
||||
"order_product",
|
||||
"rating",
|
||||
|
|
@ -736,9 +657,9 @@ class FeedbackAdmin(
|
|||
@register(Order)
|
||||
class OrderAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Order
|
||||
model = Order # type: ignore [misc]
|
||||
list_display = (
|
||||
"human_readable_id",
|
||||
"user",
|
||||
|
|
@ -789,9 +710,9 @@ class OrderAdmin(
|
|||
@register(OrderProduct)
|
||||
class OrderProductAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = OrderProduct
|
||||
model = OrderProduct # type: ignore [misc]
|
||||
list_display = (
|
||||
"order",
|
||||
"product",
|
||||
|
|
@ -829,9 +750,9 @@ class OrderProductAdmin(
|
|||
@register(PromoCode)
|
||||
class PromoCodeAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = PromoCode
|
||||
model = PromoCode # type: ignore [misc]
|
||||
list_display = (
|
||||
"code",
|
||||
"discount_percent",
|
||||
|
|
@ -875,10 +796,9 @@ class PromoCodeAdmin(
|
|||
@register(Promotion)
|
||||
class PromotionAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Promotion
|
||||
formfield_overrides = {TextField: {"widget": MarkdownWidget}}
|
||||
model = Promotion # type: ignore [misc]
|
||||
list_display = (
|
||||
"name",
|
||||
"discount_percent",
|
||||
|
|
@ -905,9 +825,9 @@ class PromotionAdmin(
|
|||
@register(Stock)
|
||||
class StockAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Stock
|
||||
model = Stock # type: ignore [misc]
|
||||
form = StockForm
|
||||
list_display = (
|
||||
"product",
|
||||
|
|
@ -939,8 +859,8 @@ class StockAdmin(
|
|||
"is_active",
|
||||
"sku",
|
||||
"quantity",
|
||||
"purchase_price",
|
||||
"price",
|
||||
"purchase_price",
|
||||
"digital_asset",
|
||||
]
|
||||
additional_fields = [
|
||||
|
|
@ -955,9 +875,9 @@ class StockAdmin(
|
|||
@register(Wishlist)
|
||||
class WishlistAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = Wishlist
|
||||
model = Wishlist # type: ignore [misc]
|
||||
list_display = (
|
||||
"user",
|
||||
"modified",
|
||||
|
|
@ -983,9 +903,9 @@ class WishlistAdmin(
|
|||
@register(ProductImage)
|
||||
class ProductImageAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = ProductImage
|
||||
model = ProductImage # type: ignore [misc]
|
||||
list_display = (
|
||||
"alt",
|
||||
"product",
|
||||
|
|
@ -1018,42 +938,10 @@ class ProductImageAdmin(
|
|||
]
|
||||
|
||||
|
||||
@register(PastedImage)
|
||||
class PastedImageAdmin(ActivationActionsMixin, ModelAdmin):
|
||||
list_display = ("name", "image_preview", "alt_text", "is_active", "created")
|
||||
list_filter = ("is_active",)
|
||||
search_fields = ("name", "alt_text")
|
||||
readonly_fields = ("uuid", "created", "modified", "image_preview_large")
|
||||
|
||||
fieldsets = (
|
||||
(None, {"fields": ("name", "image", "alt_text")}),
|
||||
(_("Preview"), {"fields": ("image_preview_large",)}),
|
||||
(_("Metadata"), {"fields": ("uuid", "is_active", "created", "modified")}),
|
||||
)
|
||||
|
||||
@admin.display(description=_("preview"))
|
||||
def image_preview(self, obj: PastedImage) -> str:
|
||||
if obj.image:
|
||||
return format_html(
|
||||
'<img src="{}" style="max-height: 50px; max-width: 100px;" />',
|
||||
obj.image.url,
|
||||
)
|
||||
return "-"
|
||||
|
||||
@admin.display(description=_("image preview"))
|
||||
def image_preview_large(self, obj: PastedImage) -> str:
|
||||
if obj.image:
|
||||
return format_html(
|
||||
'<img src="{}" style="max-height: 300px; max-width: 500px;" />',
|
||||
obj.image.url,
|
||||
)
|
||||
return "-"
|
||||
|
||||
|
||||
@register(Address)
|
||||
class AddressAdmin(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin):
|
||||
class AddressAdmin(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Address
|
||||
model = Address # type: ignore [misc]
|
||||
list_display = (
|
||||
"street",
|
||||
"city",
|
||||
|
|
@ -1061,10 +949,16 @@ class AddressAdmin(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin):
|
|||
"country",
|
||||
"user",
|
||||
)
|
||||
# country and region are encrypted — DB-level filtering is not possible
|
||||
list_filter = ()
|
||||
# street, city, postal_code are encrypted — DB-level search is not possible
|
||||
search_fields = ("user__email",)
|
||||
list_filter = (
|
||||
"country",
|
||||
"region",
|
||||
)
|
||||
search_fields = (
|
||||
"street",
|
||||
"city",
|
||||
"postal_code",
|
||||
"user__email",
|
||||
)
|
||||
readonly_fields = (
|
||||
"uuid",
|
||||
"modified",
|
||||
|
|
@ -1097,9 +991,9 @@ class AddressAdmin(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin):
|
|||
@register(CustomerRelationshipManagementProvider)
|
||||
class CustomerRelationshipManagementProviderAdmin(
|
||||
DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin
|
||||
):
|
||||
): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = CustomerRelationshipManagementProvider
|
||||
model = CustomerRelationshipManagementProvider # type: ignore [misc]
|
||||
list_display = (
|
||||
"name",
|
||||
"default",
|
||||
|
|
@ -1126,9 +1020,9 @@ class CustomerRelationshipManagementProviderAdmin(
|
|||
|
||||
|
||||
@register(OrderCrmLink)
|
||||
class OrderCrmLinkAdmin(DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin):
|
||||
class OrderCrmLinkAdmin(DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin): # type: ignore [misc, type-arg]
|
||||
# noinspection PyClassVar
|
||||
model = OrderCrmLink
|
||||
model = OrderCrmLink # type: ignore [misc]
|
||||
list_display = (
|
||||
"crm_lead_id",
|
||||
"order",
|
||||
|
|
@ -1189,10 +1083,12 @@ class ConstanceConfig:
|
|||
_meta = Meta()
|
||||
|
||||
|
||||
site.unregister([Config]) # ty:ignore[invalid-argument-type]
|
||||
site.register([ConstanceConfig], BaseConstanceAdmin) # ty:ignore[invalid-argument-type]
|
||||
# noinspection PyTypeChecker
|
||||
site.unregister([Config])
|
||||
# noinspection PyTypeChecker
|
||||
site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore [list-item]
|
||||
site.site_title = settings.PROJECT_NAME
|
||||
site.site_header = "Schon"
|
||||
site.site_header = "eVibes"
|
||||
site.index_title = settings.PROJECT_NAME
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from django.conf import settings
|
||||
from django.http import FileResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema, inline_serializer
|
||||
from rest_framework import status
|
||||
from rest_framework.fields import CharField, DictField, JSONField, ListField
|
||||
|
|
@ -32,9 +32,6 @@ CUSTOM_OPENAPI_SCHEMA = {
|
|||
"OpenApi3 schema for this API. Format can be selected via content negotiation. "
|
||||
"Language can be selected with Accept-Language and query parameter both."
|
||||
),
|
||||
responses={
|
||||
status.HTTP_200_OK: OpenApiTypes.OBJECT,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +176,7 @@ DOWNLOAD_DIGITAL_ASSET_SCHEMA = {
|
|||
],
|
||||
summary=_("download a digital asset from purchased digital order"),
|
||||
responses={
|
||||
status.HTTP_200_OK: OpenApiTypes.BINARY,
|
||||
status.HTTP_200_OK: FileResponse,
|
||||
status.HTTP_400_BAD_REQUEST: error,
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema, inline_serializer
|
||||
from rest_framework import serializers, status
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from rest_framework import status
|
||||
|
||||
from engine.core.docs.drf import BASE_ERRORS
|
||||
from engine.core.serializers import (
|
||||
|
|
@ -234,7 +234,7 @@ CATEGORY_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Category UUID or slug"),
|
||||
type=OpenApiTypes.STR,
|
||||
type=str,
|
||||
),
|
||||
],
|
||||
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||
|
|
@ -284,7 +284,7 @@ CATEGORY_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Category UUID or slug"),
|
||||
type=OpenApiTypes.STR,
|
||||
type=str,
|
||||
),
|
||||
],
|
||||
responses={
|
||||
|
|
@ -369,7 +369,7 @@ ORDER_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Order UUID or human-readable id"),
|
||||
type=OpenApiTypes.STR,
|
||||
type=str,
|
||||
),
|
||||
],
|
||||
responses={status.HTTP_200_OK: OrderDetailSerializer(), **BASE_ERRORS},
|
||||
|
|
@ -750,30 +750,6 @@ PRODUCT_SCHEMA = {
|
|||
**BASE_ERRORS,
|
||||
},
|
||||
),
|
||||
"exact_list": extend_schema(
|
||||
tags=[
|
||||
"products",
|
||||
],
|
||||
summary=_("retrieve exact products by identifier"),
|
||||
description=_(
|
||||
"retrieve a list of products by identifier type (uuid, slug, or sku). "
|
||||
"Send a POST request with `identificator_type` and `identificators` (list of values)."
|
||||
),
|
||||
request=inline_serializer(
|
||||
name="ExactProductsRequest",
|
||||
fields={
|
||||
"identificator_type": serializers.ChoiceField(
|
||||
choices=["uuid", "slug", "sku"]
|
||||
),
|
||||
"identificators": serializers.ListField(child=serializers.CharField()),
|
||||
},
|
||||
),
|
||||
parameters=[],
|
||||
responses={
|
||||
status.HTTP_200_OK: ProductSimpleSerializer(many=True),
|
||||
**BASE_ERRORS,
|
||||
},
|
||||
),
|
||||
"seo_meta": extend_schema(
|
||||
tags=[
|
||||
"products",
|
||||
|
|
@ -1030,7 +1006,7 @@ BRAND_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Brand UUID or slug"),
|
||||
type=OpenApiTypes.STR,
|
||||
type=str,
|
||||
),
|
||||
],
|
||||
responses={status.HTTP_200_OK: BrandDetailSerializer(), **BASE_ERRORS},
|
||||
|
|
@ -1073,7 +1049,7 @@ BRAND_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Brand UUID or slug"),
|
||||
type=OpenApiTypes.STR,
|
||||
type=str,
|
||||
),
|
||||
],
|
||||
responses={status.HTTP_200_OK: SeoSnapshotSerializer(), **BASE_ERRORS},
|
||||
|
|
|
|||
BIN
engine/core/docs/images/evibes-big-simple.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
engine/core/docs/images/evibes-big.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
engine/core/docs/images/evibes.ico
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
engine/core/docs/images/evibes.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
25
engine/core/docs/images/favicon.svg
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="100.000000pt" height="100.000000pt" viewBox="0 0 100.000000 100.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)"
|
||||
fill="#7965D1" stroke="none">
|
||||
<path d="M678 935 c-73 -50 -88 -121 -38 -175 29 -31 50 -35 57 -13 2 6 -5 14
|
||||
-16 18 -30 9 -26 48 9 88 63 72 130 72 149 -1 18 -67 -6 -117 -89 -182 -97
|
||||
-76 -142 -97 -235 -109 -121 -16 -324 -29 -380 -24 -48 5 -49 4 -33 -13 26
|
||||
-26 108 -34 248 -23 308 23 362 40 480 147 l65 59 0 64 c0 79 -17 114 -72 152
|
||||
-61 41 -100 44 -145 12z"/>
|
||||
<path d="M327 912 c-10 -10 -17 -27 -17 -38 0 -24 35 -64 55 -64 18 0 19 12 3
|
||||
28 -16 16 19 54 46 50 17 -2 22 -11 24 -45 4 -55 -38 -105 -105 -124 -50 -14
|
||||
-179 -17 -225 -6 -34 9 -36 -3 -6 -23 55 -35 251 -29 327 10 95 48 92 168 -6
|
||||
219 -33 17 -78 13 -96 -7z"/>
|
||||
<path d="M475 435 c-60 -8 -171 -19 -245 -25 -74 -7 -137 -14 -139 -16 -2 -2
|
||||
9 -9 25 -16 35 -15 179 -13 309 3 50 7 146 12 215 13 186 2 223 -22 185 -119
|
||||
-20 -53 -49 -78 -115 -100 -37 -12 -54 -14 -69 -5 -41 21 -16 91 36 105 27 6
|
||||
27 7 9 21 -31 22 -69 17 -99 -14 -15 -15 -27 -34 -27 -42 0 -23 52 -90 81
|
||||
-106 43 -22 73 -17 144 22 73 40 93 64 102 118 21 131 -138 193 -412 161z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -10,7 +10,6 @@ from django_elasticsearch_dsl import fields
|
|||
from django_elasticsearch_dsl.registries import registry
|
||||
from elasticsearch import NotFoundError
|
||||
from elasticsearch.dsl import Q, Search
|
||||
from elasticsearch.dsl.types import Hit
|
||||
from rest_framework.request import Request
|
||||
|
||||
from engine.core.models import Brand, Category, Product
|
||||
|
|
@ -200,8 +199,8 @@ def process_query(
|
|||
minimum_should_match=1,
|
||||
)
|
||||
|
||||
def build_search(idxs: list[str], size: int) -> Search[Hit]:
|
||||
result: Search[Hit] = ( # ty: ignore[invalid-assignment]
|
||||
def build_search(idxs: list[str], size: int) -> Search:
|
||||
return (
|
||||
Search(index=idxs)
|
||||
.query(query_base)
|
||||
.extra(
|
||||
|
|
@ -223,7 +222,6 @@ def process_query(
|
|||
)
|
||||
.extra(size=size, track_total_hits=True)
|
||||
)
|
||||
return result
|
||||
|
||||
resp_cats = None
|
||||
if "categories" in indexes:
|
||||
|
|
@ -291,12 +289,12 @@ def process_query(
|
|||
]
|
||||
for qx in product_exact_sequence:
|
||||
try:
|
||||
search_exact = (
|
||||
resp_exact = (
|
||||
Search(index=["products"])
|
||||
.query(qx)
|
||||
.extra(size=5, track_total_hits=False)
|
||||
.execute()
|
||||
)
|
||||
resp_exact = search_exact.execute() # ty: ignore[possibly-missing-attribute]
|
||||
except NotFoundError:
|
||||
resp_exact = None
|
||||
if resp_exact is not None and getattr(resp_exact, "hits", None):
|
||||
|
|
@ -311,7 +309,7 @@ def process_query(
|
|||
.extra(size=5, track_total_hits=False)
|
||||
)
|
||||
try:
|
||||
resp_exact = s_exact.execute() # ty: ignore[possibly-missing-attribute]
|
||||
resp_exact = s_exact.execute()
|
||||
except NotFoundError:
|
||||
resp_exact = None
|
||||
if resp_exact is not None and getattr(resp_exact, "hits", None):
|
||||
|
|
@ -436,9 +434,9 @@ def _lang_analyzer(lang_code: str) -> str:
|
|||
|
||||
class ActiveOnlyMixin:
|
||||
def get_queryset(self) -> QuerySet[Any]:
|
||||
return super().get_queryset().filter(is_active=True) # type: ignore[misc]
|
||||
return super().get_queryset().filter(is_active=True) # type: ignore [no-any-return, misc]
|
||||
|
||||
def should_index_object(self, obj) -> bool:
|
||||
def should_index_object(self, obj) -> bool: # type: ignore [no-untyped-def]
|
||||
return getattr(obj, "is_active", False)
|
||||
|
||||
|
||||
|
|
@ -667,7 +665,7 @@ def process_system_query(
|
|||
.query(mm)
|
||||
.extra(size=size_per_index, track_total_hits=False)
|
||||
)
|
||||
resp = s.execute() # ty: ignore[possibly-missing-attribute]
|
||||
resp = s.execute()
|
||||
for h in resp.hits:
|
||||
name = getattr(h, "name", None) or getattr(h, "title", None) or "N/A"
|
||||
results[idx].append(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
from typing import Any
|
||||
|
||||
from django.db.models import Model, QuerySet
|
||||
from django_elasticsearch_dsl import Document, fields
|
||||
from django_elasticsearch_dsl.registries import registry
|
||||
from health_check.db.models import TestModel
|
||||
|
||||
from engine.core.elasticsearch import (
|
||||
COMMON_ANALYSIS,
|
||||
|
|
@ -10,7 +13,7 @@ from engine.core.elasticsearch import (
|
|||
from engine.core.models import Brand, Category, Product
|
||||
|
||||
|
||||
class BaseDocument(Document):
|
||||
class BaseDocument(Document): # type: ignore [misc]
|
||||
name = fields.TextField(
|
||||
attr="name",
|
||||
analyzer="standard",
|
||||
|
|
@ -192,3 +195,18 @@ class BrandDocument(ActiveOnlyMixin, BaseDocument):
|
|||
|
||||
add_multilang_fields(BrandDocument)
|
||||
registry.register_document(BrandDocument)
|
||||
|
||||
|
||||
class TestModelDocument(Document): # type: ignore [misc]
|
||||
class Index:
|
||||
name = "testmodels"
|
||||
|
||||
class Django:
|
||||
model = TestModel
|
||||
fields = ["title"]
|
||||
ignore_signals = True
|
||||
related_models: list[Any] = []
|
||||
auto_refresh = False
|
||||
|
||||
|
||||
registry.register_document(TestModelDocument)
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
from engine.core.feeds.amazon_seller import AmazonSellerFeedGenerator
|
||||
from engine.core.feeds.base import BaseFeedGenerator
|
||||
from engine.core.feeds.google_merchant import GoogleMerchantFeedGenerator
|
||||
from engine.core.feeds.yandex_market import YandexMarketFeedGenerator
|
||||
from engine.core.feeds.yandex_products import YandexProductsFeedGenerator
|
||||
|
||||
FEED_GENERATORS: dict[str, type[BaseFeedGenerator]] = {
|
||||
"google_merchant": GoogleMerchantFeedGenerator,
|
||||
"yandex_market": YandexMarketFeedGenerator,
|
||||
"yandex_products": YandexProductsFeedGenerator,
|
||||
"amazon_seller": AmazonSellerFeedGenerator,
|
||||
}
|
||||
|
||||
__all__ = [
|
||||
"BaseFeedGenerator",
|
||||
"GoogleMerchantFeedGenerator",
|
||||
"YandexMarketFeedGenerator",
|
||||
"YandexProductsFeedGenerator",
|
||||
"AmazonSellerFeedGenerator",
|
||||
"FEED_GENERATORS",
|
||||
]
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
from datetime import datetime
|
||||
from typing import Any
|
||||
from xml.etree.ElementTree import Element, SubElement
|
||||
|
||||
from constance import config
|
||||
from django.conf import settings
|
||||
from django.db.models import QuerySet
|
||||
|
||||
from engine.core.feeds.base import BaseFeedGenerator
|
||||
from engine.core.models import Product
|
||||
|
||||
|
||||
class AmazonSellerFeedGenerator(BaseFeedGenerator):
|
||||
"""
|
||||
Amazon Seller Central feed generator.
|
||||
|
||||
Generates product feeds in Amazon's XML format for Seller Central.
|
||||
Reference: https://developer-docs.amazon.com/sp-api/docs/feeds-api-v2021-06-30-reference
|
||||
"""
|
||||
|
||||
name: str = "amazon_seller"
|
||||
supported_formats: tuple[str, ...] = ("xml", "json", "yaml")
|
||||
default_format: str = "xml"
|
||||
|
||||
AMAZON_NS = "http://www.amazon.com/schema/merchant/product/2024-01"
|
||||
|
||||
def generate_feed_data(self, products: QuerySet[Product]) -> dict[str, Any]:
|
||||
"""Generate feed data as a structured dictionary."""
|
||||
messages = []
|
||||
for idx, product in enumerate(products, start=1):
|
||||
message = self._build_message(product, idx)
|
||||
if message:
|
||||
messages.append(message)
|
||||
|
||||
return {
|
||||
"header": {
|
||||
"documentVersion": "1.0",
|
||||
"merchantIdentifier": config.COMPANY_NAME or settings.PROJECT_NAME,
|
||||
},
|
||||
"messageType": "Product",
|
||||
"purgeAndReplace": False,
|
||||
"messages": messages,
|
||||
"generated_at": datetime.now().isoformat(),
|
||||
}
|
||||
|
||||
def _build_message(
|
||||
self, product: Product, message_id: int
|
||||
) -> dict[str, Any] | None:
|
||||
"""Build a message dictionary for a product."""
|
||||
if not product.price or product.price <= 0:
|
||||
return None
|
||||
|
||||
images = self.get_product_images(product)
|
||||
|
||||
description_data: dict[str, Any] = {
|
||||
"title": product.name[:200],
|
||||
"brand": product.brand.name if product.brand else "",
|
||||
"description": (product.description or "")[:2000],
|
||||
"bulletPoint": self._get_bullet_points(product),
|
||||
"manufacturer": product.brand.name
|
||||
if product.brand
|
||||
else config.COMPANY_NAME or "",
|
||||
"itemType": self._get_item_type(product),
|
||||
}
|
||||
|
||||
if images:
|
||||
description_data["mainImage"] = {
|
||||
"imageType": "Main",
|
||||
"imageLocation": images[0],
|
||||
}
|
||||
if len(images) > 1:
|
||||
description_data["otherImages"] = [
|
||||
{"imageType": f"PT{i}", "imageLocation": img}
|
||||
for i, img in enumerate(images[1:9], start=1)
|
||||
]
|
||||
|
||||
message: dict[str, Any] = {
|
||||
"messageID": message_id,
|
||||
"operationType": "Update",
|
||||
"product": {
|
||||
"sku": product.sku,
|
||||
"standardProductID": self._get_standard_product_id(product),
|
||||
"productTaxCode": "A_GEN_TAX",
|
||||
"descriptionData": description_data,
|
||||
"productData": self._get_product_data(product),
|
||||
},
|
||||
}
|
||||
|
||||
return message
|
||||
|
||||
def _get_standard_product_id(self, product: Product) -> dict[str, str]:
|
||||
"""Get standard product identifier (EAN/UPC/GTIN)."""
|
||||
id_types = [
|
||||
("ean", "EAN"),
|
||||
("upc", "UPC"),
|
||||
("gtin", "GTIN"),
|
||||
("isbn", "ISBN"),
|
||||
]
|
||||
|
||||
for attr_value in product.attributes.all():
|
||||
attr_name_lower = attr_value.attribute.name.lower()
|
||||
for attr_key, amazon_type in id_types:
|
||||
if attr_name_lower == attr_key:
|
||||
return {"type": amazon_type, "value": attr_value.value}
|
||||
|
||||
if product.partnumber:
|
||||
return {"type": "PrivateLabel", "value": product.partnumber}
|
||||
|
||||
return {"type": "PrivateLabel", "value": product.sku}
|
||||
|
||||
def _get_bullet_points(self, product: Product) -> list[str]:
|
||||
"""Generate bullet points from product attributes."""
|
||||
bullet_points = []
|
||||
|
||||
for attr_value in product.attributes.all()[:5]:
|
||||
bullet_points.append(f"{attr_value.attribute.name}: {attr_value.value}")
|
||||
|
||||
return bullet_points
|
||||
|
||||
def _get_item_type(self, product: Product) -> str:
|
||||
"""Get the item type from category."""
|
||||
if product.category:
|
||||
return product.category.name
|
||||
return "General"
|
||||
|
||||
def _get_product_data(self, product: Product) -> dict[str, Any]:
|
||||
"""Get additional product data."""
|
||||
data = {
|
||||
"price": {
|
||||
"standardPrice": {
|
||||
"value": product.price,
|
||||
"currency": self.get_currency(),
|
||||
},
|
||||
},
|
||||
"inventory": {
|
||||
"quantity": product.quantity,
|
||||
"fulfillmentLatency": 3,
|
||||
},
|
||||
}
|
||||
|
||||
if product.discount_price:
|
||||
sale_price = product.price - product.discount_price
|
||||
if sale_price > 0:
|
||||
data["price"]["salePrice"] = {
|
||||
"value": sale_price,
|
||||
"currency": self.get_currency(),
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
def to_xml(self, data: dict[str, Any]) -> str:
|
||||
"""Convert feed data to Amazon XML format."""
|
||||
envelope = Element("AmazonEnvelope")
|
||||
envelope.set("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
envelope.set("xsi:noNamespaceSchemaLocation", "amzn-envelope.xsd")
|
||||
|
||||
header = SubElement(envelope, "Header")
|
||||
doc_version = SubElement(header, "DocumentVersion")
|
||||
doc_version.text = data["header"]["documentVersion"]
|
||||
merchant_id = SubElement(header, "MerchantIdentifier")
|
||||
merchant_id.text = data["header"]["merchantIdentifier"]
|
||||
|
||||
message_type = SubElement(envelope, "MessageType")
|
||||
message_type.text = data["messageType"]
|
||||
|
||||
purge = SubElement(envelope, "PurgeAndReplace")
|
||||
purge.text = "true" if data["purgeAndReplace"] else "false"
|
||||
|
||||
for msg_data in data["messages"]:
|
||||
self._add_message_to_xml(envelope, msg_data)
|
||||
|
||||
return '<?xml version="1.0" encoding="UTF-8"?>\n' + self.prettify_xml(envelope)
|
||||
|
||||
def _add_message_to_xml(self, envelope: Element, msg_data: dict[str, Any]) -> None:
|
||||
"""Add a message to the XML envelope."""
|
||||
message = SubElement(envelope, "Message")
|
||||
|
||||
message_id = SubElement(message, "MessageID")
|
||||
message_id.text = str(msg_data["messageID"])
|
||||
|
||||
operation_type = SubElement(message, "OperationType")
|
||||
operation_type.text = msg_data["operationType"]
|
||||
|
||||
product = SubElement(message, "Product")
|
||||
product_data = msg_data["product"]
|
||||
|
||||
sku = SubElement(product, "SKU")
|
||||
sku.text = product_data["sku"]
|
||||
|
||||
std_product_id = SubElement(product, "StandardProductID")
|
||||
type_elem = SubElement(std_product_id, "Type")
|
||||
type_elem.text = product_data["standardProductID"]["type"]
|
||||
value_elem = SubElement(std_product_id, "Value")
|
||||
value_elem.text = product_data["standardProductID"]["value"]
|
||||
|
||||
tax_code = SubElement(product, "ProductTaxCode")
|
||||
tax_code.text = product_data["productTaxCode"]
|
||||
|
||||
desc_data = SubElement(product, "DescriptionData")
|
||||
self._add_description_data_to_xml(desc_data, product_data["descriptionData"])
|
||||
|
||||
def _add_description_data_to_xml(
|
||||
self, parent: Element, desc_data: dict[str, Any]
|
||||
) -> None:
|
||||
"""Add description data to the XML element."""
|
||||
title = SubElement(parent, "Title")
|
||||
title.text = desc_data["title"]
|
||||
|
||||
if desc_data.get("brand"):
|
||||
brand = SubElement(parent, "Brand")
|
||||
brand.text = desc_data["brand"]
|
||||
|
||||
if desc_data.get("description"):
|
||||
description = SubElement(parent, "Description")
|
||||
description.text = desc_data["description"]
|
||||
|
||||
for bullet in desc_data.get("bulletPoint", []):
|
||||
bullet_point = SubElement(parent, "BulletPoint")
|
||||
bullet_point.text = bullet
|
||||
|
||||
if desc_data.get("manufacturer"):
|
||||
manufacturer = SubElement(parent, "Manufacturer")
|
||||
manufacturer.text = desc_data["manufacturer"]
|
||||
|
||||
if desc_data.get("itemType"):
|
||||
item_type = SubElement(parent, "ItemType")
|
||||
item_type.text = desc_data["itemType"]
|
||||
|
||||
if desc_data.get("mainImage"):
|
||||
main_image = SubElement(parent, "MainImage")
|
||||
img_type = SubElement(main_image, "ImageType")
|
||||
img_type.text = desc_data["mainImage"]["imageType"]
|
||||
img_loc = SubElement(main_image, "ImageLocation")
|
||||
img_loc.text = desc_data["mainImage"]["imageLocation"]
|
||||
|
||||
for other_img in desc_data.get("otherImages", []):
|
||||
other_image = SubElement(parent, "OtherImage")
|
||||
img_type = SubElement(other_image, "ImageType")
|
||||
img_type.text = other_img["imageType"]
|
||||
img_loc = SubElement(other_image, "ImageLocation")
|
||||
img_loc.text = other_img["imageLocation"]
|
||||