Merge branch 'master' into storefront-nuxt
233
.gitignore
vendored
|
|
@ -1,136 +1,149 @@
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
||||||
# Python bytecode, caches, and compiled artifacts
|
# ║ ║
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# ║ ███████╗ ██████╗██╗ ██╗ ██████╗ ███╗ ██╗ ║
|
||||||
# Byte-compiled / optimized / DLL files
|
# ║ ██╔════╝██╔════╝██║ ██║██╔═══██╗████╗ ██║ ║
|
||||||
|
# ║ ███████╗██║ ███████║██║ ██║██╔██╗ ██║ ║
|
||||||
|
# ║ ╚════██║██║ ██╔══██║██║ ██║██║╚██╗██║ ║
|
||||||
|
# ║ ███████║╚██████╗██║ ██║╚██████╔╝██║ ╚████║ ║
|
||||||
|
# ║ ╚══════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ║
|
||||||
|
# ║ ║
|
||||||
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
|
||||||
|
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ Python │
|
||||||
|
# └───────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
# Bytecode & compiled
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
*.so
|
*.so
|
||||||
|
|
||||||
# Cache directories
|
# Caches
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
.hypothesis/
|
.hypothesis/
|
||||||
|
.mypy_cache/
|
||||||
.pyre/
|
.pyre/
|
||||||
.pytype/
|
.pytype/
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
.dmypy.json
|
||||||
dmypy.json
|
dmypy.json
|
||||||
cython_debug/
|
cython_debug/
|
||||||
|
|
||||||
# Python environments
|
# Virtual environments
|
||||||
.Python
|
.Python
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
env/
|
env/
|
||||||
|
ENV/
|
||||||
env.bak/
|
env.bak/
|
||||||
ENV.bak/
|
ENV.bak/
|
||||||
venv/
|
|
||||||
venv.bak/
|
venv.bak/
|
||||||
ENV/
|
|
||||||
.venv/
|
|
||||||
__pypackages__/
|
__pypackages__/
|
||||||
.python-version
|
.python-version
|
||||||
|
|
||||||
# Local Django settings and database
|
|
||||||
|
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ Django │
|
||||||
|
# └───────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
local_settings.py
|
local_settings.py
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
db.sqlite3-journal
|
db.sqlite3-journal
|
||||||
|
|
||||||
# Django backups and metadata
|
|
||||||
instance/
|
instance/
|
||||||
backups/
|
backups/
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# Static & media (collected)
|
||||||
# Logs and reports
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
|
||||||
logs/
|
|
||||||
*.log
|
|
||||||
debug.log
|
|
||||||
errors.log
|
|
||||||
test.json
|
|
||||||
coverage.xml
|
|
||||||
coverage.*
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
nosetests.xml
|
|
||||||
tmp
|
|
||||||
|
|
||||||
# Coverage / test reports
|
|
||||||
htmlcov/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
|
|
||||||
# CI / tox / nox
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.scrapy
|
|
||||||
.cover
|
|
||||||
.pybuilder/
|
|
||||||
|
|
||||||
# Storefronts
|
|
||||||
.nuxt/
|
|
||||||
.next/
|
|
||||||
next-env.d.ts
|
|
||||||
|
|
||||||
# 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/
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
|
||||||
# Static, media, and uploads
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
|
||||||
static/
|
static/
|
||||||
media/
|
media/
|
||||||
|
|
||||||
# Allow checked-in static from apps
|
# Allow checked-in app static files
|
||||||
!engine/core/static/
|
!engine/core/static/
|
||||||
!engine/payments/static/
|
!engine/payments/static/
|
||||||
!engine/vibes_auth/static/
|
!engine/vibes_auth/static/
|
||||||
!engine/blog/static/
|
!engine/blog/static/
|
||||||
|
|
||||||
# Webassets
|
# Celery
|
||||||
.webassets-cache/
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
|
||||||
|
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ Testing & Coverage │
|
||||||
|
# └───────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
htmlcov/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
coverage.xml
|
||||||
|
coverage.*
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
nosetests.xml
|
||||||
|
test.json
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
|
||||||
|
|
||||||
|
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ 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 dependencies
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
|
||||||
node_modules/
|
node_modules/
|
||||||
|
.nuxt/
|
||||||
|
.next/
|
||||||
|
next-env.d.ts
|
||||||
|
*.tsbuildinfo
|
||||||
|
.webassets-cache/
|
||||||
|
site/
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# Debug logs
|
||||||
# Cypress test artifacts
|
npm-debug.log*
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Cypress
|
||||||
cypress/videos/
|
cypress/videos/
|
||||||
cypress/screenshots/
|
cypress/screenshots/
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
|
||||||
# IDEs and editors
|
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# │ IDEs & Editors │
|
||||||
|
# └───────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
# VS Code
|
# VS Code
|
||||||
.vscode/
|
.vscode/
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
|
|
@ -139,33 +152,47 @@ cypress/screenshots/
|
||||||
.idea/
|
.idea/
|
||||||
!.idea/icon.svg
|
!.idea/icon.svg
|
||||||
!.idea/externalDependencies.xml
|
!.idea/externalDependencies.xml
|
||||||
!.idea/evibes.iml
|
!.idea/schon.iml
|
||||||
!.idea/evibes.ico
|
|
||||||
|
|
||||||
# Microsoft
|
# Visual Studio
|
||||||
*.suo
|
*.suo
|
||||||
*.ntvs*
|
*.ntvs*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
# Spyder / Rope
|
# Spyder & Rope
|
||||||
.spyderproject
|
.spyderproject
|
||||||
.spyproject
|
.spyproject
|
||||||
.ropeproject
|
.ropeproject
|
||||||
|
|
||||||
# macOS
|
|
||||||
|
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ OS & System │
|
||||||
|
# └───────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
desktop.ini
|
||||||
|
*.iml
|
||||||
|
|
||||||
# TypeScript
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Environment file
|
# ┌───────────────────────────────────────────────────────────────────────────┐
|
||||||
|
# │ Project-specific │
|
||||||
|
# └───────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
# Environment
|
||||||
.env
|
.env
|
||||||
|
|
||||||
# Development stuff
|
# Development
|
||||||
test.ipynb
|
test.ipynb
|
||||||
|
.scrapy
|
||||||
|
.cover
|
||||||
|
.pybuilder/
|
||||||
|
engine/core/vendors/docs/*
|
||||||
|
|
||||||
# Production stuff
|
# Production
|
||||||
.initialized
|
.initialized
|
||||||
queries
|
queries/
|
||||||
|
|
||||||
|
# AI assistants
|
||||||
|
.claude/
|
||||||
|
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
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"
|
|
||||||
when: on_success
|
|
||||||
- when: never
|
|
||||||
|
|
||||||
typecheck:
|
|
||||||
stage: typecheck
|
|
||||||
script:
|
|
||||||
- uv run ty check
|
|
||||||
rules:
|
|
||||||
- changes:
|
|
||||||
- "**/*.py"
|
|
||||||
- "pyproject.toml"
|
|
||||||
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
|
Before Width: | Height: | Size: 41 KiB |
1268
.idea/icon.svg
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 355 KiB |
35
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# 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
|
blog/ @fureunoir contact@fureunoir.com
|
||||||
core/ @fureunoir contact@fureunoir.com
|
core/ @fureunoir contact@fureunoir.com
|
||||||
evibes/ @fureunoir contact@fureunoir.com
|
schon/ @fureunoir contact@fureunoir.com
|
||||||
payments/ @fureunoir contact@fureunoir.com
|
payments/ @fureunoir contact@fureunoir.com
|
||||||
scripts/ @fureunoir contact@fureunoir.com
|
scripts/ @fureunoir contact@fureunoir.com
|
||||||
vibes_auth/ @fureunoir contact@fureunoir.com
|
vibes_auth/ @fureunoir contact@fureunoir.com
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,9 @@ RUN set -eux; \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
gettext \
|
gettext \
|
||||||
libgettextpo-dev \
|
libgettextpo-dev \
|
||||||
graphviz-dev \
|
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
chrony \
|
chrony \
|
||||||
graphviz \
|
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
postgresql-client-17 \
|
postgresql-client-17 \
|
||||||
|
|
@ -38,16 +36,16 @@ RUN set -eux; \
|
||||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
RUN uv venv /opt/evibes-python
|
RUN uv venv /opt/schon-python
|
||||||
ENV VIRTUAL_ENV=/opt/evibes-python
|
ENV VIRTUAL_ENV=/opt/schon-python
|
||||||
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
ENV UV_PROJECT_ENVIRONMENT=/opt/schon-python
|
||||||
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
ENV PATH="/opt/schon-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
COPY pyproject.toml pyproject.toml
|
COPY pyproject.toml pyproject.toml
|
||||||
COPY uv.lock uv.lock
|
COPY uv.lock uv.lock
|
||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
uv sync --extra graph --extra worker --extra openai --locked
|
uv sync --extra worker --extra openai --locked
|
||||||
|
|
||||||
COPY ./scripts/Docker/app-entrypoint.sh /usr/local/bin/app-entrypoint.sh
|
COPY ./scripts/Docker/app-entrypoint.sh /usr/local/bin/app-entrypoint.sh
|
||||||
RUN chmod +x /usr/local/bin/app-entrypoint.sh
|
RUN chmod +x /usr/local/bin/app-entrypoint.sh
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,9 @@ RUN set -eux; \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
gettext \
|
gettext \
|
||||||
libgettextpo-dev \
|
libgettextpo-dev \
|
||||||
graphviz-dev \
|
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
chrony \
|
chrony \
|
||||||
graphviz \
|
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
postgresql-client-17 \
|
postgresql-client-17 \
|
||||||
|
|
@ -37,11 +35,10 @@ RUN set -eux; \
|
||||||
|
|
||||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
RUN uv venv /opt/schon-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
|
||||||
RUN uv venv /opt/evibes-python
|
ENV PATH="/opt/schon-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
ENV VIRTUAL_ENV=/opt/evibes-python
|
|
||||||
|
|
||||||
COPY pyproject.toml pyproject.toml
|
COPY pyproject.toml pyproject.toml
|
||||||
COPY uv.lock uv.lock
|
COPY uv.lock uv.lock
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,9 @@ RUN set -eux; \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
gettext \
|
gettext \
|
||||||
libgettextpo-dev \
|
libgettextpo-dev \
|
||||||
graphviz-dev \
|
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
chrony \
|
chrony \
|
||||||
graphviz \
|
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
postgresql-client-17 \
|
postgresql-client-17 \
|
||||||
|
|
@ -37,11 +35,10 @@ RUN set -eux; \
|
||||||
|
|
||||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
RUN uv venv /opt/schon-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
|
||||||
RUN uv venv /opt/evibes-python
|
ENV PATH="/opt/schon-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
ENV VIRTUAL_ENV=/opt/evibes-python
|
|
||||||
|
|
||||||
COPY pyproject.toml pyproject.toml
|
COPY pyproject.toml pyproject.toml
|
||||||
COPY uv.lock uv.lock
|
COPY uv.lock uv.lock
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
FROM node:22-bookworm-slim AS build
|
FROM node:22-bookworm-slim AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ARG EVIBES_BASE_DOMAIN
|
ARG schon_BASE_DOMAIN
|
||||||
ARG EVIBES_PROJECT_NAME
|
ARG schon_PROJECT_NAME
|
||||||
ENV EVIBES_BASE_DOMAIN=$EVIBES_BASE_DOMAIN
|
ENV schon_BASE_DOMAIN=$schon_BASE_DOMAIN
|
||||||
ENV EVIBES_PROJECT_NAME=$EVIBES_PROJECT_NAME
|
ENV schon_PROJECT_NAME=$schon_PROJECT_NAME
|
||||||
|
|
||||||
COPY ./supervisor/package.json ./supervisor/package-lock.json ./
|
COPY ./supervisor/package.json ./supervisor/package-lock.json ./
|
||||||
RUN npm ci --include=optional
|
RUN npm ci --include=optional
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,9 @@ RUN set -eux; \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
gettext \
|
gettext \
|
||||||
libgettextpo-dev \
|
libgettextpo-dev \
|
||||||
graphviz-dev \
|
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
chrony \
|
chrony \
|
||||||
graphviz \
|
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
postgresql-client-17 \
|
postgresql-client-17 \
|
||||||
|
|
@ -38,10 +36,10 @@ RUN set -eux; \
|
||||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
RUN uv venv /opt/evibes-python
|
RUN uv venv /opt/schon-python
|
||||||
ENV VIRTUAL_ENV=/opt/evibes-python
|
ENV VIRTUAL_ENV=/opt/schon-python
|
||||||
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
ENV UV_PROJECT_ENVIRONMENT=/opt/schon-python
|
||||||
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
ENV PATH="/opt/schon-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
COPY pyproject.toml pyproject.toml
|
COPY pyproject.toml pyproject.toml
|
||||||
COPY uv.lock uv.lock
|
COPY uv.lock uv.lock
|
||||||
|
|
|
||||||
6
LICENSE
|
|
@ -1,8 +1,8 @@
|
||||||
eVibes License – Version 2.0, April 29, 2025
|
Schon License – Version 2.0, April 29, 2025
|
||||||
|
|
||||||
Copyright (c) 2025 Egor “fureunoir” Gorbunov
|
Copyright (c) 2025 Egor “fureunoir” Gorbunov
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
1. Non-Commercial Use
|
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.
|
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
|
Email: contact@fureunoir.com
|
||||||
Telegram: https://t.me/fureunoir
|
Telegram: https://t.me/fureunoir
|
||||||
|
|
||||||
By using the eVibes framework, you acknowledge that you have read and understood this License and agree to be bound by its terms.
|
By using the Schon framework, you acknowledge that you have read and understood this License and agree to be bound by its terms.
|
||||||
|
|
|
||||||
122
Makefile
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
.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
|
||||||
|
|
||||||
|
# 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 " 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
|
||||||
|
|
||||||
|
format: clear
|
||||||
|
@ruff format
|
||||||
|
|
||||||
|
check: clear
|
||||||
|
@ruff check
|
||||||
|
|
||||||
|
typecheck: clear
|
||||||
|
@ty check
|
||||||
|
|
||||||
|
precommit: clear
|
||||||
|
@ruff format
|
||||||
|
@ruff check
|
||||||
|
@ty check
|
||||||
317
README.md
|
|
@ -1,132 +1,263 @@
|
||||||
# eVibes
|
# Schon
|
||||||
|
|
||||||

|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
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.
|
<p align="center">
|
||||||
|
<img src="engine/core/static/logo.png" alt="Schon Logo" width="200"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
- Public issues: https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban
|
**Schon** is a production-ready e-commerce backend. Storefront, product catalog, cart, orders, and payments work out of the box. Minimal complexity, maximum flexibility.
|
||||||
|
|
||||||
## Table of Contents
|
---
|
||||||
|
|
||||||
- Features
|
## What is Schon?
|
||||||
- Quick Start
|
|
||||||
- Prerequisites
|
Schon is a complete backend solution for online stores. Whether you're launching a small shop or scaling a marketplace, Schon provides the foundation:
|
||||||
- Installation
|
|
||||||
- Configuration
|
- **Ready to use** - Clone, configure, deploy. No assembly required.
|
||||||
- Dockerfile
|
- **API-first** - REST and GraphQL endpoints for any frontend framework.
|
||||||
- nginx
|
- **Multilingual** - 28 languages supported out of the box.
|
||||||
- .env
|
- **Extensible** - Modular Django apps, easy to customize.
|
||||||
- Usage
|
|
||||||
- Contributing
|
---
|
||||||
- Contact
|
|
||||||
- License
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Modular backend, easy to extend and customize
|
| Category | Details |
|
||||||
- Dockerized deployment with Docker Compose
|
|----------|---------|
|
||||||
- Celery workers and beat for background tasks
|
| **Framework** | Django 5.2, Django REST Framework 3.16, Graphene-Django |
|
||||||
- REST and GraphQL APIs
|
| **Database** | PostgreSQL with PostGIS, Redis caching, Elasticsearch search |
|
||||||
- Internationalization with modeltranslation
|
| **Tasks** | Celery workers with Redis broker, scheduled tasks with Beat |
|
||||||
- Redis-based caching and queues
|
| **Auth** | JWT authentication, rate limiting, custom user model (email-based) |
|
||||||
- JWT auth and rate limiting
|
| **APIs** | REST + GraphQL, Swagger/ReDoc documentation |
|
||||||
|
| **i18n** | 28 languages, model translation support |
|
||||||
|
| **Deployment** | Docker Compose or native Linux with systemd |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Docker and Docker Compose
|
- Git
|
||||||
|
- Docker and Docker Compose **or** Linux with Python 3.12+, PostgreSQL, Redis, Elasticsearch
|
||||||
|
|
||||||
### Installation
|
### Docker (Recommended for Development)
|
||||||
|
|
||||||
1. Clone the repository
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://gitlab.com/wiseless.xyz/eVibes.git
|
# Clone the repository
|
||||||
cd eVibes
|
git clone https://git.wiseless.xyz/fureunoir/schon
|
||||||
|
cd schon
|
||||||
|
|
||||||
|
# Generate environment file
|
||||||
|
make generate-env
|
||||||
|
|
||||||
|
# Review and adjust .env as needed
|
||||||
|
nano .env
|
||||||
|
|
||||||
|
# Install (pull and build images)
|
||||||
|
make install
|
||||||
|
|
||||||
|
# Start all services
|
||||||
|
make run
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Choose a storefront (optional). The `main` branch ships without a storefront. If you want one, pick a branch:
|
### 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
|
```bash
|
||||||
git checkout storefront-<nuxt|next|sk|qwik>
|
git checkout storefront-<nuxt|next|sk|qwik>
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Install dependencies
|
|
||||||
- Windows
|
|
||||||
```powershell
|
|
||||||
scripts\Windows\install.ps1
|
|
||||||
```
|
|
||||||
- Unix
|
|
||||||
```bash
|
|
||||||
scripts/Unix/install.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Run the stack
|
|
||||||
- Windows
|
|
||||||
```powershell
|
|
||||||
scripts\Windows\run.ps1
|
|
||||||
```
|
|
||||||
- Unix
|
|
||||||
```bash
|
|
||||||
scripts/Unix/run.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Production checklist
|
|
||||||
- Include `nginx.conf` into your Nginx setup
|
|
||||||
- Issue TLS certs with Certbot (https://certbot.eff.org/)
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Dockerfile
|
### Environment Variables
|
||||||
If you rely on locale mirrors, adjust Debian sources before running installation scripts:
|
|
||||||
```
|
After running `make generate-env`, review `.env`:
|
||||||
RUN sed -i 's|https://deb.debian.org/debian|https://ftp.<locale>.debian.org/debian|g' /etc/apt/sources.list.d/debian.sources
|
|
||||||
|
| 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
|
||||||
```
|
```
|
||||||
|
|
||||||
### nginx
|
2. Update domain names and paths in the config
|
||||||
- Comment out SSL-related lines
|
|
||||||
- Apply your domain-specific settings
|
|
||||||
- Run `certbot --cert-only --nginx`
|
|
||||||
- Uncomment SSL lines and reload Nginx
|
|
||||||
|
|
||||||
### .env
|
3. Enable the site:
|
||||||
After generation, review and update secrets and credentials (API keys, DB password, Redis password, etc.).
|
```bash
|
||||||
|
sudo ln -s /etc/nginx/sites-available/schon /etc/nginx/sites-enabled/
|
||||||
|
```
|
||||||
|
|
||||||
## Usage
|
4. Obtain SSL certificates:
|
||||||
|
```bash
|
||||||
|
sudo certbot --nginx -d api.yourdomain.com -d yourdomain.com -d www.yourdomain.com
|
||||||
|
```
|
||||||
|
|
||||||
- DNS records you’ll typically want:
|
5. Reload Nginx:
|
||||||
1. @.your-domain.com
|
```bash
|
||||||
2. www.your-domain.com
|
sudo systemctl reload nginx
|
||||||
3. api.your-domain.com
|
```
|
||||||
4. prometheus.your-domain.com
|
|
||||||
|
|
||||||
- Once running, access:
|
### DNS Records
|
||||||
- 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/
|
|
||||||
|
|
||||||
## Contributing
|
Configure these DNS records pointing to your server:
|
||||||
|
|
||||||
- Track and report issues here: https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=list
|
- `yourdomain.com` (A record)
|
||||||
- Pull requests are welcome. Please keep changes minimal and focused.
|
- `www.yourdomain.com` (A or CNAME)
|
||||||
|
- `api.yourdomain.com` (A or CNAME)
|
||||||
|
- `prometheus.yourdomain.com` (A or CNAME, optional)
|
||||||
|
|
||||||
## Contact
|
---
|
||||||
|
|
||||||
- Author: Egor "fureunoir" Gorbunov
|
## API Documentation
|
||||||
- Email: contact@fureunoir.com
|
|
||||||
- Telegram: https://t.me/fureunoir
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running Migrations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Docker
|
||||||
|
docker compose exec app uv run python manage.py migrate
|
||||||
|
|
||||||
|
# Native
|
||||||
|
cd /opt/schon && .venv/bin/python manage.py migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating a Superuser
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Docker
|
||||||
|
docker compose exec app uv run python manage.py createsuperuser
|
||||||
|
|
||||||
|
# Native
|
||||||
|
cd /opt/schon && .venv/bin/python manage.py createsuperuser
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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
|
## License
|
||||||
|
|
||||||
This project is licensed under the terms of the LICENSE file included in this repository.
|
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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
**Author:** Egor "fureunoir" Gorbunov
|
||||||
|
|
||||||
|
- Email: [contact@fureunoir.com](mailto:contact@fureunoir.com)
|
||||||
|
- Telegram: [@fureunoir](https://t.me/fureunoir)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<sub>Built with care by the Wiseless Team</sub>
|
||||||
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,6 @@ services:
|
||||||
- xpack.security.enabled=false
|
- xpack.security.enabled=false
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
ports:
|
|
||||||
- "9200:9200"
|
|
||||||
volumes:
|
volumes:
|
||||||
- es-data:/usr/share/elasticsearch/data
|
- es-data:/usr/share/elasticsearch/data
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
|
|
@ -147,7 +145,7 @@ services:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD-SHELL", "celery -A evibes status | grep -q 'OK'" ]
|
test: [ "CMD-SHELL", "celery -A schon status | grep -q 'OK'" ]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|
@ -175,7 +173,7 @@ services:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD-SHELL", "celery -A evibes status | grep -q 'OK'" ]
|
test: [ "CMD-SHELL", "celery -A schon status | grep -q 'OK'" ]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,21 @@
|
||||||
from django.contrib.admin import register
|
from django.contrib.admin import register
|
||||||
from django.db.models import TextField
|
from django.db.models import TextField
|
||||||
from django_summernote.admin import (
|
|
||||||
SummernoteModelAdminMixin,
|
|
||||||
)
|
|
||||||
from unfold.admin import ModelAdmin
|
from unfold.admin import ModelAdmin
|
||||||
from unfold_markdown import MarkdownWidget
|
from unfold.contrib.forms.widgets import WysiwygWidget
|
||||||
|
|
||||||
from engine.blog.models import Post, PostTag
|
from engine.blog.models import Post, PostTag
|
||||||
from engine.core.admin import ActivationActionsMixin, FieldsetsMixin
|
from engine.core.admin import ActivationActionsMixin, FieldsetsMixin
|
||||||
|
|
||||||
|
|
||||||
@register(Post)
|
@register(Post)
|
||||||
class PostAdmin(
|
class PostAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
SummernoteModelAdminMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
||||||
):
|
|
||||||
list_display = ("title", "author", "slug", "created", "modified")
|
list_display = ("title", "author", "slug", "created", "modified")
|
||||||
list_filter = ("author", "tags", "created", "modified")
|
list_filter = ("author", "tags", "created", "modified")
|
||||||
search_fields = ("title", "content", "slug")
|
search_fields = ("title", "content", "slug")
|
||||||
filter_horizontal = ("tags",)
|
filter_horizontal = ("tags",)
|
||||||
date_hierarchy = "created"
|
date_hierarchy = "created"
|
||||||
autocomplete_fields = ("tags",)
|
autocomplete_fields = ("tags",)
|
||||||
formfield_overrides = {TextField: {"widget": MarkdownWidget}}
|
formfield_overrides = {TextField: {"widget": WysiwygWidget}}
|
||||||
readonly_fields = (
|
readonly_fields = (
|
||||||
"uuid",
|
"uuid",
|
||||||
"slug",
|
"slug",
|
||||||
|
|
@ -28,7 +23,6 @@ class PostAdmin(
|
||||||
"created",
|
"created",
|
||||||
)
|
)
|
||||||
|
|
||||||
summernote_fields = ("content",)
|
|
||||||
general_fields = [
|
general_fields = [
|
||||||
"title",
|
"title",
|
||||||
"content",
|
"content",
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class PostType(DjangoObjectType):
|
||||||
interfaces = (relay.Node,)
|
interfaces = (relay.Node,)
|
||||||
|
|
||||||
def resolve_content(self: Post, _info: HttpRequest) -> str:
|
def resolve_content(self: Post, _info: HttpRequest) -> str:
|
||||||
return self.content.html.replace("\n", "<br/>")
|
return self.content or ""
|
||||||
|
|
||||||
|
|
||||||
class PostTagType(DjangoObjectType):
|
class PostTagType(DjangoObjectType):
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "سرد جميع المشاركات (للقراءة فقط)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "استرداد منشور واحد (للقراءة فقط)"
|
msgstr "استرداد منشور واحد (للقراءة فقط)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -37,64 +37,72 @@ msgstr ""
|
||||||
"يمثل نموذج منشور المدونة. تحدد فئة المشاركة بنية وسلوك مشاركة المدونة. "
|
"يمثل نموذج منشور المدونة. تحدد فئة المشاركة بنية وسلوك مشاركة المدونة. "
|
||||||
"وتتضمن سمات للمؤلف والعنوان والمحتوى ومرفق الملف الاختياري والسبيكة "
|
"وتتضمن سمات للمؤلف والعنوان والمحتوى ومرفق الملف الاختياري والسبيكة "
|
||||||
"والعلامات المرتبطة بها. يفرض الصنف قيودًا مثل طلب إما محتوى أو مرفق ملف ولكن"
|
"والعلامات المرتبطة بها. يفرض الصنف قيودًا مثل طلب إما محتوى أو مرفق ملف ولكن"
|
||||||
"ليس كلاهما في نفس الوقت. كما أنها تدعم إنشاء سبيكة تلقائية بناءً على العنوان."
|
" ليس كلاهما في نفس الوقت. كما أنها تدعم إنشاء سبيكة تلقائية بناءً على "
|
||||||
|
"العنوان."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "عنوان المنشور"
|
msgstr "عنوان المنشور"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "العنوان"
|
msgstr "العنوان"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "المحتوى"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "نشر المحتوى"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "هي صفحة ثابتة"
|
msgstr "هي صفحة ثابتة"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"هل هذا منشور لصفحة ذات عنوان URL ثابت (على سبيل المثال '/مساعدة/التسليم'؟)"
|
"هل هذا منشور لصفحة ذات عنوان URL ثابت (على سبيل المثال '/مساعدة/التسليم'؟)"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "المنشور"
|
msgstr "المنشور"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "المنشورات"
|
msgstr "المنشورات"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
|
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
msgstr "يجب توفير ملف تخفيض أو محتوى تخفيض - متبادل الاستبعاد"
|
||||||
msgstr "يجب توفير ملف ترميز أو محتوى ترميز مخفض - متنافيان"
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
|
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "اسم العلامة"
|
msgstr "اسم العلامة"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "اسم سهل الاستخدام لعلامة المنشور"
|
msgstr "اسم سهل الاستخدام لعلامة المنشور"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "اسم عرض العلامة"
|
msgstr "اسم عرض العلامة"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "علامة المشاركة"
|
msgstr "علامة المشاركة"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "علامات المشاركة"
|
msgstr "علامات المشاركة"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Seznam všech příspěvků (pouze pro čtení)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Získání jednoho příspěvku (pouze pro čtení)"
|
msgstr "Získání jednoho příspěvku (pouze pro čtení)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -40,65 +40,72 @@ msgstr ""
|
||||||
"je požadavek na obsah nebo přílohu souboru, ale ne obojí současně. Podporuje"
|
"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."
|
" také automatické generování slugu na základě názvu."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Název příspěvku"
|
msgstr "Název příspěvku"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Název"
|
msgstr "Název"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "obsah"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "obsah příspěvku"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "je statická stránka"
|
msgstr "je statická stránka"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"je to příspěvek pro stránku se statickou adresou URL (např. `/help/"
|
"je to příspěvek pro stránku se statickou adresou URL (např. "
|
||||||
"delivery`)?"
|
"`/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Příspěvek"
|
msgstr "Příspěvek"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Příspěvky"
|
msgstr "Příspěvky"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Soubory Markdown nejsou podporovány - místo toho použijte obsah Markdown!"
|
"Soubory Markdown nejsou podporovány - místo toho použijte obsah Markdown!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"musí být poskytnut soubor markdown nebo obsah markdown - vzájemně se "
|
"musí být poskytnut soubor markdown nebo obsah markdown - vzájemně se "
|
||||||
"vylučují."
|
"vylučují."
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "interní identifikátor tagu pro tag příspěvku"
|
msgstr "interní identifikátor tagu pro tag příspěvku"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Název štítku"
|
msgstr "Název štítku"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Uživatelsky přívětivý název pro značku příspěvku"
|
msgstr "Uživatelsky přívětivý název pro značku příspěvku"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Zobrazení názvu štítku"
|
msgstr "Zobrazení názvu štítku"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Označení příspěvku"
|
msgstr "Označení příspěvku"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Štítky příspěvků"
|
msgstr "Štítky příspěvků"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Vis alle indlæg (skrivebeskyttet)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Hent et enkelt indlæg (skrivebeskyttet)"
|
msgstr "Hent et enkelt indlæg (skrivebeskyttet)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,62 +41,69 @@ msgstr ""
|
||||||
"ikke begge dele på samme tid. Den understøtter også automatisk generering af"
|
"ikke begge dele på samme tid. Den understøtter også automatisk generering af"
|
||||||
" slugs baseret på titlen."
|
" slugs baseret på titlen."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Indlæggets titel"
|
msgstr "Indlæggets titel"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "indhold"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "indhold"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "er en statisk side"
|
msgstr "er en statisk side"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Er dette et indlæg til en side med statisk URL (f.eks. `/help/delivery`)?"
|
"Er dette et indlæg til en side med statisk URL (f.eks. `/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Indlæg"
|
msgstr "Indlæg"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Indlæg"
|
msgstr "Indlæg"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "Markdown-filer understøttes ikke - brug markdown-indhold i stedet!"
|
msgstr "filoverførsler understøttes endnu ikke – brug i stedet indhold"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"en markdown-fil eller markdown-indhold skal leveres - gensidigt udelukkende"
|
"en markdown-fil eller markdown-indhold skal leveres - gensidigt udelukkende"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "intern tag-identifikator for indlægs-tagget"
|
msgstr "intern tag-identifikator for indlægs-tagget"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tag-navn"
|
msgstr "Tag-navn"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Brugervenligt navn til posttagget"
|
msgstr "Brugervenligt navn til posttagget"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Navn på tag-visning"
|
msgstr "Navn på tag-visning"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag til indlæg"
|
msgstr "Tag til indlæg"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tags til indlæg"
|
msgstr "Tags til indlæg"
|
||||||
|
|
||||||
|
|
@ -114,4 +121,5 @@ msgstr ""
|
||||||
"håndtere Post-objekter, der er aktive, og tillader filtrering baseret på "
|
"håndtere Post-objekter, der er aktive, og tillader filtrering baseret på "
|
||||||
"definerede filtre. Den integreres med Djangos backend-filtreringssystem og "
|
"definerede filtre. Den integreres med Djangos backend-filtreringssystem og "
|
||||||
"sikrer, at handlingerne er i overensstemmelse med de definerede tilladelser."
|
"sikrer, at handlingerne er i overensstemmelse med de definerede tilladelser."
|
||||||
"Visningssættet indeholder også en ekstra konfiguration af tilladelsen 'hent'."
|
" Visningssættet indeholder også en ekstra konfiguration af tilladelsen "
|
||||||
|
"'hent'."
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Alle Beiträge auflisten (schreibgeschützt)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Einen einzelnen Beitrag abrufen (schreibgeschützt)"
|
msgstr "Einen einzelnen Beitrag abrufen (schreibgeschützt)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -42,66 +42,73 @@ msgstr ""
|
||||||
"unterstützt auch die automatische Slug-Generierung auf der Grundlage des "
|
"unterstützt auch die automatische Slug-Generierung auf der Grundlage des "
|
||||||
"Titels."
|
"Titels."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titel des Beitrags"
|
msgstr "Titel des Beitrags"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "Inhalt"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "Beitragsinhalte"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "ist eine statische Seite"
|
msgstr "ist eine statische Seite"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ist dies ein Beitrag für eine Seite mit statischer URL (z. B. `/help/"
|
"Ist dies ein Beitrag für eine Seite mit statischer URL (z. B. "
|
||||||
"delivery`)?"
|
"`/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Beitrag"
|
msgstr "Beitrag"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Beiträge"
|
msgstr "Beiträge"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Markdown-Dateien werden nicht unterstützt - verwenden Sie stattdessen "
|
"Markdown-Dateien werden nicht unterstützt - verwenden Sie stattdessen "
|
||||||
"Markdown-Inhalte!"
|
"Markdown-Inhalte!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"eine Markdown-Datei oder ein Markdown-Inhalt muss bereitgestellt werden - "
|
"eine Markdown-Datei oder ein Markdown-Inhalt muss bereitgestellt werden - "
|
||||||
"beide schließen sich gegenseitig aus"
|
"beide schließen sich gegenseitig aus"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "interner Tag-Bezeichner für den Post-Tag"
|
msgstr "interner Tag-Bezeichner für den Post-Tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tag name"
|
msgstr "Tag name"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Benutzerfreundlicher Name für das Post-Tag"
|
msgstr "Benutzerfreundlicher Name für das Post-Tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Tag-Anzeigename"
|
msgstr "Tag-Anzeigename"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag eintragen"
|
msgstr "Tag eintragen"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tags eintragen"
|
msgstr "Tags eintragen"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
# 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 ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -29,7 +25,7 @@ msgstr "List all posts (read-only)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Retrieve a single post (read-only)"
|
msgstr "Retrieve a single post (read-only)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -45,61 +41,68 @@ msgstr ""
|
||||||
"both simultaneously. It also supports automatic slug generation based on the"
|
"both simultaneously. It also supports automatic slug generation based on the"
|
||||||
" title."
|
" title."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Post's title"
|
msgstr "Post's title"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Title"
|
msgstr "Title"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "content"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "post content"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "is static page"
|
msgstr "is static page"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
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`)?"
|
msgstr "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Posts"
|
msgstr "Posts"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
msgstr "file uploads are not supported yet - use content instead"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "internal tag identifier for the post tag"
|
msgstr "internal tag identifier for the post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tag name"
|
msgstr "Tag name"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "User-friendly name for the post tag"
|
msgstr "User-friendly name for the post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Tag display name"
|
msgstr "Tag display name"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Post tags"
|
msgstr "Post tags"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "List all posts (read-only)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Retrieve a single post (read-only)"
|
msgstr "Retrieve a single post (read-only)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,61 +41,68 @@ msgstr ""
|
||||||
"both simultaneously. It also supports automatic slug generation based on the"
|
"both simultaneously. It also supports automatic slug generation based on the"
|
||||||
" title."
|
" title."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Post's title"
|
msgstr "Post's title"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Title"
|
msgstr "Title"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "content"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "post content"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "is static page"
|
msgstr "is static page"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
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`)?"
|
msgstr "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Posts"
|
msgstr "Posts"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
msgstr "file uploads are not supported yet - use content instead"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "internal tag identifier for the post tag"
|
msgstr "internal tag identifier for the post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tag name"
|
msgstr "Tag name"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "User-friendly name for the post tag"
|
msgstr "User-friendly name for the post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Tag display name"
|
msgstr "Tag display name"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Post tags"
|
msgstr "Post tags"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Listar todos los mensajes (sólo lectura)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Recuperar una única entrada (sólo lectura)"
|
msgstr "Recuperar una única entrada (sólo lectura)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,65 +41,72 @@ msgstr ""
|
||||||
"adjunto, pero no ambos simultáneamente. También admite la generación "
|
"adjunto, pero no ambos simultáneamente. También admite la generación "
|
||||||
"automática de slug a partir del título."
|
"automática de slug a partir del título."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Título del mensaje"
|
msgstr "Título del mensaje"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Título"
|
msgstr "Título"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "contenido"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "publicar contenido"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "es una página estática"
|
msgstr "es una página estática"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"¿se trata de una entrada para una página con URL estática (por ejemplo, `/"
|
"¿se trata de una entrada para una página con URL estática (por ejemplo, "
|
||||||
"help/delivery`)?"
|
"`/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Publicar en"
|
msgstr "Publicar en"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Puestos"
|
msgstr "Puestos"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"No se admiten archivos Markdown - ¡utiliza contenido Markdown en su lugar!"
|
"No se admiten archivos Markdown - ¡utiliza contenido Markdown en su lugar!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"se debe proporcionar un archivo markdown o contenido markdown - mutuamente "
|
"se debe proporcionar un archivo markdown o contenido markdown - mutuamente "
|
||||||
"excluyentes"
|
"excluyentes"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identificador interno de la etiqueta post"
|
msgstr "identificador interno de la etiqueta post"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nombre de la etiqueta"
|
msgstr "Nombre de la etiqueta"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
|
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nombre de la etiqueta"
|
msgstr "Nombre de la etiqueta"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Etiqueta postal"
|
msgstr "Etiqueta postal"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Etiquetas"
|
msgstr "Etiquetas"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 01:44+0300\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
@ -28,7 +28,7 @@ msgstr ""
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -38,60 +38,67 @@ msgid ""
|
||||||
"title."
|
"title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:77
|
||||||
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:110
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Liste de tous les messages (en lecture seule)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Récupérer un seul message (en lecture seule)"
|
msgstr "Récupérer un seul message (en lecture seule)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -42,66 +42,73 @@ msgstr ""
|
||||||
"simultanément. Elle prend également en charge la génération automatique "
|
"simultanément. Elle prend également en charge la génération automatique "
|
||||||
"d'une balise en fonction du titre."
|
"d'une balise en fonction du titre."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titre du message"
|
msgstr "Titre du message"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titre"
|
msgstr "Titre"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "contenu"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "contenu de publication"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "est une page statique"
|
msgstr "est une page statique"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"s'agit-il d'un message pour une page dont l'URL est statique (par exemple `/"
|
"s'agit-il d'un message pour une page dont l'URL est statique (par exemple "
|
||||||
"help/delivery`) ?"
|
"`/help/delivery`) ?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Poste"
|
msgstr "Poste"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Postes"
|
msgstr "Postes"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Les fichiers Markdown ne sont pas pris en charge - utilisez plutôt du "
|
"Les fichiers Markdown ne sont pas pris en charge - utilisez plutôt du "
|
||||||
"contenu Markdown !"
|
"contenu Markdown !"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent"
|
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent"
|
||||||
" mutuellement"
|
" mutuellement"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identifiant interne de la balise post"
|
msgstr "identifiant interne de la balise post"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nom du jour"
|
msgstr "Nom du jour"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nom convivial pour la balise post"
|
msgstr "Nom convivial pour la balise post"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nom d'affichage de l'étiquette"
|
msgstr "Nom d'affichage de l'étiquette"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag de poste"
|
msgstr "Tag de poste"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tags de la poste"
|
msgstr "Tags de la poste"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "הצג את כל ההודעות (לקריאה בלבד)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "איתור פוסט בודד (לקריאה בלבד)"
|
msgstr "איתור פוסט בודד (לקריאה בלבד)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -39,60 +39,67 @@ msgstr ""
|
||||||
"ותגיות נלוות. המחלקה אוכפת אילוצים כגון דרישה לתוכן או לקובץ מצורף, אך לא "
|
"ותגיות נלוות. המחלקה אוכפת אילוצים כגון דרישה לתוכן או לקובץ מצורף, אך לא "
|
||||||
"לשניהם בו-זמנית. היא תומכת גם ביצירה אוטומטית של slug על סמך הכותרת."
|
"לשניהם בו-זמנית. היא תומכת גם ביצירה אוטומטית של slug על סמך הכותרת."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "כותרת הפוסט"
|
msgstr "כותרת הפוסט"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "כותרת"
|
msgstr "כותרת"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "תוכן"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "תוכן הפוסט"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "הוא דף סטטי"
|
msgstr "הוא דף סטטי"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr "האם זו הודעה לדף עם כתובת URL סטטית (למשל `/help/delivery`)?"
|
msgstr "האם זו הודעה לדף עם כתובת URL סטטית (למשל `/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "פוסט"
|
msgstr "פוסט"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "פוסטים"
|
msgstr "פוסטים"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "קובצי Markdown אינם נתמכים עדיין - השתמש בתוכן Markdown במקום!"
|
msgstr "העלאת קבצים אינה נתמכת עדיין - השתמש בתוכן במקום זאת"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr "יש לספק קובץ markdown או תוכן markdown - באופן בלעדי"
|
msgstr "יש לספק קובץ markdown או תוכן markdown - באופן בלעדי"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "מזהה תגיות פנימי עבור תגיות הפוסט"
|
msgstr "מזהה תגיות פנימי עבור תגיות הפוסט"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "שם היום"
|
msgstr "שם היום"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "שם ידידותי למשתמש עבור תגיות הפוסט"
|
msgstr "שם ידידותי למשתמש עבור תגיות הפוסט"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "שם תצוגה של התג"
|
msgstr "שם תצוגה של התג"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "תגית פוסט"
|
msgstr "תגית פוסט"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "תגיות פוסט"
|
msgstr "תגיות פוסט"
|
||||||
|
|
||||||
|
|
@ -106,6 +113,6 @@ msgid ""
|
||||||
"permission configuration."
|
"permission configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"מכיל פעולות לניהול ואחזור ישויות Post במערך תצוגה של מודל לקריאה בלבד. מחלקה"
|
"מכיל פעולות לניהול ואחזור ישויות Post במערך תצוגה של מודל לקריאה בלבד. מחלקה"
|
||||||
"זו מותאמת לטיפול באובייקטי Post פעילים ומאפשרת סינון על בסיס מסננים מוגדרים. "
|
" זו מותאמת לטיפול באובייקטי Post פעילים ומאפשרת סינון על בסיס מסננים "
|
||||||
"היא משתלבת במערכת הסינון האחורית של Django ומבטיחה שהפעולות תואמות את "
|
"מוגדרים. היא משתלבת במערכת הסינון האחורית של Django ומבטיחה שהפעולות תואמות "
|
||||||
"ההרשאות המוגדרות. מערך התצוגה כולל גם תצורת הרשאה נוספת ל'אחזור'."
|
"את ההרשאות המוגדרות. מערך התצוגה כולל גם תצורת הרשאה נוספת ל'אחזור'."
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
# 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 ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:26+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -28,7 +24,7 @@ msgstr ""
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -38,60 +34,67 @@ msgid ""
|
||||||
"title."
|
"title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:77
|
||||||
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:110
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 01:44+0300\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
@ -28,7 +28,7 @@ msgstr ""
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -38,60 +38,67 @@ msgid ""
|
||||||
"title."
|
"title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:77
|
||||||
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:110
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Daftar semua postingan (hanya-baca)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Mengambil satu postingan (hanya-baca)"
|
msgstr "Mengambil satu postingan (hanya-baca)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,66 +41,73 @@ msgstr ""
|
||||||
" secara bersamaan. Kelas ini juga mendukung pembuatan slug otomatis "
|
" secara bersamaan. Kelas ini juga mendukung pembuatan slug otomatis "
|
||||||
"berdasarkan judul."
|
"berdasarkan judul."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Judul postingan"
|
msgstr "Judul postingan"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Judul"
|
msgstr "Judul"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "konten"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "posting konten"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "adalah halaman statis"
|
msgstr "adalah halaman statis"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"apakah ini adalah postingan untuk halaman dengan URL statis (misalnya `/help/"
|
"apakah ini adalah postingan untuk halaman dengan URL statis (misalnya "
|
||||||
"pengiriman`)?"
|
"`/help/pengiriman`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Pos"
|
msgstr "Pos"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Posting"
|
msgstr "Posting"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"File penurunan harga tidak didukung - gunakan konten penurunan harga sebagai"
|
"File penurunan harga tidak didukung - gunakan konten penurunan harga sebagai"
|
||||||
" gantinya!"
|
" gantinya!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"file penurunan harga atau konten penurunan harga harus disediakan - tidak "
|
"file penurunan harga atau konten penurunan harga harus disediakan - tidak "
|
||||||
"boleh ada yang sama"
|
"boleh ada yang sama"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "pengidentifikasi tag internal untuk tag pos"
|
msgstr "pengidentifikasi tag internal untuk tag pos"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nama tag"
|
msgstr "Nama tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nama yang mudah digunakan untuk tag postingan"
|
msgstr "Nama yang mudah digunakan untuk tag postingan"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nama tampilan tag"
|
msgstr "Nama tampilan tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag pos"
|
msgstr "Tag pos"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tag pos"
|
msgstr "Tag pos"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Elenco di tutti i messaggi (solo lettura)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Recuperare un singolo post (solo lettura)"
|
msgstr "Recuperare un singolo post (solo lettura)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,64 +41,73 @@ msgstr ""
|
||||||
" di un file allegato, ma non di entrambi contemporaneamente. Supporta anche "
|
" di un file allegato, ma non di entrambi contemporaneamente. Supporta anche "
|
||||||
"la generazione automatica dello slug in base al titolo."
|
"la generazione automatica dello slug in base al titolo."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titolo del post"
|
msgstr "Titolo del post"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titolo"
|
msgstr "Titolo"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "contenuto"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "pubblicare contenuti"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "è una pagina statica"
|
msgstr "è una pagina statica"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Si tratta di un post per una pagina con URL statico (ad esempio `/help/"
|
"Si tratta di un post per una pagina con URL statico (ad esempio "
|
||||||
"delivery`)?"
|
"`/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Posta"
|
msgstr "Posta"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Messaggi"
|
msgstr "Messaggi"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "I file Markdown non sono supportati: usa invece i contenuti Markdown!"
|
msgstr ""
|
||||||
|
"Il caricamento dei file non è ancora supportato: utilizzare invece i "
|
||||||
|
"contenuti."
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"deve essere fornito un file markdown o un contenuto markdown - si escludono "
|
"deve essere fornito un file markdown o un contenuto markdown - si escludono "
|
||||||
"a vicenda"
|
"a vicenda"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identificatore interno del tag post"
|
msgstr "identificatore interno del tag post"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nome del tag"
|
msgstr "Nome del tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nome intuitivo per il tag del post"
|
msgstr "Nome intuitivo per il tag del post"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nome del tag"
|
msgstr "Nome del tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tag dei post"
|
msgstr "Tag dei post"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "すべての投稿をリストアップする(読み取り専用)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "単一の投稿を取得する(読み取り専用)"
|
msgstr "単一の投稿を取得する(読み取り専用)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -34,70 +34,70 @@ msgid ""
|
||||||
"both simultaneously. It also supports automatic slug generation based on the"
|
"both simultaneously. It also supports automatic slug generation based on the"
|
||||||
" title."
|
" title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"ブログ記事のモデルを表します。Post クラスはブログ記事の構造と動作を定義しま"
|
"ブログ記事のモデルを表します。Post "
|
||||||
"す。著者、タイトル、内容、オプションの添付ファイル、スラッグ、関連タグの属性"
|
"クラスはブログ記事の構造と動作を定義します。著者、タイトル、内容、オプションの添付ファイル、スラッグ、関連タグの属性を含みます。このクラスは、内容か添付ファイルのどちらかを要求するが、両方は同時に要求しないといった制約を強制します。また、タイトルに基づくスラッグの自動生成もサポートしています。"
|
||||||
"を含みます。このクラスは、内容か添付ファイルのどちらかを要求するが、両方は同"
|
|
||||||
"時に要求しないといった制約を強制します。また、タイトルに基づくスラッグの自動"
|
|
||||||
"生成もサポートしています。"
|
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "投稿タイトル"
|
msgstr "投稿タイトル"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "タイトル"
|
msgstr "タイトル"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "内容"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "投稿内容"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "は静的ページ"
|
msgstr "は静的ページ"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr "これは静的URLのページ(例:`/help/delivery`)への投稿ですか?"
|
msgstr "これは静的URLのページ(例:`/help/delivery`)への投稿ですか?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "ポスト"
|
msgstr "ポスト"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "投稿"
|
msgstr "投稿"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr "マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテンツを使用してください!"
|
||||||
"マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテ"
|
|
||||||
"ンツを使用してください!"
|
#: engine/blog/models.py:77
|
||||||
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
|
msgstr "マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならない。"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:110
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならな"
|
|
||||||
"い。"
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "投稿タグの内部タグ識別子"
|
msgstr "投稿タグの内部タグ識別子"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "タグ名"
|
msgstr "タグ名"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "投稿タグのユーザーフレンドリーな名前"
|
msgstr "投稿タグのユーザーフレンドリーな名前"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "タグ表示名"
|
msgstr "タグ表示名"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "投稿タグ"
|
msgstr "投稿タグ"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "投稿タグ"
|
msgstr "投稿タグ"
|
||||||
|
|
||||||
|
|
@ -110,9 +110,7 @@ msgid ""
|
||||||
"defined permissions. The view set also includes an additional 'retrieve' "
|
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||||
"permission configuration."
|
"permission configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"読み取り専用のモデルビューセットにおける Post エンティティの管理と取得のため"
|
"読み取り専用のモデルビューセットにおける Post エンティティの管理と取得のための操作をカプセル化します。このクラスは、アクティブな Post "
|
||||||
"の操作をカプセル化します。このクラスは、アクティブな Post オブジェクトを扱"
|
"オブジェクトを扱い、定義されたフィルタに基 づいてフィルタリングできるように調整されています。Django "
|
||||||
"い、定義されたフィルタに基 づいてフィルタリングできるように調整されています。"
|
"のバックエンドのフィルタリングシステムと統合し、定義されたパーミッションに沿った操作を保証します。ビューセットには、追加の 'retrieve' "
|
||||||
"Django のバックエンドのフィルタリングシステムと統合し、定義されたパーミッショ"
|
"権限設定も含まれます。"
|
||||||
"ンに沿った操作を保証します。ビューセットには、追加の 'retrieve' 権限設定も含"
|
|
||||||
"まれます。"
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
# 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 ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:13+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -28,7 +24,7 @@ msgstr ""
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -38,60 +34,67 @@ msgid ""
|
||||||
"title."
|
"title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: engine/blog/models.py:77
|
||||||
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:110
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "모든 게시물 나열(읽기 전용)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "단일 게시물 검색(읽기 전용)"
|
msgstr "단일 게시물 검색(읽기 전용)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -34,67 +34,71 @@ msgid ""
|
||||||
"both simultaneously. It also supports automatic slug generation based on the"
|
"both simultaneously. It also supports automatic slug generation based on the"
|
||||||
" title."
|
" title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"블로그 글 모델을 나타냅니다. Post 클래스는 블로그 글의 구조와 동작을 정의합니"
|
"블로그 글 모델을 나타냅니다. Post 클래스는 블로그 글의 구조와 동작을 정의합니다. 여기에는 작성자, 제목, 콘텐츠, 선택적 파일 "
|
||||||
"다. 여기에는 작성자, 제목, 콘텐츠, 선택적 파일 첨부, 슬러그 및 관련 태그에 대"
|
"첨부, 슬러그 및 관련 태그에 대한 속성이 포함됩니다. 이 클래스는 콘텐츠 또는 파일 첨부 중 하나만 요구하고 둘 다 동시에 요구하지 "
|
||||||
"한 속성이 포함됩니다. 이 클래스는 콘텐츠 또는 파일 첨부 중 하나만 요구하고 "
|
"않는 등의 제약 조건을 적용합니다. 또한 제목에 따른 자동 슬러그 생성도 지원합니다."
|
||||||
"둘 다 동시에 요구하지 않는 등의 제약 조건을 적용합니다. 또한 제목에 따른 자"
|
|
||||||
"동 슬러그 생성도 지원합니다."
|
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "게시물 제목"
|
msgstr "게시물 제목"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "제목"
|
msgstr "제목"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "콘텐츠"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "게시물 내용"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "는 정적 페이지입니다."
|
msgstr "는 정적 페이지입니다."
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr "정적 URL(예: `/help/delivery`)이 있는 페이지의 게시물인가요?"
|
msgstr "정적 URL(예: `/help/delivery`)이 있는 페이지의 게시물인가요?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "게시물"
|
msgstr "게시물"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "게시물"
|
msgstr "게시물"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr "마크다운 파일은 지원되지 않습니다 예 - 대신 마크다운 콘텐츠를 사용하세요!"
|
||||||
"마크다운 파일은 지원되지 않습니다 예 - 대신 마크다운 콘텐츠를 사용하세요!"
|
|
||||||
|
#: engine/blog/models.py:77
|
||||||
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
|
msgstr "마크다운 파일 또는 마크다운 콘텐츠를 제공해야 합니다 - 상호 배타적"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:110
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr "마크다운 파일 또는 마크다운 콘텐츠가 제공되어야 합니다."
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "게시물 태그의 내부 태그 식별자"
|
msgstr "게시물 태그의 내부 태그 식별자"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "태그 이름"
|
msgstr "태그 이름"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "게시물 태그의 사용자 친화적인 이름"
|
msgstr "게시물 태그의 사용자 친화적인 이름"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "태그 표시 이름"
|
msgstr "태그 표시 이름"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "게시물 태그"
|
msgstr "게시물 태그"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "게시물 태그"
|
msgstr "게시물 태그"
|
||||||
|
|
||||||
|
|
@ -107,8 +111,6 @@ msgid ""
|
||||||
"defined permissions. The view set also includes an additional 'retrieve' "
|
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||||
"permission configuration."
|
"permission configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"읽기 전용 모델 보기 집합에서 Post 엔티티를 관리하고 검색하기 위한 작업을 캡슐"
|
"읽기 전용 모델 보기 집합에서 Post 엔티티를 관리하고 검색하기 위한 작업을 캡슐화합니다. 이 클래스는 활성 상태인 Post 개체를 "
|
||||||
"화합니다. 이 클래스는 활성 상태인 Post 개체를 처리하도록 맞춤화되어 있으며 정"
|
"처리하도록 맞춤화되어 있으며 정의된 필터를 기반으로 필터링을 허용합니다. 이 클래스는 장고의 백엔드 필터링 시스템과 통합되며 정의된 "
|
||||||
"의된 필터를 기반으로 필터링을 허용합니다. 이 클래스는 장고의 백엔드 필터링 시"
|
"권한에 따라 작업이 이루어지도록 합니다. 보기 세트에는 추가 '검색' 권한 구성도 포함되어 있습니다."
|
||||||
"스템과 통합되며 정의된 권한에 따라 작업이 이루어지도록 합니다. 보기 세트에는 "
|
|
||||||
"추가 '검색' 권한 구성도 포함되어 있습니다."
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Alle berichten weergeven (alleen-lezen)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Een enkel bericht ophalen (alleen-lezen)"
|
msgstr "Een enkel bericht ophalen (alleen-lezen)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,66 +41,73 @@ msgstr ""
|
||||||
"maar niet beide tegelijk. Het ondersteunt ook het automatisch genereren van "
|
"maar niet beide tegelijk. Het ondersteunt ook het automatisch genereren van "
|
||||||
"slugs op basis van de titel."
|
"slugs op basis van de titel."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titel van de post"
|
msgstr "Titel van de post"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "inhoud"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "berichtinhoud"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "is statische pagina"
|
msgstr "is statische pagina"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Is dit een bericht voor een pagina met een statische URL (bijv. `/help/"
|
"Is dit een bericht voor een pagina met een statische URL (bijv. "
|
||||||
"delivery`)?"
|
"`/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Plaats"
|
msgstr "Plaats"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Berichten"
|
msgstr "Berichten"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Markdown-bestanden worden niet ondersteund - gebruik in plaats daarvan "
|
"Markdown-bestanden worden niet ondersteund - gebruik in plaats daarvan "
|
||||||
"markdown-inhoud!"
|
"markdown-inhoud!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds"
|
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds"
|
||||||
" exclusief"
|
" exclusief"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "interne tagidentifier voor de posttag"
|
msgstr "interne tagidentifier voor de posttag"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tag naam"
|
msgstr "Tag naam"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Gebruiksvriendelijke naam voor de posttag"
|
msgstr "Gebruiksvriendelijke naam voor de posttag"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Tag weergavenaam"
|
msgstr "Tag weergavenaam"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Post tags"
|
msgstr "Post tags"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Liste over alle innlegg (skrivebeskyttet)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Hent et enkelt innlegg (skrivebeskyttet)"
|
msgstr "Hent et enkelt innlegg (skrivebeskyttet)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,62 +41,69 @@ msgstr ""
|
||||||
"må være med, men ikke begge deler samtidig. Den støtter også automatisk "
|
"må være med, men ikke begge deler samtidig. Den støtter også automatisk "
|
||||||
"generering av slug basert på tittelen."
|
"generering av slug basert på tittelen."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Innleggets tittel"
|
msgstr "Innleggets tittel"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Title"
|
msgstr "Title"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "innhold"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "innleggsinnhold"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "er statisk side"
|
msgstr "er statisk side"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"er dette et innlegg for en side med statisk URL (f.eks. `/help/delivery`)?"
|
"er dette et innlegg for en side med statisk URL (f.eks. `/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Innlegg"
|
msgstr "Innlegg"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "Markdown-filer støttes ikke - bruk markdown-innhold i stedet!"
|
msgstr "filopplasting støttes ikke ennå – bruk innhold i stedet"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"en markdown-fil eller markdown-innhold må oppgis - gjensidig utelukkende"
|
"en markdown-fil eller markdown-innhold må oppgis - gjensidig utelukkende"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "intern tagg-identifikator for innleggstaggen"
|
msgstr "intern tagg-identifikator for innleggstaggen"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tagg navn"
|
msgstr "Tagg navn"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Brukervennlig navn for innleggstaggen"
|
msgstr "Brukervennlig navn for innleggstaggen"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Visningsnavn for taggen"
|
msgstr "Visningsnavn for taggen"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tagger for innlegg"
|
msgstr "Tagger for innlegg"
|
||||||
|
|
||||||
|
|
@ -114,5 +121,5 @@ msgstr ""
|
||||||
"håndtere Post-objekter som er aktive, og tillater filtrering basert på "
|
"håndtere Post-objekter som er aktive, og tillater filtrering basert på "
|
||||||
"definerte filtre. Den integreres med Djangos backend-filtreringssystem og "
|
"definerte filtre. Den integreres med Djangos backend-filtreringssystem og "
|
||||||
"sørger for at operasjonene er i tråd med de definerte tillatelsene. "
|
"sørger for at operasjonene er i tråd med de definerte tillatelsene. "
|
||||||
"Visningssettet inkluderer også en ekstra konfigurasjon for \"hent\"-"
|
"Visningssettet inkluderer også en ekstra konfigurasjon for "
|
||||||
"tillatelse."
|
"\"hent\"-tillatelse."
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Lista wszystkich postów (tylko do odczytu)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Pobieranie pojedynczego wpisu (tylko do odczytu)"
|
msgstr "Pobieranie pojedynczego wpisu (tylko do odczytu)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,64 +41,72 @@ msgstr ""
|
||||||
"nie obu jednocześnie. Obsługuje również automatyczne generowanie slug na "
|
"nie obu jednocześnie. Obsługuje również automatyczne generowanie slug na "
|
||||||
"podstawie tytułu."
|
"podstawie tytułu."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Tytuł postu"
|
msgstr "Tytuł postu"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Tytuł"
|
msgstr "Tytuł"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "treść"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "treść postu"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "jest stroną statyczną"
|
msgstr "jest stroną statyczną"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
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:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Posty"
|
msgstr "Posty"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Pliki Markdown nie są obsługiwane - zamiast tego użyj zawartości Markdown!"
|
"Pliki Markdown nie są obsługiwane - zamiast tego użyj zawartości Markdown!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"należy dostarczyć plik markdown lub zawartość markdown - wzajemnie się "
|
"należy dostarczyć plik markdown lub zawartość markdown - wzajemnie się "
|
||||||
"wykluczające"
|
"wykluczające"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "wewnętrzny identyfikator tagu posta"
|
msgstr "wewnętrzny identyfikator tagu posta"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nazwa tagu"
|
msgstr "Nazwa tagu"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
|
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Wyświetlana nazwa znacznika"
|
msgstr "Wyświetlana nazwa znacznika"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag posta"
|
msgstr "Tag posta"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tagi postów"
|
msgstr "Tagi postów"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Listar todas as postagens (somente leitura)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Recuperar um único post (somente leitura)"
|
msgstr "Recuperar um único post (somente leitura)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,64 +41,72 @@ msgstr ""
|
||||||
"simultaneamente. Ela também oferece suporte à geração automática de slug com"
|
"simultaneamente. Ela também oferece suporte à geração automática de slug com"
|
||||||
" base no título."
|
" base no título."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Título da postagem"
|
msgstr "Título da postagem"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Título"
|
msgstr "Título"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "conteúdo"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "conteúdo da publicação"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "é uma página estática"
|
msgstr "é uma página estática"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Essa é uma postagem para uma página com URL estático (por exemplo, `/help/"
|
"Essa é uma postagem para uma página com URL estático (por exemplo, "
|
||||||
"delivery`)?"
|
"`/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Postar"
|
msgstr "Postar"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Publicações"
|
msgstr "Publicações"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
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:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"um arquivo ou conteúdo de markdown deve ser fornecido - mutuamente exclusivo"
|
"um arquivo ou conteúdo de markdown deve ser fornecido - mutuamente exclusivo"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identificador de tag interno para a tag de postagem"
|
msgstr "identificador de tag interno para a tag de postagem"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nome da etiqueta"
|
msgstr "Nome da etiqueta"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nome de fácil utilização para a tag de postagem"
|
msgstr "Nome de fácil utilização para a tag de postagem"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nome de exibição da tag"
|
msgstr "Nome de exibição da tag"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Etiqueta de postagem"
|
msgstr "Etiqueta de postagem"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tags de postagem"
|
msgstr "Tags de postagem"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Listează toate postările (doar pentru citire)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Recuperează o singură postare (read-only)"
|
msgstr "Recuperează o singură postare (read-only)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,65 +41,73 @@ msgstr ""
|
||||||
"fișier atașat, dar nu ambele simultan. De asemenea, acceptă generarea "
|
"fișier atașat, dar nu ambele simultan. De asemenea, acceptă generarea "
|
||||||
"automată a slug-ului pe baza titlului."
|
"automată a slug-ului pe baza titlului."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titlul postului"
|
msgstr "Titlul postului"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titlul"
|
msgstr "Titlul"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "conținut"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "conținutul postării"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "este o pagină statică"
|
msgstr "este o pagină statică"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"este aceasta o postare pentru o pagină cu URL static (de exemplu `/help/"
|
"este aceasta o postare pentru o pagină cu URL static (de exemplu "
|
||||||
"delivery`)?"
|
"`/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Mesaje"
|
msgstr "Mesaje"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
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:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"trebuie furnizat un fișier markdown sau conținut markdown - se exclud "
|
"trebuie furnizat un fișier markdown sau conținut markdown - se exclud "
|
||||||
"reciproc"
|
"reciproc"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identificator intern de etichetă pentru eticheta postului"
|
msgstr "identificator intern de etichetă pentru eticheta postului"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nume etichetă"
|
msgstr "Nume etichetă"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nume ușor de utilizat pentru eticheta postului"
|
msgstr "Nume ușor de utilizat pentru eticheta postului"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nume afișare etichetă"
|
msgstr "Nume afișare etichetă"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Etichetă post"
|
msgstr "Etichetă post"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Etichete poștale"
|
msgstr "Etichete poștale"
|
||||||
|
|
||||||
|
|
@ -112,8 +120,8 @@ msgid ""
|
||||||
"defined permissions. The view set also includes an additional 'retrieve' "
|
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||||
"permission configuration."
|
"permission configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Încapsulează operațiunile de gestionare și extragere a entităților Post într-"
|
"Încapsulează operațiunile de gestionare și extragere a entităților Post "
|
||||||
"un set de vizualizări de model numai pentru citire. Această clasă este "
|
"î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 "
|
"adaptată pentru a gestiona obiectele Post care sunt active și permite "
|
||||||
"filtrarea pe baza filtrelor definite. Se integrează cu sistemul de filtrare "
|
"filtrarea pe baza filtrelor definite. Se integrează cu sistemul de filtrare "
|
||||||
"din backend al Django și asigură alinierea operațiunilor cu permisiunile "
|
"din backend al Django și asigură alinierea operațiunilor cu permisiunile "
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Список всех сообщений (только для чтени
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Получение одного сообщения (только для чтения)"
|
msgstr "Получение одного сообщения (только для чтения)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,65 +41,72 @@ msgstr ""
|
||||||
"вложение файла, но не то и другое одновременно. Он также поддерживает "
|
"вложение файла, но не то и другое одновременно. Он также поддерживает "
|
||||||
"автоматическую генерацию slug на основе заголовка."
|
"автоматическую генерацию slug на основе заголовка."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Заголовок сообщения"
|
msgstr "Заголовок сообщения"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Название"
|
msgstr "Название"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "содержание"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "содержание публикации"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "это статическая страница"
|
msgstr "это статическая страница"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Это сообщение для страницы со статическим URL (например, `/help/delivery`)?"
|
"Это сообщение для страницы со статическим URL (например, `/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Пост"
|
msgstr "Пост"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Посты"
|
msgstr "Посты"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
|
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
|
||||||
"содержимое в формате Markdown!"
|
"содержимое в формате Markdown!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"необходимо предоставить файл разметки или содержимое разметки - "
|
"необходимо предоставить файл разметки или содержимое разметки - "
|
||||||
"взаимоисключающие варианты"
|
"взаимоисключающие варианты"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "внутренний идентификатор тега для тега post"
|
msgstr "внутренний идентификатор тега для тега post"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Название тега"
|
msgstr "Название тега"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Удобное для пользователя название тега поста"
|
msgstr "Удобное для пользователя название тега поста"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Отображаемое имя тега"
|
msgstr "Отображаемое имя тега"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Тэг поста"
|
msgstr "Тэг поста"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Тэги постов"
|
msgstr "Тэги постов"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Lista alla inlägg (skrivskyddad)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Hämta ett enskilt inlägg (skrivskyddat)"
|
msgstr "Hämta ett enskilt inlägg (skrivskyddat)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,63 +41,70 @@ msgstr ""
|
||||||
"filbilaga krävs, men inte båda samtidigt. Den stöder också automatisk "
|
"filbilaga krävs, men inte båda samtidigt. Den stöder också automatisk "
|
||||||
"sluggenerering baserat på titeln."
|
"sluggenerering baserat på titeln."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Inläggets titel"
|
msgstr "Inläggets titel"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "innehåll"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "inläggsinnehåll"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "är statisk sida"
|
msgstr "är statisk sida"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"är detta ett inlägg för en sida med statisk URL (t.ex. `/help/delivery`)?"
|
"är detta ett inlägg för en sida med statisk URL (t.ex. `/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Inlägg"
|
msgstr "Inlägg"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "Markdown-filer stöds inte - använd markdown-innehåll istället!"
|
msgstr "filuppladdningar stöds ännu inte – använd innehåll istället"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"en markdown-fil eller markdown-innehåll måste tillhandahållas - ömsesidigt "
|
"en markdown-fil eller markdown-innehåll måste tillhandahållas - ömsesidigt "
|
||||||
"uteslutande"
|
"uteslutande"
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "intern taggidentifierare för inläggstaggen"
|
msgstr "intern taggidentifierare för inläggstaggen"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tagg namn"
|
msgstr "Tagg namn"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Användarvänligt namn för inläggstaggen"
|
msgstr "Användarvänligt namn för inläggstaggen"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Taggens visningsnamn"
|
msgstr "Taggens visningsnamn"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tagg"
|
msgstr "Post tagg"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Taggar för inlägg"
|
msgstr "Taggar för inlägg"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "แสดงรายการโพสต์ทั้งหมด (อ
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "ดึงโพสต์เดียว (อ่านอย่างเดียว)"
|
msgstr "ดึงโพสต์เดียว (อ่านอย่างเดียว)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -34,65 +34,77 @@ msgid ""
|
||||||
"both simultaneously. It also supports automatic slug generation based on the"
|
"both simultaneously. It also supports automatic slug generation based on the"
|
||||||
" title."
|
" title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"แทนแบบจำลองของโพสต์ในบล็อก คลาส Post กำหนดโครงสร้างและพฤติกรรมของโพสต์ในบล็อก "
|
"แทนแบบจำลองของโพสต์ในบล็อก คลาส Post "
|
||||||
"ประกอบด้วยแอตทริบิวต์สำหรับผู้เขียน, ชื่อเรื่อง, เนื้อหา, ไฟล์แนบ (ไม่บังคับ), slug "
|
"กำหนดโครงสร้างและพฤติกรรมของโพสต์ในบล็อก "
|
||||||
"และแท็กที่เกี่ยวข้อง คลาสนี้บังคับใช้ข้อจำกัด เช่น ต้องมีเนื้อหาหรือไฟล์แนบอย่างใดอย่างหนึ่ง "
|
"ประกอบด้วยแอตทริบิวต์สำหรับผู้เขียน, ชื่อเรื่อง, เนื้อหา, ไฟล์แนบ "
|
||||||
"แต่ไม่สามารถมีทั้งสองอย่างพร้อมกันได้ นอกจากนี้ยังรองรับการสร้าง slug โดยอัตโนมัติจากชื่อเรื่อง"
|
"(ไม่บังคับ), slug และแท็กที่เกี่ยวข้อง คลาสนี้บังคับใช้ข้อจำกัด เช่น "
|
||||||
|
"ต้องมีเนื้อหาหรือไฟล์แนบอย่างใดอย่างหนึ่ง "
|
||||||
|
"แต่ไม่สามารถมีทั้งสองอย่างพร้อมกันได้ นอกจากนี้ยังรองรับการสร้าง slug "
|
||||||
|
"โดยอัตโนมัติจากชื่อเรื่อง"
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "ชื่อโพสต์"
|
msgstr "ชื่อโพสต์"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "ชื่อเรื่อง"
|
msgstr "ชื่อเรื่อง"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "เนื้อหา"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "โพสต์เนื้อหา"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "เป็นหน้าคงที่"
|
msgstr "เป็นหน้าคงที่"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr "นี่คือโพสต์สำหรับหน้าที่มี URL แบบคงที่ (เช่น `/help/delivery`)?"
|
msgstr "นี่คือโพสต์สำหรับหน้าที่มี URL แบบคงที่ (เช่น `/help/delivery`)?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "โพสต์"
|
msgstr "โพสต์"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "โพสต์"
|
msgstr "โพสต์"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "ไฟล์มาร์กดาวน์ยังไม่รองรับในตอนนี้ - กรุณาใช้เนื้อหาแบบมาร์กดาวน์แทน!"
|
msgstr "ยังไม่รองรับการอัปโหลดไฟล์ - กรุณาใช้เนื้อหาแทน"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:77
|
||||||
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
|
msgstr ""
|
||||||
|
"ไฟล์มาร์กดาวน์หรือเนื้อหาแบบมาร์กดาวน์ต้องได้รับการจัดเตรียมไว้ - "
|
||||||
|
"ไม่สามารถใช้ร่วมกันได้"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:110
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr "ไฟล์มาร์กดาวน์หรือเนื้อหาแบบมาร์กดาวน์ต้องได้รับการจัดเตรียมไว้ - ไม่สามารถใช้ร่วมกันได้"
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "ตัวระบุแท็กภายในสำหรับแท็กโพสต์"
|
msgstr "ตัวระบุแท็กภายในสำหรับแท็กโพสต์"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "ชื่อวัน"
|
msgstr "ชื่อวัน"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "ชื่อที่ใช้งานได้ง่ายสำหรับแท็กโพสต์"
|
msgstr "ชื่อที่ใช้งานได้ง่ายสำหรับแท็กโพสต์"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "แสดงชื่อแท็ก"
|
msgstr "แสดงชื่อแท็ก"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "โพสต์แท็ก"
|
msgstr "โพสต์แท็ก"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "ป้ายกำกับโพสต์"
|
msgstr "ป้ายกำกับโพสต์"
|
||||||
|
|
||||||
|
|
@ -106,7 +118,8 @@ msgid ""
|
||||||
"permission configuration."
|
"permission configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"รวบรวมการดำเนินการสำหรับการจัดการและดึงข้อมูลเอนทิตีโพสต์ในชุดมุมมองแบบอ่านอย่างเดียว"
|
"รวบรวมการดำเนินการสำหรับการจัดการและดึงข้อมูลเอนทิตีโพสต์ในชุดมุมมองแบบอ่านอย่างเดียว"
|
||||||
|
" "
|
||||||
"คลาสนี้ถูกออกแบบมาเพื่อจัดการกับวัตถุโพสต์ที่ใช้งานอยู่และอนุญาตให้มีการกรองตามตัวกรองที่กำหนดไว้"
|
"คลาสนี้ถูกออกแบบมาเพื่อจัดการกับวัตถุโพสต์ที่ใช้งานอยู่และอนุญาตให้มีการกรองตามตัวกรองที่กำหนดไว้"
|
||||||
" มันผสานรวมกับระบบการกรองแบ็กเอนด์ของ Django "
|
" มันผสานรวมกับระบบการกรองแบ็กเอนด์ของ Django "
|
||||||
"และทำให้แน่ใจว่าการดำเนินการสอดคล้องกับสิทธิ์ที่กำหนดไว้ ชุดมุมมองยังรวมถึงการกำหนดค่าสิทธิ์ "
|
"และทำให้แน่ใจว่าการดำเนินการสอดคล้องกับสิทธิ์ที่กำหนดไว้ "
|
||||||
"'ดึงข้อมูล' เพิ่มเติมด้วย"
|
"ชุดมุมมองยังรวมถึงการกำหนดค่าสิทธิ์ 'ดึงข้อมูล' เพิ่มเติมด้วย"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Tüm gönderileri listele (salt okunur)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Tek bir gönderiyi al (salt okunur)"
|
msgstr "Tek bir gönderiyi al (salt okunur)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -41,65 +41,73 @@ msgstr ""
|
||||||
"kısıtlamalar uygular. Ayrıca başlığa dayalı otomatik slug oluşturmayı da "
|
"kısıtlamalar uygular. Ayrıca başlığa dayalı otomatik slug oluşturmayı da "
|
||||||
"destekler."
|
"destekler."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Gönderinin başlığı"
|
msgstr "Gönderinin başlığı"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Başlık"
|
msgstr "Başlık"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "içerik"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "yazı içeriği"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "statik sayfadır"
|
msgstr "statik sayfadır"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Bu, statik URL'ye sahip bir sayfa (örneğin `/help/delivery`) için bir "
|
"Bu, statik URL'ye sahip bir sayfa (örneğin `/help/delivery`) için bir "
|
||||||
"gönderi mi?"
|
"gönderi mi?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Posta"
|
msgstr "Posta"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Mesajlar"
|
msgstr "Mesajlar"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Markdown dosyaları desteklenmiyor yer - bunun yerine markdown içeriği "
|
"Markdown dosyaları desteklenmiyor yer - bunun yerine markdown içeriği "
|
||||||
"kullanın!"
|
"kullanın!"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
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:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "gönderi etiketi için dahili etiket tanımlayıcısı"
|
msgstr "gönderi etiketi için dahili etiket tanımlayıcısı"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Etiket adı"
|
msgstr "Etiket adı"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Gönderi etiketi için kullanıcı dostu ad"
|
msgstr "Gönderi etiketi için kullanıcı dostu ad"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Etiket görünen adı"
|
msgstr "Etiket görünen adı"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Mesaj etiketi"
|
msgstr "Mesaj etiketi"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Gönderi etiketleri"
|
msgstr "Gönderi etiketleri"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "Danh sách tất cả các bài đăng (chỉ đọc)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "Lấy một bài đăng duy nhất (chỉ đọc)"
|
msgstr "Lấy một bài đăng duy nhất (chỉ đọc)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -40,65 +40,72 @@ 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 "
|
"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 đề."
|
"cùng lúc. Nó cũng hỗ trợ tạo slug tự động dựa trên tiêu đề."
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Tiêu đề bài đăng"
|
msgstr "Tiêu đề bài đăng"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Tiêu đề"
|
msgstr "Tiêu đề"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "nội dung"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "Nội dung bài đăng"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "là trang tĩnh"
|
msgstr "là trang tĩnh"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Đây có phải là bài đăng cho một trang có URL tĩnh (ví dụ: `/help/delivery`) "
|
"Đây có phải là bài đăng cho một trang có URL tĩnh (ví dụ: `/help/delivery`) "
|
||||||
"không?"
|
"không?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Bài đăng"
|
msgstr "Bài đăng"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Bài đăng"
|
msgstr "Bài đăng"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Tệp Markdown hiện chưa được hỗ trợ - hãy sử dụng nội dung Markdown thay thế!"
|
"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:110
|
#: engine/blog/models.py:77
|
||||||
msgid ""
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Phải cung cấp tệp Markdown hoặc nội dung Markdown - hai tùy chọn này là "
|
"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."
|
"tương phản nhau."
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
#: engine/blog/models.py:110
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "Mã định danh thẻ nội bộ cho thẻ bài viết"
|
msgstr "Mã định danh thẻ nội bộ cho thẻ bài viết"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tên ngày"
|
msgstr "Tên ngày"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
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"
|
msgstr "Tên thân thiện với người dùng cho thẻ bài viết"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Hiển thị tên thẻ"
|
msgstr "Hiển thị tên thẻ"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Thẻ bài viết"
|
msgstr "Thẻ bài viết"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Thẻ bài viết"
|
msgstr "Thẻ bài viết"
|
||||||
|
|
||||||
|
|
@ -115,4 +122,5 @@ msgstr ""
|
||||||
"xem mô hình chỉ đọc. Lớp này được thiết kế để xử lý các đối tượng Post đang "
|
"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"
|
"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ệ 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."
|
" 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 ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2026.1\n"
|
"Project-Id-Version: SCHON 2026.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:38+0300\n"
|
"POT-Creation-Date: 2026-01-26 02:16+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -25,7 +25,7 @@ msgstr "列出所有帖子(只读)"
|
||||||
msgid "retrieve a single post (read-only)"
|
msgid "retrieve a single post (read-only)"
|
||||||
msgstr "检索单个帖子(只读)"
|
msgstr "检索单个帖子(只读)"
|
||||||
|
|
||||||
#: engine/blog/models.py:20
|
#: engine/blog/models.py:19
|
||||||
msgid ""
|
msgid ""
|
||||||
"Represents a blog post model. The Post class defines the structure and "
|
"Represents a blog post model. The Post class defines the structure and "
|
||||||
"behavior of a blog post. It includes attributes for author, title, content, "
|
"behavior of a blog post. It includes attributes for author, title, content, "
|
||||||
|
|
@ -34,64 +34,69 @@ msgid ""
|
||||||
"both simultaneously. It also supports automatic slug generation based on the"
|
"both simultaneously. It also supports automatic slug generation based on the"
|
||||||
" title."
|
" title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"代表博文模型。帖子类定义了博文的结构和行为。它包括作者、标题、内容、可选文件"
|
"代表博文模型。帖子类定义了博文的结构和行为。它包括作者、标题、内容、可选文件附件、标签和相关标记的属性。该类可强制执行一些限制条件,如要求提供内容或文件附件,但不能同时提供这两种内容。它还支持根据标题自动生成标签。"
|
||||||
"附件、标签和相关标记的属性。该类可强制执行一些限制条件,如要求提供内容或文件"
|
|
||||||
"附件,但不能同时提供这两种内容。它还支持根据标题自动生成标签。"
|
|
||||||
|
|
||||||
#: engine/blog/models.py:41
|
#: engine/blog/models.py:40
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "帖子标题"
|
msgstr "帖子标题"
|
||||||
|
|
||||||
#: engine/blog/models.py:42
|
#: engine/blog/models.py:41
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "标题"
|
msgstr "标题"
|
||||||
|
|
||||||
#: engine/blog/models.py:89
|
#: engine/blog/models.py:44
|
||||||
|
msgid "content"
|
||||||
|
msgstr "内容"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:45
|
||||||
|
msgid "post content"
|
||||||
|
msgstr "发布内容"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:57
|
||||||
msgid "is static page"
|
msgid "is static page"
|
||||||
msgstr "是静态页面"
|
msgstr "是静态页面"
|
||||||
|
|
||||||
#: engine/blog/models.py:91
|
#: engine/blog/models.py:59
|
||||||
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
msgid "is this a post for a page with static URL (e.g. `/help/delivery`)?"
|
||||||
msgstr "这是静态 URL 页面(如 `/help/delivery`)的帖子吗?"
|
msgstr "这是静态 URL 页面(如 `/help/delivery`)的帖子吗?"
|
||||||
|
|
||||||
#: engine/blog/models.py:99
|
#: engine/blog/models.py:67
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "职位"
|
msgstr "职位"
|
||||||
|
|
||||||
#: engine/blog/models.py:100
|
#: engine/blog/models.py:68
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "职位"
|
msgstr "职位"
|
||||||
|
|
||||||
#: engine/blog/models.py:105
|
#: engine/blog/models.py:73
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "file uploads are not supported yet - use content instead"
|
||||||
msgstr "不支持 Markdown 文件,请使用 Markdown 内容!"
|
msgstr "目前尚不支持文件上传——请改用内容上传功能"
|
||||||
|
|
||||||
|
#: engine/blog/models.py:77
|
||||||
|
msgid "a file or content must be provided - mutually exclusive"
|
||||||
|
msgstr "必须提供一个Markdown文件或Markdown内容——两者互斥"
|
||||||
|
|
||||||
#: engine/blog/models.py:110
|
#: engine/blog/models.py:110
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr "必须提供标记符文件或标记符内容 - 相互排斥"
|
|
||||||
|
|
||||||
#: engine/blog/models.py:144
|
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "职位标签的内部标签标识符"
|
msgstr "职位标签的内部标签标识符"
|
||||||
|
|
||||||
#: engine/blog/models.py:145
|
#: engine/blog/models.py:111
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "标签名称"
|
msgstr "标签名称"
|
||||||
|
|
||||||
#: engine/blog/models.py:149
|
#: engine/blog/models.py:115
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "方便用户使用的帖子标签名称"
|
msgstr "方便用户使用的帖子标签名称"
|
||||||
|
|
||||||
#: engine/blog/models.py:150
|
#: engine/blog/models.py:116
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "标签显示名称"
|
msgstr "标签显示名称"
|
||||||
|
|
||||||
#: engine/blog/models.py:158
|
#: engine/blog/models.py:124
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "职位标签"
|
msgstr "职位标签"
|
||||||
|
|
||||||
#: engine/blog/models.py:159
|
#: engine/blog/models.py:125
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "帖子标签"
|
msgstr "帖子标签"
|
||||||
|
|
||||||
|
|
@ -104,6 +109,5 @@ msgid ""
|
||||||
"defined permissions. The view set also includes an additional 'retrieve' "
|
"defined permissions. The view set also includes an additional 'retrieve' "
|
||||||
"permission configuration."
|
"permission configuration."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"该类封装了在只读模型视图集中管理和检索 \"帖子 \"实体的操作。该类专门用于处理"
|
"该类封装了在只读模型视图集中管理和检索 \"帖子 \"实体的操作。该类专门用于处理活动的 \"帖子 \"对象,并允许根据定义的过滤器进行过滤。它与 "
|
||||||
"活动的 \"帖子 \"对象,并允许根据定义的过滤器进行过滤。它与 Django 的后台过滤"
|
"Django 的后台过滤系统集成,确保操作与定义的权限一致。视图集还包括额外的 \"检索 \"权限配置。"
|
||||||
"系统集成,确保操作与定义的权限一致。视图集还包括额外的 \"检索 \"权限配置。"
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
# 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"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -6,11 +6,10 @@ from django.db.models import (
|
||||||
FileField,
|
FileField,
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
ManyToManyField,
|
ManyToManyField,
|
||||||
|
TextField,
|
||||||
)
|
)
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_extensions.db.fields import AutoSlugField
|
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.abstract import NiceModel
|
||||||
|
|
||||||
|
|
@ -41,40 +40,9 @@ class Post(NiceModel):
|
||||||
help_text=_("post title"),
|
help_text=_("post title"),
|
||||||
verbose_name=_("title"),
|
verbose_name=_("title"),
|
||||||
)
|
)
|
||||||
content: MarkdownField = MarkdownField(
|
content = TextField(
|
||||||
"content",
|
verbose_name=_("content"),
|
||||||
extensions=[
|
help_text=_("post content"),
|
||||||
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,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
|
|
@ -102,13 +70,11 @@ class Post(NiceModel):
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if self.file:
|
if self.file:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
_("markdown files are not supported yet - use markdown content instead")
|
_("file uploads are not supported yet - use content instead")
|
||||||
)
|
)
|
||||||
if not any([self.file, self.content]) or all([self.file, self.content]):
|
if not any([self.file, self.content]) or all([self.file, self.content]):
|
||||||
raise ValueError(
|
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(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,4 @@ class PostSerializer(ModelSerializer):
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
|
||||||
def get_content(self, obj: Post) -> str:
|
def get_content(self, obj: Post) -> str:
|
||||||
return obj.content.html.replace("\n", "<br/>")
|
return obj.content or ""
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from engine.blog.docs.drf.viewsets import POST_SCHEMA
|
||||||
from engine.blog.filters import PostFilter
|
from engine.blog.filters import PostFilter
|
||||||
from engine.blog.models import Post
|
from engine.blog.models import Post
|
||||||
from engine.blog.serializers import PostSerializer
|
from engine.blog.serializers import PostSerializer
|
||||||
from engine.core.permissions import EvibesPermission
|
from engine.core.permissions import SchonPermission
|
||||||
|
|
||||||
|
|
||||||
@extend_schema_view(**POST_SCHEMA)
|
@extend_schema_view(**POST_SCHEMA)
|
||||||
|
|
@ -20,7 +20,7 @@ class PostViewSet(ReadOnlyModelViewSet):
|
||||||
)
|
)
|
||||||
|
|
||||||
serializer_class = PostSerializer
|
serializer_class = PostSerializer
|
||||||
permission_classes = (EvibesPermission,)
|
permission_classes = (SchonPermission,)
|
||||||
queryset = Post.objects.filter(is_active=True)
|
queryset = Post.objects.filter(is_active=True)
|
||||||
filter_backends = [DjangoFilterBackend]
|
filter_backends = [DjangoFilterBackend]
|
||||||
filterset_class = PostFilter
|
filterset_class = PostFilter
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ class ActivationActionsMixin:
|
||||||
]
|
]
|
||||||
|
|
||||||
@action(
|
@action(
|
||||||
description=_("activate selected %(verbose_name_plural)s").lower(),
|
description=_("Activate selected %(verbose_name_plural)s"), # ty:ignore[invalid-argument-type]
|
||||||
permissions=["change"],
|
permissions=["change"],
|
||||||
)
|
)
|
||||||
def activate_selected(self, request: HttpRequest, queryset: QuerySet[Any]) -> None:
|
def activate_selected(self, request: HttpRequest, queryset: QuerySet[Any]) -> None:
|
||||||
|
|
@ -163,7 +163,7 @@ class ActivationActionsMixin:
|
||||||
queryset.update(is_active=True)
|
queryset.update(is_active=True)
|
||||||
self.message_user(
|
self.message_user(
|
||||||
request=request,
|
request=request,
|
||||||
message=_("selected items have been activated.").lower(),
|
message=_("selected items have been activated.").lower().title(),
|
||||||
level=messages.SUCCESS,
|
level=messages.SUCCESS,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ class ActivationActionsMixin:
|
||||||
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||||
|
|
||||||
@action(
|
@action(
|
||||||
description=_("deactivate selected %(verbose_name_plural)s").lower(),
|
description=_("Deactivate selected %(verbose_name_plural)s"), # ty:ignore[invalid-argument-type]
|
||||||
permissions=["change"],
|
permissions=["change"],
|
||||||
)
|
)
|
||||||
def deactivate_selected(
|
def deactivate_selected(
|
||||||
|
|
@ -181,7 +181,7 @@ class ActivationActionsMixin:
|
||||||
queryset.update(is_active=False)
|
queryset.update(is_active=False)
|
||||||
self.message_user(
|
self.message_user(
|
||||||
request=request,
|
request=request,
|
||||||
message=_("selected items have been deactivated.").lower(),
|
message=_("selected items have been deactivated.").lower().title(),
|
||||||
level=messages.SUCCESS,
|
level=messages.SUCCESS,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -454,14 +454,19 @@ class ProductAdmin(
|
||||||
):
|
):
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Product
|
model = Product
|
||||||
|
actions = ActivationActionsMixin.actions + [
|
||||||
|
"export_to_marketplaces",
|
||||||
|
"ban_from_marketplaces",
|
||||||
|
]
|
||||||
list_display = (
|
list_display = (
|
||||||
"sku",
|
"sku",
|
||||||
"name",
|
"name",
|
||||||
"is_active",
|
"is_active",
|
||||||
|
"export_to_marketplaces",
|
||||||
|
"has_images",
|
||||||
"category",
|
"category",
|
||||||
"brand",
|
"brand",
|
||||||
"price",
|
"price",
|
||||||
"rating",
|
|
||||||
"modified",
|
"modified",
|
||||||
)
|
)
|
||||||
list_filter = (
|
list_filter = (
|
||||||
|
|
@ -509,6 +514,7 @@ class ProductAdmin(
|
||||||
"name",
|
"name",
|
||||||
"partnumber",
|
"partnumber",
|
||||||
"is_digital",
|
"is_digital",
|
||||||
|
"export_to_marketplaces",
|
||||||
]
|
]
|
||||||
relation_fields = [
|
relation_fields = [
|
||||||
"category",
|
"category",
|
||||||
|
|
@ -519,6 +525,56 @@ class ProductAdmin(
|
||||||
"is_updatable",
|
"is_updatable",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
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):
|
def get_queryset(self, request):
|
||||||
return (
|
return (
|
||||||
super()
|
super()
|
||||||
|
|
@ -1090,7 +1146,7 @@ class ConstanceConfig:
|
||||||
site.unregister([Config]) # ty:ignore[invalid-argument-type]
|
site.unregister([Config]) # ty:ignore[invalid-argument-type]
|
||||||
site.register([ConstanceConfig], BaseConstanceAdmin) # ty:ignore[invalid-argument-type]
|
site.register([ConstanceConfig], BaseConstanceAdmin) # ty:ignore[invalid-argument-type]
|
||||||
site.site_title = settings.PROJECT_NAME
|
site.site_title = settings.PROJECT_NAME
|
||||||
site.site_header = "eVibes"
|
site.site_header = "Schon"
|
||||||
site.index_title = settings.PROJECT_NAME
|
site.index_title = settings.PROJECT_NAME
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
|
@ -1,25 +0,0 @@
|
||||||
<?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>
|
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB |
21
engine/core/feeds/__init__.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
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",
|
||||||
|
]
|
||||||
241
engine/core/feeds/amazon_seller.py
Normal file
|
|
@ -0,0 +1,241 @@
|
||||||
|
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"]
|
||||||
173
engine/core/feeds/base.py
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Any
|
||||||
|
from xml.dom import minidom
|
||||||
|
from xml.etree.ElementTree import Element, tostring
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db.models import QuerySet
|
||||||
|
|
||||||
|
from engine.core.models import Product
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseFeedGenerator(ABC):
|
||||||
|
"""
|
||||||
|
Base class for marketplace feed generators.
|
||||||
|
|
||||||
|
Each marketplace feed generator should inherit from this class and implement
|
||||||
|
the required methods for generating feed data in the appropriate format.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name: str = "base"
|
||||||
|
supported_formats: tuple[str, ...] = ("xml", "json", "yaml")
|
||||||
|
default_format: str = "xml"
|
||||||
|
|
||||||
|
def __init__(self, locale: str = "en-gb"):
|
||||||
|
self.locale = locale
|
||||||
|
self.generated_at = datetime.now()
|
||||||
|
|
||||||
|
def get_products(self) -> QuerySet[Product]:
|
||||||
|
"""Get products that should be exported to marketplaces."""
|
||||||
|
return (
|
||||||
|
Product.objects.filter(
|
||||||
|
is_active=True,
|
||||||
|
export_to_marketplaces=True,
|
||||||
|
)
|
||||||
|
.select_related(
|
||||||
|
"category",
|
||||||
|
"brand",
|
||||||
|
)
|
||||||
|
.prefetch_related(
|
||||||
|
"images",
|
||||||
|
"stocks",
|
||||||
|
"attributes__attribute",
|
||||||
|
"tags",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_product_url(self, product: Product) -> str:
|
||||||
|
"""Generate the frontend URL for a product."""
|
||||||
|
return (
|
||||||
|
f"https://{settings.STOREFRONT_DOMAIN}/{self.locale}/product/{product.slug}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_product_image_url(self, product: Product) -> str:
|
||||||
|
"""Get the primary image URL for a product."""
|
||||||
|
image = product.images.order_by("priority").first()
|
||||||
|
if image:
|
||||||
|
return image.image_url
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_product_images(self, product: Product) -> list[str]:
|
||||||
|
"""Get all image URLs for a product."""
|
||||||
|
return [
|
||||||
|
img.image_url
|
||||||
|
for img in product.images.order_by("priority")
|
||||||
|
if img.image_url
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_availability(self, product: Product) -> str:
|
||||||
|
"""Get availability status for a product."""
|
||||||
|
return "in stock" if product.quantity > 0 else "out of stock"
|
||||||
|
|
||||||
|
def get_currency(self) -> str:
|
||||||
|
"""Get the currency code."""
|
||||||
|
return settings.CURRENCY_CODE
|
||||||
|
|
||||||
|
def get_output_path(self, format_type: str) -> str:
|
||||||
|
"""Get the output file path for the feed."""
|
||||||
|
feeds_dir = os.path.join(settings.MEDIA_ROOT, "feeds")
|
||||||
|
os.makedirs(feeds_dir, exist_ok=True)
|
||||||
|
|
||||||
|
extension = format_type if format_type != "yaml" else "yml"
|
||||||
|
return os.path.join(feeds_dir, f"{self.name}.{extension}")
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def generate_feed_data(self, products: QuerySet[Product]) -> Any:
|
||||||
|
"""
|
||||||
|
Generate the feed data structure.
|
||||||
|
|
||||||
|
This method should be implemented by each marketplace-specific generator
|
||||||
|
to create the appropriate data structure for that marketplace.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def to_xml(self, data: Any) -> str:
|
||||||
|
"""Convert feed data to XML format."""
|
||||||
|
raise NotImplementedError(
|
||||||
|
f"{self.__class__.__name__} does not support XML format"
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_json(self, data: Any) -> str:
|
||||||
|
"""Convert feed data to JSON format."""
|
||||||
|
return json.dumps(data, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
def to_yaml(self, data: Any) -> str:
|
||||||
|
"""Convert feed data to YAML format."""
|
||||||
|
return yaml.dump(data, allow_unicode=True, default_flow_style=False)
|
||||||
|
|
||||||
|
def generate(self, format_type: str | None = None) -> str:
|
||||||
|
"""
|
||||||
|
Generate the feed and save it to a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
format_type: The output format (xml, json, yaml). Defaults to the generator's default.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The path to the generated feed file.
|
||||||
|
"""
|
||||||
|
if format_type is None:
|
||||||
|
format_type = self.default_format
|
||||||
|
|
||||||
|
if format_type not in self.supported_formats:
|
||||||
|
raise ValueError(
|
||||||
|
f"Format '{format_type}' is not supported by {self.__class__.__name__}. "
|
||||||
|
f"Supported formats: {self.supported_formats}"
|
||||||
|
)
|
||||||
|
|
||||||
|
products = self.get_products()
|
||||||
|
product_count = products.count()
|
||||||
|
|
||||||
|
if product_count == 0:
|
||||||
|
logger.warning("No products to export for %s feed", self.name)
|
||||||
|
|
||||||
|
logger.info("Generating %s feed with %d products", self.name, product_count)
|
||||||
|
|
||||||
|
feed_data = self.generate_feed_data(products)
|
||||||
|
|
||||||
|
match format_type:
|
||||||
|
case "xml":
|
||||||
|
content = self.to_xml(feed_data)
|
||||||
|
case "json":
|
||||||
|
content = self.to_json(feed_data)
|
||||||
|
case "yaml" | "yml":
|
||||||
|
content = self.to_yaml(feed_data)
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Unknown format: {format_type}")
|
||||||
|
|
||||||
|
output_path = self.get_output_path(format_type)
|
||||||
|
|
||||||
|
with open(output_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
logger.info("Generated %s feed at %s", self.name, output_path)
|
||||||
|
|
||||||
|
return output_path
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def prettify_xml(elem: Element) -> str:
|
||||||
|
"""Return a pretty-printed XML string for the Element (without XML declaration)."""
|
||||||
|
rough_string = tostring(elem, encoding="unicode")
|
||||||
|
reparsed = minidom.parseString(rough_string)
|
||||||
|
pretty = reparsed.toprettyxml(indent=" ")
|
||||||
|
# Strip the XML declaration added by toprettyxml so callers can add their own
|
||||||
|
lines = pretty.split("\n")
|
||||||
|
if lines and lines[0].startswith("<?xml"):
|
||||||
|
lines = lines[1:]
|
||||||
|
return "\n".join(lines).strip()
|
||||||
162
engine/core/feeds/google_merchant.py
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
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 GoogleMerchantFeedGenerator(BaseFeedGenerator):
|
||||||
|
"""
|
||||||
|
Google Merchant Center feed generator.
|
||||||
|
|
||||||
|
Generates product feeds in Atom/RSS format compatible with Google Shopping.
|
||||||
|
Reference: https://support.google.com/merchants/answer/7052112
|
||||||
|
"""
|
||||||
|
|
||||||
|
name: str = "google_merchant"
|
||||||
|
supported_formats: tuple[str, ...] = ("xml", "json")
|
||||||
|
default_format: str = "xml"
|
||||||
|
|
||||||
|
GOOGLE_NS = "http://base.google.com/ns/1.0"
|
||||||
|
|
||||||
|
def generate_feed_data(self, products: QuerySet[Product]) -> list[dict[str, Any]]:
|
||||||
|
"""Generate feed data as a list of product dictionaries."""
|
||||||
|
items = []
|
||||||
|
|
||||||
|
for product in products:
|
||||||
|
item = self._build_product_item(product)
|
||||||
|
if item:
|
||||||
|
items.append(item)
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
|
def _build_product_item(self, product: Product) -> dict[str, Any] | None:
|
||||||
|
"""Build a product item dictionary for the feed."""
|
||||||
|
if not product.price or product.price <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
images = self.get_product_images(product)
|
||||||
|
primary_image = images[0] if images else ""
|
||||||
|
additional_images = images[1:10] if len(images) > 1 else []
|
||||||
|
|
||||||
|
item = {
|
||||||
|
"id": product.sku,
|
||||||
|
"title": product.name[:150],
|
||||||
|
"description": (product.description or "")[:5000],
|
||||||
|
"link": self.get_product_url(product),
|
||||||
|
"image_link": primary_image,
|
||||||
|
"availability": self.get_availability(product),
|
||||||
|
"price": f"{product.price:.2f} {self.get_currency()}",
|
||||||
|
"brand": product.brand.name if product.brand else "",
|
||||||
|
"condition": "new",
|
||||||
|
"product_type": self._get_product_type(product),
|
||||||
|
}
|
||||||
|
|
||||||
|
if additional_images:
|
||||||
|
item["additional_image_link"] = additional_images
|
||||||
|
|
||||||
|
if product.partnumber:
|
||||||
|
item["mpn"] = product.partnumber
|
||||||
|
|
||||||
|
if product.discount_price:
|
||||||
|
sale_price = product.price - product.discount_price
|
||||||
|
if sale_price > 0:
|
||||||
|
item["sale_price"] = f"{sale_price:.2f} {self.get_currency()}"
|
||||||
|
|
||||||
|
gtin = self._get_gtin(product)
|
||||||
|
if gtin:
|
||||||
|
item["gtin"] = gtin
|
||||||
|
else:
|
||||||
|
item["identifier_exists"] = "no"
|
||||||
|
|
||||||
|
return item
|
||||||
|
|
||||||
|
def _get_product_type(self, product: Product) -> str:
|
||||||
|
"""Build the product type hierarchy from category."""
|
||||||
|
if not product.category:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
ancestors = product.category.get_ancestors(include_self=True)
|
||||||
|
return " > ".join([cat.name for cat in ancestors])
|
||||||
|
|
||||||
|
def _get_gtin(self, product: Product) -> str | None:
|
||||||
|
"""Extract GTIN/EAN/UPC from product attributes."""
|
||||||
|
gtin_names = ["gtin", "ean", "upc", "isbn", "barcode"]
|
||||||
|
|
||||||
|
for attr_value in product.attributes.all():
|
||||||
|
if attr_value.attribute.name.lower() in gtin_names:
|
||||||
|
return attr_value.value
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def to_xml(self, data: list[dict[str, Any]]) -> str:
|
||||||
|
"""Convert feed data to Google Merchant XML format."""
|
||||||
|
rss = Element("rss")
|
||||||
|
rss.set("version", "2.0")
|
||||||
|
rss.set("xmlns:g", self.GOOGLE_NS)
|
||||||
|
|
||||||
|
channel = SubElement(rss, "channel")
|
||||||
|
|
||||||
|
title = SubElement(channel, "title")
|
||||||
|
title.text = config.COMPANY_NAME or settings.PROJECT_NAME
|
||||||
|
|
||||||
|
link = SubElement(channel, "link")
|
||||||
|
link.text = f"https://{settings.STOREFRONT_DOMAIN}"
|
||||||
|
|
||||||
|
description = SubElement(channel, "description")
|
||||||
|
description.text = (
|
||||||
|
f"Product feed for {config.COMPANY_NAME or settings.PROJECT_NAME}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for product_data in data:
|
||||||
|
item = SubElement(channel, "item")
|
||||||
|
self._add_product_to_xml(item, product_data)
|
||||||
|
|
||||||
|
return '<?xml version="1.0" encoding="UTF-8"?>\n' + self.prettify_xml(rss)
|
||||||
|
|
||||||
|
def _add_product_to_xml(self, item: Element, product_data: dict[str, Any]) -> None:
|
||||||
|
"""Add a product's data to an XML item element."""
|
||||||
|
simple_fields = [
|
||||||
|
("id", "g:id"),
|
||||||
|
("title", "g:title"),
|
||||||
|
("description", "g:description"),
|
||||||
|
("link", "g:link"),
|
||||||
|
("image_link", "g:image_link"),
|
||||||
|
("availability", "g:availability"),
|
||||||
|
("price", "g:price"),
|
||||||
|
("brand", "g:brand"),
|
||||||
|
("condition", "g:condition"),
|
||||||
|
("product_type", "g:product_type"),
|
||||||
|
("mpn", "g:mpn"),
|
||||||
|
("gtin", "g:gtin"),
|
||||||
|
("sale_price", "g:sale_price"),
|
||||||
|
("identifier_exists", "g:identifier_exists"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for data_key, xml_tag in simple_fields:
|
||||||
|
if data_key in product_data and product_data[data_key]:
|
||||||
|
elem = SubElement(item, xml_tag)
|
||||||
|
elem.text = str(product_data[data_key])
|
||||||
|
|
||||||
|
additional_images = product_data.get("additional_image_link", [])
|
||||||
|
for img_url in additional_images:
|
||||||
|
elem = SubElement(item, "g:additional_image_link")
|
||||||
|
elem.text = img_url
|
||||||
|
|
||||||
|
def to_json(self, data: list[dict[str, Any]]) -> str:
|
||||||
|
"""Convert feed data to JSON format."""
|
||||||
|
feed = {
|
||||||
|
"channel": {
|
||||||
|
"title": config.COMPANY_NAME or settings.PROJECT_NAME,
|
||||||
|
"link": f"https://{settings.STOREFRONT_DOMAIN}",
|
||||||
|
"description": f"Product feed for {config.COMPANY_NAME or settings.PROJECT_NAME}",
|
||||||
|
"generated_at": datetime.now().isoformat(),
|
||||||
|
},
|
||||||
|
"items": data,
|
||||||
|
}
|
||||||
|
return super().to_json(feed)
|
||||||
219
engine/core/feeds/yandex_market.py
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
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 YandexMarketFeedGenerator(BaseFeedGenerator):
|
||||||
|
"""
|
||||||
|
Yandex Market feed generator (YML format).
|
||||||
|
|
||||||
|
Generates product feeds in Yandex Market Language (YML) format.
|
||||||
|
Reference: https://yandex.ru/support/partnermarket/export/yml.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
name: str = "yandex_market"
|
||||||
|
supported_formats: tuple[str, ...] = ("xml", "json", "yaml")
|
||||||
|
default_format: str = "xml"
|
||||||
|
|
||||||
|
def generate_feed_data(self, products: QuerySet[Product]) -> dict[str, Any]:
|
||||||
|
"""Generate feed data as a structured dictionary."""
|
||||||
|
categories = self._get_categories_from_products(products)
|
||||||
|
currencies = self._get_currencies()
|
||||||
|
|
||||||
|
offers = []
|
||||||
|
for product in products:
|
||||||
|
offer = self._build_offer(product)
|
||||||
|
if offer:
|
||||||
|
offers.append(offer)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"shop": {
|
||||||
|
"name": config.COMPANY_NAME or settings.PROJECT_NAME,
|
||||||
|
"company": config.COMPANY_NAME or settings.PROJECT_NAME,
|
||||||
|
"url": f"https://{settings.STOREFRONT_DOMAIN}",
|
||||||
|
"currencies": currencies,
|
||||||
|
"categories": categories,
|
||||||
|
"offers": offers,
|
||||||
|
},
|
||||||
|
"date": datetime.now().strftime("%Y-%m-%d %H:%M"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_categories_from_products(
|
||||||
|
self, products: QuerySet[Product]
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
"""Extract unique categories from products with their hierarchy."""
|
||||||
|
category_ids = set()
|
||||||
|
categories_data = []
|
||||||
|
|
||||||
|
for product in products:
|
||||||
|
if product.category_id:
|
||||||
|
ancestors = product.category.get_ancestors(include_self=True)
|
||||||
|
for cat in ancestors:
|
||||||
|
if cat.id not in category_ids:
|
||||||
|
category_ids.add(cat.id)
|
||||||
|
cat_data = {
|
||||||
|
"id": cat.id,
|
||||||
|
"name": cat.name,
|
||||||
|
}
|
||||||
|
if cat.parent_id:
|
||||||
|
cat_data["parentId"] = cat.parent_id
|
||||||
|
categories_data.append(cat_data)
|
||||||
|
|
||||||
|
return categories_data
|
||||||
|
|
||||||
|
def _get_currencies(self) -> list[dict[str, str]]:
|
||||||
|
"""Get supported currencies."""
|
||||||
|
return [
|
||||||
|
{"id": self.get_currency(), "rate": "1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
def _build_offer(self, product: Product) -> dict[str, Any] | None:
|
||||||
|
"""Build an offer dictionary for a product."""
|
||||||
|
if not product.price or product.price <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
images = self.get_product_images(product)
|
||||||
|
|
||||||
|
offer = {
|
||||||
|
"id": product.sku,
|
||||||
|
"available": product.quantity > 0,
|
||||||
|
"url": self.get_product_url(product),
|
||||||
|
"price": product.price,
|
||||||
|
"currencyId": self.get_currency(),
|
||||||
|
"categoryId": product.category_id,
|
||||||
|
"name": product.name[:120],
|
||||||
|
}
|
||||||
|
|
||||||
|
if images:
|
||||||
|
offer["picture"] = images[:10]
|
||||||
|
|
||||||
|
if product.brand:
|
||||||
|
offer["vendor"] = product.brand.name
|
||||||
|
|
||||||
|
if product.partnumber:
|
||||||
|
offer["vendorCode"] = product.partnumber
|
||||||
|
|
||||||
|
if product.description:
|
||||||
|
offer["description"] = product.description[:3000]
|
||||||
|
|
||||||
|
if product.discount_price:
|
||||||
|
offer["oldprice"] = product.price
|
||||||
|
offer["price"] = product.price - product.discount_price
|
||||||
|
|
||||||
|
barcode = self._get_barcode(product)
|
||||||
|
if barcode:
|
||||||
|
offer["barcode"] = barcode
|
||||||
|
|
||||||
|
params = self._get_params(product)
|
||||||
|
if params:
|
||||||
|
offer["param"] = params
|
||||||
|
|
||||||
|
return offer
|
||||||
|
|
||||||
|
def _get_barcode(self, product: Product) -> str | None:
|
||||||
|
"""Extract barcode/EAN from product attributes."""
|
||||||
|
barcode_names = ["barcode", "ean", "gtin", "upc"]
|
||||||
|
|
||||||
|
for attr_value in product.attributes.all():
|
||||||
|
if attr_value.attribute.name.lower() in barcode_names:
|
||||||
|
return attr_value.value
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_params(self, product: Product) -> list[dict[str, str]]:
|
||||||
|
"""Extract product parameters from attributes."""
|
||||||
|
params = []
|
||||||
|
skip_names = ["barcode", "ean", "gtin", "upc", "isbn"]
|
||||||
|
|
||||||
|
for attr_value in product.attributes.all():
|
||||||
|
attr_name = attr_value.attribute.name
|
||||||
|
if attr_name.lower() not in skip_names:
|
||||||
|
params.append(
|
||||||
|
{
|
||||||
|
"name": attr_name,
|
||||||
|
"value": attr_value.value,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return params
|
||||||
|
|
||||||
|
def to_xml(self, data: dict[str, Any]) -> str:
|
||||||
|
"""Convert feed data to YML XML format."""
|
||||||
|
yml_catalog = Element("yml_catalog")
|
||||||
|
yml_catalog.set("date", data["date"])
|
||||||
|
|
||||||
|
shop = SubElement(yml_catalog, "shop")
|
||||||
|
|
||||||
|
name = SubElement(shop, "name")
|
||||||
|
name.text = data["shop"]["name"]
|
||||||
|
|
||||||
|
company = SubElement(shop, "company")
|
||||||
|
company.text = data["shop"]["company"]
|
||||||
|
|
||||||
|
url = SubElement(shop, "url")
|
||||||
|
url.text = data["shop"]["url"]
|
||||||
|
|
||||||
|
currencies = SubElement(shop, "currencies")
|
||||||
|
for curr in data["shop"]["currencies"]:
|
||||||
|
currency = SubElement(currencies, "currency")
|
||||||
|
currency.set("id", curr["id"])
|
||||||
|
currency.set("rate", curr["rate"])
|
||||||
|
|
||||||
|
categories = SubElement(shop, "categories")
|
||||||
|
for cat in data["shop"]["categories"]:
|
||||||
|
category = SubElement(categories, "category")
|
||||||
|
category.set("id", str(cat["id"]))
|
||||||
|
if "parentId" in cat:
|
||||||
|
category.set("parentId", str(cat["parentId"]))
|
||||||
|
category.text = cat["name"]
|
||||||
|
|
||||||
|
offers = SubElement(shop, "offers")
|
||||||
|
for offer_data in data["shop"]["offers"]:
|
||||||
|
self._add_offer_to_xml(offers, offer_data)
|
||||||
|
|
||||||
|
return (
|
||||||
|
'<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE yml_catalog SYSTEM "shops.dtd">\n'
|
||||||
|
+ self.prettify_xml(yml_catalog)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _add_offer_to_xml(self, offers: Element, offer_data: dict[str, Any]) -> None:
|
||||||
|
"""Add an offer to the XML offers element."""
|
||||||
|
offer = SubElement(offers, "offer")
|
||||||
|
offer.set("id", str(offer_data["id"]))
|
||||||
|
offer.set("available", "true" if offer_data["available"] else "false")
|
||||||
|
|
||||||
|
simple_fields = [
|
||||||
|
"url",
|
||||||
|
"price",
|
||||||
|
"oldprice",
|
||||||
|
"currencyId",
|
||||||
|
"categoryId",
|
||||||
|
"name",
|
||||||
|
"vendor",
|
||||||
|
"vendorCode",
|
||||||
|
"description",
|
||||||
|
"barcode",
|
||||||
|
]
|
||||||
|
|
||||||
|
for field in simple_fields:
|
||||||
|
if field in offer_data and offer_data[field] is not None:
|
||||||
|
elem = SubElement(offer, field)
|
||||||
|
elem.text = str(offer_data[field])
|
||||||
|
|
||||||
|
pictures = offer_data.get("picture", [])
|
||||||
|
for pic_url in pictures:
|
||||||
|
picture = SubElement(offer, "picture")
|
||||||
|
picture.text = pic_url
|
||||||
|
|
||||||
|
params = offer_data.get("param", [])
|
||||||
|
for param_data in params:
|
||||||
|
param = SubElement(offer, "param")
|
||||||
|
param.set("name", param_data["name"])
|
||||||
|
param.text = param_data["value"]
|
||||||
141
engine/core/feeds/yandex_products.py
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
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 YandexProductsFeedGenerator(BaseFeedGenerator):
|
||||||
|
"""
|
||||||
|
Yandex Products (Yandex Webmaster) feed generator.
|
||||||
|
|
||||||
|
Generates product feeds for Yandex Webmaster product snippets.
|
||||||
|
Reference: https://yandex.ru/support/webmaster/goods-prices/technical-requirements.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
name: str = "yandex_products"
|
||||||
|
supported_formats: tuple[str, ...] = ("xml", "json", "yaml")
|
||||||
|
default_format: str = "xml"
|
||||||
|
|
||||||
|
def generate_feed_data(self, products: QuerySet[Product]) -> dict[str, Any]:
|
||||||
|
"""Generate feed data as a structured dictionary."""
|
||||||
|
offers = []
|
||||||
|
for product in products:
|
||||||
|
offer = self._build_offer(product)
|
||||||
|
if offer:
|
||||||
|
offers.append(offer)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"shop": {
|
||||||
|
"name": config.COMPANY_NAME or settings.PROJECT_NAME,
|
||||||
|
"company": config.COMPANY_NAME or settings.PROJECT_NAME,
|
||||||
|
"url": f"https://{settings.STOREFRONT_DOMAIN}",
|
||||||
|
"email": config.EMAIL_HOST_USER or "",
|
||||||
|
"offers": offers,
|
||||||
|
},
|
||||||
|
"date": datetime.now().strftime("%Y-%m-%d %H:%M"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def _build_offer(self, product: Product) -> dict[str, Any] | None:
|
||||||
|
"""Build an offer dictionary for a product."""
|
||||||
|
if not product.price or product.price <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
images = self.get_product_images(product)
|
||||||
|
|
||||||
|
offer = {
|
||||||
|
"url": self.get_product_url(product),
|
||||||
|
"price": product.price,
|
||||||
|
"currencyId": self.get_currency(),
|
||||||
|
"name": product.name[:120],
|
||||||
|
"available": product.quantity > 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
if images:
|
||||||
|
offer["picture"] = images[0]
|
||||||
|
|
||||||
|
if product.brand:
|
||||||
|
offer["vendor"] = product.brand.name
|
||||||
|
|
||||||
|
if product.category:
|
||||||
|
ancestors = product.category.get_ancestors(include_self=True)
|
||||||
|
offer["category"] = " / ".join([cat.name for cat in ancestors])
|
||||||
|
|
||||||
|
if product.description:
|
||||||
|
offer["description"] = product.description[:500]
|
||||||
|
|
||||||
|
if product.discount_price:
|
||||||
|
offer["oldprice"] = product.price
|
||||||
|
offer["price"] = product.price - product.discount_price
|
||||||
|
|
||||||
|
barcode = self._get_barcode(product)
|
||||||
|
if barcode:
|
||||||
|
offer["barcode"] = barcode
|
||||||
|
|
||||||
|
return offer
|
||||||
|
|
||||||
|
def _get_barcode(self, product: Product) -> str | None:
|
||||||
|
"""Extract barcode/EAN from product attributes."""
|
||||||
|
barcode_names = ["barcode", "ean", "gtin", "upc"]
|
||||||
|
|
||||||
|
for attr_value in product.attributes.all():
|
||||||
|
if attr_value.attribute.name.lower() in barcode_names:
|
||||||
|
return attr_value.value
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def to_xml(self, data: dict[str, Any]) -> str:
|
||||||
|
"""Convert feed data to Yandex Products XML format."""
|
||||||
|
yml_catalog = Element("yml_catalog")
|
||||||
|
yml_catalog.set("date", data["date"])
|
||||||
|
|
||||||
|
shop = SubElement(yml_catalog, "shop")
|
||||||
|
|
||||||
|
name = SubElement(shop, "name")
|
||||||
|
name.text = data["shop"]["name"]
|
||||||
|
|
||||||
|
company = SubElement(shop, "company")
|
||||||
|
company.text = data["shop"]["company"]
|
||||||
|
|
||||||
|
url = SubElement(shop, "url")
|
||||||
|
url.text = data["shop"]["url"]
|
||||||
|
|
||||||
|
if data["shop"].get("email"):
|
||||||
|
email = SubElement(shop, "email")
|
||||||
|
email.text = data["shop"]["email"]
|
||||||
|
|
||||||
|
offers = SubElement(shop, "offers")
|
||||||
|
for offer_data in data["shop"]["offers"]:
|
||||||
|
self._add_offer_to_xml(offers, offer_data)
|
||||||
|
|
||||||
|
return '<?xml version="1.0" encoding="UTF-8"?>\n' + self.prettify_xml(
|
||||||
|
yml_catalog
|
||||||
|
)
|
||||||
|
|
||||||
|
def _add_offer_to_xml(self, offers: Element, offer_data: dict[str, Any]) -> None:
|
||||||
|
"""Add an offer to the XML offers element."""
|
||||||
|
offer = SubElement(offers, "offer")
|
||||||
|
offer.set("available", "true" if offer_data["available"] else "false")
|
||||||
|
|
||||||
|
simple_fields = [
|
||||||
|
"url",
|
||||||
|
"price",
|
||||||
|
"oldprice",
|
||||||
|
"currencyId",
|
||||||
|
"name",
|
||||||
|
"vendor",
|
||||||
|
"category",
|
||||||
|
"picture",
|
||||||
|
"description",
|
||||||
|
"barcode",
|
||||||
|
]
|
||||||
|
|
||||||
|
for field in simple_fields:
|
||||||
|
if field in offer_data and offer_data[field] is not None:
|
||||||
|
elem = SubElement(offer, field)
|
||||||
|
elem.text = str(offer_data[field])
|
||||||
710
engine/core/fixtures/demo.json
Normal file
|
|
@ -0,0 +1,710 @@
|
||||||
|
{
|
||||||
|
"category_tags": [
|
||||||
|
{"tag_name": "precious", "name": "Precious Stones", "name_ru": "Драгоценные камни"},
|
||||||
|
{"tag_name": "semi-precious", "name": "Semi-Precious Stones", "name_ru": "Полудрагоценные камни"},
|
||||||
|
{"tag_name": "organic", "name": "Organic Gems", "name_ru": "Органические камни"}
|
||||||
|
],
|
||||||
|
"product_tags": [
|
||||||
|
{"tag_name": "certified", "name": "GIA Certified", "name_ru": "Сертификат GIA"},
|
||||||
|
{"tag_name": "ethically-sourced", "name": "Ethically Sourced", "name_ru": "Этичное происхождение"},
|
||||||
|
{"tag_name": "rare", "name": "Rare Find", "name_ru": "Редкая находка"},
|
||||||
|
{"tag_name": "investment", "name": "Investment Grade", "name_ru": "Инвестиционное качество"},
|
||||||
|
{"tag_name": "collector", "name": "Collector's Item", "name_ru": "Коллекционный экземпляр"}
|
||||||
|
],
|
||||||
|
"attribute_groups": [
|
||||||
|
{"name": "Physical Properties", "name_ru": "Физические свойства"},
|
||||||
|
{"name": "Grading", "name_ru": "Оценка качества"},
|
||||||
|
{"name": "Origin", "name_ru": "Происхождение"}
|
||||||
|
],
|
||||||
|
"attributes": [
|
||||||
|
{"group": "Physical Properties", "name": "Carat Weight", "name_ru": "Вес в каратах", "value_type": "float", "is_filterable": true},
|
||||||
|
{"group": "Physical Properties", "name": "Dimensions (mm)", "name_ru": "Размеры (мм)", "value_type": "string", "is_filterable": false},
|
||||||
|
{"group": "Physical Properties", "name": "Cut", "name_ru": "Огранка", "value_type": "string", "is_filterable": true},
|
||||||
|
{"group": "Grading", "name": "Color Grade", "name_ru": "Цветовая категория", "value_type": "string", "is_filterable": true},
|
||||||
|
{"group": "Grading", "name": "Clarity Grade", "name_ru": "Чистота", "value_type": "string", "is_filterable": true},
|
||||||
|
{"group": "Origin", "name": "Country of Origin", "name_ru": "Страна происхождения", "value_type": "string", "is_filterable": true},
|
||||||
|
{"group": "Origin", "name": "Mine", "name_ru": "Месторождение", "value_type": "string", "is_filterable": true}
|
||||||
|
],
|
||||||
|
"brands": [
|
||||||
|
{
|
||||||
|
"name": "Sparkle & Stone",
|
||||||
|
"name_ru": "Искра и Камень",
|
||||||
|
"description": "Premium gemstone specialists since 1987. Known for exceptional quality and ethical sourcing.",
|
||||||
|
"description_ru": "Премиальные специалисты по драгоценным камням с 1987 года. Известны исключительным качеством и этичными поставками."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Azure Dreams",
|
||||||
|
"name_ru": "Лазурные Мечты",
|
||||||
|
"description": "Specializing in rare blue gemstones from around the world.",
|
||||||
|
"description_ru": "Специализируемся на редких голубых драгоценных камнях со всего мира."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Crimson Vault",
|
||||||
|
"name_ru": "Багровое Хранилище",
|
||||||
|
"description": "Expert purveyors of red and pink precious stones.",
|
||||||
|
"description_ru": "Эксперты по красным и розовым драгоценным камням."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Evergreen Gems",
|
||||||
|
"name_ru": "Вечнозелёные Камни",
|
||||||
|
"description": "The world's finest emeralds and green gemstones.",
|
||||||
|
"description_ru": "Лучшие изумруды и зелёные драгоценные камни в мире."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lumina Treasures",
|
||||||
|
"name_ru": "Сокровища Люмина",
|
||||||
|
"description": "Collectors' gems with exceptional clarity and fire.",
|
||||||
|
"description_ru": "Коллекционные камни с исключительной чистотой и игрой света."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oceanic Pearls",
|
||||||
|
"name_ru": "Океанический Жемчуг",
|
||||||
|
"description": "Sustainably harvested pearls from pristine waters.",
|
||||||
|
"description_ru": "Жемчуг устойчивого происхождения из чистейших вод."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Terra Rara",
|
||||||
|
"name_ru": "Терра Рара",
|
||||||
|
"description": "Rare and unusual gemstones for the discerning collector.",
|
||||||
|
"description_ru": "Редкие и необычные драгоценные камни для взыскательных коллекционеров."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Crystal Kingdom",
|
||||||
|
"name_ru": "Хрустальное Королевство",
|
||||||
|
"description": "Quartz varieties and crystal formations of museum quality.",
|
||||||
|
"description_ru": "Разновидности кварца и кристаллические образования музейного качества."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"name": "Gemstones",
|
||||||
|
"name_ru": "Драгоценные камни",
|
||||||
|
"description": "Fine gemstones from around the world",
|
||||||
|
"description_ru": "Изысканные драгоценные камни со всего мира",
|
||||||
|
"parent": null,
|
||||||
|
"markup_percent": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Diamonds",
|
||||||
|
"name_ru": "Бриллианты",
|
||||||
|
"description": "The hardest natural material on Earth, prized for brilliance and fire",
|
||||||
|
"description_ru": "Самый твёрдый природный материал на Земле, ценится за блеск и игру света",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rubies",
|
||||||
|
"name_ru": "Рубины",
|
||||||
|
"description": "The king of precious stones, known for deep red color",
|
||||||
|
"description_ru": "Король драгоценных камней, известен глубоким красным цветом",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sapphires",
|
||||||
|
"name_ru": "Сапфиры",
|
||||||
|
"description": "Classic blue gemstones with exceptional hardness",
|
||||||
|
"description_ru": "Классические голубые драгоценные камни с исключительной твёрдостью",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Emeralds",
|
||||||
|
"name_ru": "Изумруды",
|
||||||
|
"description": "Lush green beryl gemstones, symbol of rebirth",
|
||||||
|
"description_ru": "Роскошные зелёные камни берилла, символ возрождения",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Opals",
|
||||||
|
"name_ru": "Опалы",
|
||||||
|
"description": "Play-of-color gemstones with unique patterns",
|
||||||
|
"description_ru": "Камни с игрой цвета и уникальными узорами",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pearls",
|
||||||
|
"name_ru": "Жемчуг",
|
||||||
|
"description": "Organic gems formed within mollusks",
|
||||||
|
"description_ru": "Органические драгоценности, образующиеся в моллюсках",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Amethyst",
|
||||||
|
"name_ru": "Аметист",
|
||||||
|
"description": "Purple quartz variety, February birthstone",
|
||||||
|
"description_ru": "Фиолетовая разновидность кварца, камень рождения февраля",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Aquamarine",
|
||||||
|
"name_ru": "Аквамарин",
|
||||||
|
"description": "Sea-blue beryl, March birthstone",
|
||||||
|
"description_ru": "Морской голубой берилл, камень рождения марта",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tanzanite",
|
||||||
|
"name_ru": "Танзанит",
|
||||||
|
"description": "Rare blue-violet zoisite from Tanzania",
|
||||||
|
"description_ru": "Редкий сине-фиолетовый цоизит из Танзании",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tourmaline",
|
||||||
|
"name_ru": "Турмалин",
|
||||||
|
"description": "Multi-colored gemstones with electric properties",
|
||||||
|
"description_ru": "Многоцветные драгоценные камни с электрическими свойствами",
|
||||||
|
"parent": "Gemstones",
|
||||||
|
"markup_percent": 7
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"name": "Round Brilliant Diamond 1.5ct D VVS1",
|
||||||
|
"name_ru": "Бриллиант круглой огранки 1.5 карата D VVS1",
|
||||||
|
"description": "Exceptional 1.5 carat round brilliant cut diamond with D color and VVS1 clarity. Triple excellent cut grade with strong blue fluorescence. GIA certified. Perfect for an engagement ring centerpiece.",
|
||||||
|
"description_ru": "Исключительный бриллиант круглой огранки 1.5 карата с цветом D и чистотой VVS1. Тройная превосходная огранка с сильной голубой флуоресценцией. Сертификат GIA. Идеален для центрального камня обручального кольца.",
|
||||||
|
"category": "Diamonds",
|
||||||
|
"brand": "Sparkle & Stone",
|
||||||
|
"partnumber": "DIA-RB-150-D-VVS1",
|
||||||
|
"price": 18500,
|
||||||
|
"purchase_price": 15000,
|
||||||
|
"quantity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Princess Cut Diamond 2.0ct E VS2",
|
||||||
|
"name_ru": "Бриллиант огранки «Принцесса» 2.0 карата E VS2",
|
||||||
|
"description": "Stunning 2.0 carat princess cut diamond with E color and VS2 clarity. Modern cut with excellent symmetry. GIA certified with laser inscription.",
|
||||||
|
"description_ru": "Потрясающий бриллиант огранки «Принцесса» 2.0 карата с цветом E и чистотой VS2. Современная огранка с отличной симметрией. Сертификат GIA с лазерной гравировкой.",
|
||||||
|
"category": "Diamonds",
|
||||||
|
"brand": "Sparkle & Stone",
|
||||||
|
"partnumber": "DIA-PC-200-E-VS2",
|
||||||
|
"price": 24000,
|
||||||
|
"purchase_price": 19500,
|
||||||
|
"quantity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oval Diamond 1.2ct F IF",
|
||||||
|
"name_ru": "Бриллиант овальной огранки 1.2 карата F IF",
|
||||||
|
"description": "Magnificent 1.2 carat oval cut diamond with F color and Internally Flawless clarity. Exceptional fire and brilliance with elongated shape.",
|
||||||
|
"description_ru": "Великолепный бриллиант овальной огранки 1.2 карата с цветом F и безупречной внутренней чистотой. Исключительная игра света и блеск с удлинённой формой.",
|
||||||
|
"category": "Diamonds",
|
||||||
|
"brand": "Lumina Treasures",
|
||||||
|
"partnumber": "DIA-OV-120-F-IF",
|
||||||
|
"price": 28500,
|
||||||
|
"purchase_price": 23000,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Cushion Cut Diamond 3.0ct G VS1",
|
||||||
|
"name_ru": "Бриллиант огранки «Кушон» 3.0 карата G VS1",
|
||||||
|
"description": "Impressive 3.0 carat cushion cut diamond with G color and VS1 clarity. Vintage-inspired cut with modern brilliance.",
|
||||||
|
"description_ru": "Впечатляющий бриллиант огранки «Кушон» 3.0 карата с цветом G и чистотой VS1. Огранка в винтажном стиле с современным блеском.",
|
||||||
|
"category": "Diamonds",
|
||||||
|
"brand": "Sparkle & Stone",
|
||||||
|
"partnumber": "DIA-CU-300-G-VS1",
|
||||||
|
"price": 42000,
|
||||||
|
"purchase_price": 35000,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Emerald Cut Diamond 1.8ct D VVS2",
|
||||||
|
"name_ru": "Бриллиант изумрудной огранки 1.8 карата D VVS2",
|
||||||
|
"description": "Elegant 1.8 carat emerald cut diamond with D color and VVS2 clarity. Step-cut facets create a hall-of-mirrors effect.",
|
||||||
|
"description_ru": "Элегантный бриллиант изумрудной огранки 1.8 карата с цветом D и чистотой VVS2. Ступенчатые грани создают эффект зеркального зала.",
|
||||||
|
"category": "Diamonds",
|
||||||
|
"brand": "Lumina Treasures",
|
||||||
|
"partnumber": "DIA-EM-180-D-VVS2",
|
||||||
|
"price": 32000,
|
||||||
|
"purchase_price": 26000,
|
||||||
|
"quantity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fancy Yellow Diamond 2.5ct",
|
||||||
|
"name_ru": "Фантазийный жёлтый бриллиант 2.5 карата",
|
||||||
|
"description": "Magnificent 2.5 carat fancy intense yellow diamond. Radiant cut with excellent color distribution. GIA certified.",
|
||||||
|
"description_ru": "Великолепный фантазийный интенсивно-жёлтый бриллиант 2.5 карата. Огранка «Радиант» с отличным распределением цвета. Сертификат GIA.",
|
||||||
|
"category": "Diamonds",
|
||||||
|
"brand": "Lumina Treasures",
|
||||||
|
"partnumber": "DIA-FY-250",
|
||||||
|
"price": 65000,
|
||||||
|
"purchase_price": 52000,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pink Diamond 0.5ct Fancy Light",
|
||||||
|
"name_ru": "Розовый бриллиант 0.5 карата Fancy Light",
|
||||||
|
"description": "Rare 0.5 carat pink diamond with fancy light pink color. Pear shape from Argyle mine. Investment piece.",
|
||||||
|
"description_ru": "Редкий розовый бриллиант 0.5 карата светло-розового цвета. Грушевидная форма из рудника Аргайл. Инвестиционный экземпляр.",
|
||||||
|
"category": "Diamonds",
|
||||||
|
"brand": "Lumina Treasures",
|
||||||
|
"partnumber": "DIA-PNK-050-FL",
|
||||||
|
"price": 125000,
|
||||||
|
"purchase_price": 100000,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Burmese Ruby 2.5ct Pigeon Blood",
|
||||||
|
"name_ru": "Бирманский рубин 2.5 карата «Голубиная кровь»",
|
||||||
|
"description": "Exceptional 2.5 carat Burmese ruby with coveted pigeon blood color. Unheated and untreated with GRS certificate. Extremely rare collector's gem.",
|
||||||
|
"description_ru": "Исключительный бирманский рубин 2.5 карата с желанным цветом «голубиной крови». Без нагрева и обработки, сертификат GRS. Чрезвычайно редкий коллекционный камень.",
|
||||||
|
"category": "Rubies",
|
||||||
|
"brand": "Crimson Vault",
|
||||||
|
"partnumber": "RUB-BUR-250-PB",
|
||||||
|
"price": 125000,
|
||||||
|
"purchase_price": 100000,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mozambique Ruby 1.8ct Vivid Red",
|
||||||
|
"name_ru": "Мозамбикский рубин 1.8 карата насыщенно-красный",
|
||||||
|
"description": "Beautiful 1.8 carat Mozambique ruby with vivid red saturation. Minor heat treatment for enhanced clarity. Excellent value.",
|
||||||
|
"description_ru": "Прекрасный мозамбикский рубин 1.8 карата с насыщенной красной окраской. Незначительная термообработка для улучшения чистоты. Отличное соотношение цены и качества.",
|
||||||
|
"category": "Rubies",
|
||||||
|
"brand": "Crimson Vault",
|
||||||
|
"partnumber": "RUB-MOZ-180-VR",
|
||||||
|
"price": 8500,
|
||||||
|
"purchase_price": 6800,
|
||||||
|
"quantity": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Star Ruby 3.2ct Six-Ray",
|
||||||
|
"name_ru": "Звёздчатый рубин 3.2 карата с шестилучевой звездой",
|
||||||
|
"description": "Magnificent 3.2 carat star ruby displaying sharp six-ray asterism. Cabochon cut to showcase the star effect. From Sri Lanka.",
|
||||||
|
"description_ru": "Великолепный звёздчатый рубин 3.2 карата с чёткой шестилучевой звездой. Огранка кабошон для демонстрации эффекта звезды. Из Шри-Ланки.",
|
||||||
|
"category": "Rubies",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "RUB-STAR-320-SR",
|
||||||
|
"price": 15000,
|
||||||
|
"purchase_price": 12000,
|
||||||
|
"quantity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kashmir Sapphire 3.0ct Cornflower Blue",
|
||||||
|
"name_ru": "Кашмирский сапфир 3.0 карата васильково-голубой",
|
||||||
|
"description": "Museum-quality 3.0 carat Kashmir sapphire with legendary cornflower blue color. Unheated with velvety luster. Investment grade.",
|
||||||
|
"description_ru": "Кашмирский сапфир музейного качества 3.0 карата с легендарным васильково-голубым цветом. Без нагрева, с бархатистым блеском. Инвестиционное качество.",
|
||||||
|
"category": "Sapphires",
|
||||||
|
"brand": "Azure Dreams",
|
||||||
|
"partnumber": "SAP-KAS-300-CB",
|
||||||
|
"price": 185000,
|
||||||
|
"purchase_price": 150000,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ceylon Sapphire 2.2ct Royal Blue",
|
||||||
|
"name_ru": "Цейлонский сапфир 2.2 карата королевский синий",
|
||||||
|
"description": "Stunning 2.2 carat Ceylon sapphire with rich royal blue color. Excellent clarity with minor silk inclusions. Heat treated.",
|
||||||
|
"description_ru": "Потрясающий цейлонский сапфир 2.2 карата насыщенного королевского синего цвета. Отличная чистота с незначительными шёлковыми включениями. Термообработан.",
|
||||||
|
"category": "Sapphires",
|
||||||
|
"brand": "Azure Dreams",
|
||||||
|
"partnumber": "SAP-CEY-220-RB",
|
||||||
|
"price": 12500,
|
||||||
|
"purchase_price": 10000,
|
||||||
|
"quantity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Padparadscha Sapphire 1.5ct",
|
||||||
|
"name_ru": "Сапфир падпараджа 1.5 карата",
|
||||||
|
"description": "Rare 1.5 carat padparadscha sapphire with pink-orange sunset color. Unheated Sri Lankan origin. Highly sought after by collectors.",
|
||||||
|
"description_ru": "Редкий сапфир падпараджа 1.5 карата с розово-оранжевым закатным цветом. Без нагрева, происхождение Шри-Ланка. Высоко ценится коллекционерами.",
|
||||||
|
"category": "Sapphires",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "SAP-PAD-150",
|
||||||
|
"price": 45000,
|
||||||
|
"purchase_price": 36000,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Yellow Sapphire 4.0ct Golden",
|
||||||
|
"name_ru": "Жёлтый сапфир 4.0 карата золотистый",
|
||||||
|
"description": "Brilliant 4.0 carat yellow sapphire with intense golden color. From Sri Lanka with excellent clarity. Untreated.",
|
||||||
|
"description_ru": "Блестящий жёлтый сапфир 4.0 карата интенсивного золотистого цвета. Из Шри-Ланки с отличной чистотой. Без обработки.",
|
||||||
|
"category": "Sapphires",
|
||||||
|
"brand": "Azure Dreams",
|
||||||
|
"partnumber": "SAP-YEL-400-GD",
|
||||||
|
"price": 6500,
|
||||||
|
"purchase_price": 5200,
|
||||||
|
"quantity": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pink Sapphire 1.8ct Hot Pink",
|
||||||
|
"name_ru": "Розовый сапфир 1.8 карата ярко-розовый",
|
||||||
|
"description": "Vibrant 1.8 carat pink sapphire with hot pink saturation. Madagascar origin with excellent transparency.",
|
||||||
|
"description_ru": "Яркий розовый сапфир 1.8 карата с насыщенным ярко-розовым цветом. Происхождение Мадагаскар с отличной прозрачностью.",
|
||||||
|
"category": "Sapphires",
|
||||||
|
"brand": "Crimson Vault",
|
||||||
|
"partnumber": "SAP-PNK-180-HP",
|
||||||
|
"price": 4200,
|
||||||
|
"purchase_price": 3400,
|
||||||
|
"quantity": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Colombian Emerald 2.8ct Muzo Green",
|
||||||
|
"name_ru": "Колумбийский изумруд 2.8 карата зелёный Музо",
|
||||||
|
"description": "Premium 2.8 carat Colombian emerald from the famous Muzo mines. Deep green color with characteristic jardín inclusions.",
|
||||||
|
"description_ru": "Премиальный колумбийский изумруд 2.8 карата из знаменитых шахт Музо. Глубокий зелёный цвет с характерными включениями «жардин».",
|
||||||
|
"category": "Emeralds",
|
||||||
|
"brand": "Evergreen Gems",
|
||||||
|
"partnumber": "EME-COL-280-MZ",
|
||||||
|
"price": 35000,
|
||||||
|
"purchase_price": 28000,
|
||||||
|
"quantity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Zambian Emerald 3.5ct Vivid Green",
|
||||||
|
"name_ru": "Замбийский изумруд 3.5 карата насыщенно-зелёный",
|
||||||
|
"description": "Impressive 3.5 carat Zambian emerald with vivid bluish-green color. Higher clarity than Colombian stones. Minor oil treatment.",
|
||||||
|
"description_ru": "Впечатляющий замбийский изумруд 3.5 карата с насыщенным сине-зелёным цветом. Чистота выше, чем у колумбийских камней. Незначительная масляная обработка.",
|
||||||
|
"category": "Emeralds",
|
||||||
|
"brand": "Evergreen Gems",
|
||||||
|
"partnumber": "EME-ZAM-350-VG",
|
||||||
|
"price": 18500,
|
||||||
|
"purchase_price": 15000,
|
||||||
|
"quantity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Brazilian Emerald 1.2ct Medium Green",
|
||||||
|
"name_ru": "Бразильский изумруд 1.2 карата средне-зелёный",
|
||||||
|
"description": "Beautiful 1.2 carat Brazilian emerald with medium green saturation. Good clarity with subtle inclusions. Value option.",
|
||||||
|
"description_ru": "Прекрасный бразильский изумруд 1.2 карата средней зелёной насыщенности. Хорошая чистота с незаметными включениями. Выгодный вариант.",
|
||||||
|
"category": "Emeralds",
|
||||||
|
"brand": "Evergreen Gems",
|
||||||
|
"partnumber": "EME-BRA-120-MG",
|
||||||
|
"price": 2800,
|
||||||
|
"purchase_price": 2200,
|
||||||
|
"quantity": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Australian Black Opal 5.2ct",
|
||||||
|
"name_ru": "Австралийский чёрный опал 5.2 карата",
|
||||||
|
"description": "Spectacular 5.2 carat Australian black opal from Lightning Ridge. Brilliant play-of-color with red, green, and blue flashes.",
|
||||||
|
"description_ru": "Потрясающий австралийский чёрный опал 5.2 карата из Лайтнинг Ридж. Блестящая игра цвета с красными, зелёными и синими вспышками.",
|
||||||
|
"category": "Opals",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "OPL-BLK-520-LR",
|
||||||
|
"price": 28000,
|
||||||
|
"purchase_price": 22500,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ethiopian Welo Opal 3.8ct",
|
||||||
|
"name_ru": "Эфиопский опал Вело 3.8 карата",
|
||||||
|
"description": "Stunning 3.8 carat Ethiopian Welo opal with hydrophane properties. Intense play-of-color with honeycomb pattern.",
|
||||||
|
"description_ru": "Потрясающий эфиопский опал Вело 3.8 карата с гидрофанными свойствами. Интенсивная игра цвета с сотовым рисунком.",
|
||||||
|
"category": "Opals",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "OPL-ETH-380-WL",
|
||||||
|
"price": 3500,
|
||||||
|
"purchase_price": 2800,
|
||||||
|
"quantity": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Boulder Opal 8.5ct",
|
||||||
|
"name_ru": "Боулдер-опал 8.5 карата",
|
||||||
|
"description": "Natural 8.5 carat boulder opal with ironstone matrix. Unique patterns with veins of brilliant color.",
|
||||||
|
"description_ru": "Природный боулдер-опал 8.5 карата с железистой матрицей. Уникальные узоры с прожилками ярких цветов.",
|
||||||
|
"category": "Opals",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "OPL-BLD-850",
|
||||||
|
"price": 4800,
|
||||||
|
"purchase_price": 3800,
|
||||||
|
"quantity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fire Opal 2.1ct Mexican Orange",
|
||||||
|
"name_ru": "Огненный опал 2.1 карата мексиканский оранжевый",
|
||||||
|
"description": "Brilliant 2.1 carat Mexican fire opal with intense orange color. Transparent with subtle play-of-color.",
|
||||||
|
"description_ru": "Блестящий мексиканский огненный опал 2.1 карата интенсивного оранжевого цвета. Прозрачный с тонкой игрой цвета.",
|
||||||
|
"category": "Opals",
|
||||||
|
"brand": "Lumina Treasures",
|
||||||
|
"partnumber": "OPL-FIRE-210-MX",
|
||||||
|
"price": 1200,
|
||||||
|
"purchase_price": 950,
|
||||||
|
"quantity": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "South Sea Pearl 14mm Golden",
|
||||||
|
"name_ru": "Жемчуг Южных морей 14мм золотистый",
|
||||||
|
"description": "Luxurious 14mm South Sea pearl with deep golden color. AAA grade with excellent luster and minimal blemishes.",
|
||||||
|
"description_ru": "Роскошный жемчуг Южных морей 14мм глубокого золотистого цвета. Класс AAA с отличным блеском и минимальными дефектами.",
|
||||||
|
"category": "Pearls",
|
||||||
|
"brand": "Oceanic Pearls",
|
||||||
|
"partnumber": "PRL-SSG-14MM",
|
||||||
|
"price": 8500,
|
||||||
|
"purchase_price": 6800,
|
||||||
|
"quantity": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tahitian Pearl 12mm Peacock",
|
||||||
|
"name_ru": "Таитянский жемчуг 12мм павлиний",
|
||||||
|
"description": "Exotic 12mm Tahitian pearl with peacock overtones. Natural dark body color with green and purple iridescence.",
|
||||||
|
"description_ru": "Экзотический таитянский жемчуг 12мм с павлиньими переливами. Природный тёмный цвет тела с зелёной и фиолетовой иризацией.",
|
||||||
|
"category": "Pearls",
|
||||||
|
"brand": "Oceanic Pearls",
|
||||||
|
"partnumber": "PRL-TAH-12MM-PC",
|
||||||
|
"price": 3200,
|
||||||
|
"purchase_price": 2500,
|
||||||
|
"quantity": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Akoya Pearl Strand 7mm",
|
||||||
|
"name_ru": "Нить жемчуга Акойя 7мм",
|
||||||
|
"description": "Classic 18-inch strand of 7mm Akoya pearls. Perfect round shape with bright white body and rose overtone.",
|
||||||
|
"description_ru": "Классическая нить жемчуга Акойя 7мм длиной 45 см. Идеально круглая форма с ярко-белым телом и розовым перламутром.",
|
||||||
|
"category": "Pearls",
|
||||||
|
"brand": "Oceanic Pearls",
|
||||||
|
"partnumber": "PRL-AKO-7MM-STR",
|
||||||
|
"price": 4500,
|
||||||
|
"purchase_price": 3600,
|
||||||
|
"quantity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Freshwater Pearl Set",
|
||||||
|
"name_ru": "Набор пресноводного жемчуга",
|
||||||
|
"description": "Elegant set of 10 matched freshwater pearls, 9-10mm. Various pastel colors including white, pink, and lavender.",
|
||||||
|
"description_ru": "Элегантный набор из 10 подобранных пресноводных жемчужин 9-10мм. Различные пастельные цвета: белый, розовый и лавандовый.",
|
||||||
|
"category": "Pearls",
|
||||||
|
"brand": "Oceanic Pearls",
|
||||||
|
"partnumber": "PRL-FW-SET-10",
|
||||||
|
"price": 850,
|
||||||
|
"purchase_price": 680,
|
||||||
|
"quantity": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Siberian Amethyst 8.5ct Deep Purple",
|
||||||
|
"name_ru": "Сибирский аметист 8.5 карата тёмно-фиолетовый",
|
||||||
|
"description": "Premium 8.5 carat Siberian amethyst with legendary deep purple color and red flashes. Cushion cut.",
|
||||||
|
"description_ru": "Премиальный сибирский аметист 8.5 карата с легендарным тёмно-фиолетовым цветом и красными вспышками. Огранка «Кушон».",
|
||||||
|
"category": "Amethyst",
|
||||||
|
"brand": "Crystal Kingdom",
|
||||||
|
"partnumber": "AME-SIB-850-DP",
|
||||||
|
"price": 1200,
|
||||||
|
"purchase_price": 950,
|
||||||
|
"quantity": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Uruguayan Amethyst 12.3ct",
|
||||||
|
"name_ru": "Уругвайский аметист 12.3 карата",
|
||||||
|
"description": "Magnificent 12.3 carat Uruguayan amethyst with excellent saturation. Oval cut with exceptional clarity.",
|
||||||
|
"description_ru": "Великолепный уругвайский аметист 12.3 карата с отличной насыщенностью. Овальная огранка с исключительной чистотой.",
|
||||||
|
"category": "Amethyst",
|
||||||
|
"brand": "Crystal Kingdom",
|
||||||
|
"partnumber": "AME-URU-1230",
|
||||||
|
"price": 650,
|
||||||
|
"purchase_price": 520,
|
||||||
|
"quantity": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ametrine 6.8ct Bi-Color",
|
||||||
|
"name_ru": "Аметрин 6.8 карата двухцветный",
|
||||||
|
"description": "Unique 6.8 carat ametrine showing both amethyst purple and citrine gold colors. Emerald cut from Bolivia.",
|
||||||
|
"description_ru": "Уникальный аметрин 6.8 карата, демонстрирующий фиолетовый цвет аметиста и золотистый цитрина. Изумрудная огранка, Боливия.",
|
||||||
|
"category": "Amethyst",
|
||||||
|
"brand": "Crystal Kingdom",
|
||||||
|
"partnumber": "AME-TRI-680-BC",
|
||||||
|
"price": 450,
|
||||||
|
"purchase_price": 360,
|
||||||
|
"quantity": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Santa Maria Aquamarine 4.2ct",
|
||||||
|
"name_ru": "Аквамарин Санта-Мария 4.2 карата",
|
||||||
|
"description": "Exceptional 4.2 carat Santa Maria aquamarine with intense blue color. The finest aquamarine variety from Brazil.",
|
||||||
|
"description_ru": "Исключительный аквамарин Санта-Мария 4.2 карата с интенсивным голубым цветом. Лучшая разновидность аквамарина из Бразилии.",
|
||||||
|
"category": "Aquamarine",
|
||||||
|
"brand": "Azure Dreams",
|
||||||
|
"partnumber": "AQU-SM-420",
|
||||||
|
"price": 5500,
|
||||||
|
"purchase_price": 4400,
|
||||||
|
"quantity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Madagascar Aquamarine 7.5ct",
|
||||||
|
"name_ru": "Мадагаскарский аквамарин 7.5 карата",
|
||||||
|
"description": "Beautiful 7.5 carat Madagascar aquamarine with light blue color. Excellent clarity with octagon cut.",
|
||||||
|
"description_ru": "Прекрасный мадагаскарский аквамарин 7.5 карата светло-голубого цвета. Отличная чистота с восьмиугольной огранкой.",
|
||||||
|
"category": "Aquamarine",
|
||||||
|
"brand": "Azure Dreams",
|
||||||
|
"partnumber": "AQU-MAD-750",
|
||||||
|
"price": 2200,
|
||||||
|
"purchase_price": 1750,
|
||||||
|
"quantity": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pakistani Aquamarine 15.2ct",
|
||||||
|
"name_ru": "Пакистанский аквамарин 15.2 карата",
|
||||||
|
"description": "Spectacular 15.2 carat aquamarine from Pakistan's Shigar Valley. Medium blue with exceptional size and clarity.",
|
||||||
|
"description_ru": "Впечатляющий аквамарин 15.2 карата из пакистанской долины Шигар. Средне-голубой с исключительным размером и чистотой.",
|
||||||
|
"category": "Aquamarine",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "AQU-PAK-1520",
|
||||||
|
"price": 4800,
|
||||||
|
"purchase_price": 3850,
|
||||||
|
"quantity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AAA Tanzanite 5.8ct Vivid Blue",
|
||||||
|
"name_ru": "Танзанит ААА 5.8 карата насыщенно-синий",
|
||||||
|
"description": "Top-quality 5.8 carat tanzanite with vivid blue-violet color. Trillion cut with exceptional saturation.",
|
||||||
|
"description_ru": "Танзанит высшего качества 5.8 карата с насыщенным сине-фиолетовым цветом. Огранка «Триллион» с исключительной насыщенностью.",
|
||||||
|
"category": "Tanzanite",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "TAN-AAA-580-VB",
|
||||||
|
"price": 8500,
|
||||||
|
"purchase_price": 6800,
|
||||||
|
"quantity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tanzanite 3.2ct Blue-Violet",
|
||||||
|
"name_ru": "Танзанит 3.2 карата сине-фиолетовый",
|
||||||
|
"description": "Beautiful 3.2 carat tanzanite with balanced blue-violet color shift. Oval cut with good clarity.",
|
||||||
|
"description_ru": "Прекрасный танзанит 3.2 карата со сбалансированным сине-фиолетовым переходом цвета. Овальная огранка с хорошей чистотой.",
|
||||||
|
"category": "Tanzanite",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "TAN-320-BV",
|
||||||
|
"price": 3200,
|
||||||
|
"purchase_price": 2560,
|
||||||
|
"quantity": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tanzanite Pair 2.0ct Each",
|
||||||
|
"name_ru": "Пара танзанитов по 2.0 карата",
|
||||||
|
"description": "Matched pair of 2.0 carat tanzanites, perfect for earrings. Identical color and cut with excellent symmetry.",
|
||||||
|
"description_ru": "Подобранная пара танзанитов по 2.0 карата, идеальна для серёг. Идентичный цвет и огранка с отличной симметрией.",
|
||||||
|
"category": "Tanzanite",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "TAN-PAIR-200",
|
||||||
|
"price": 5800,
|
||||||
|
"purchase_price": 4650,
|
||||||
|
"quantity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Paraiba Tourmaline 1.2ct Neon Blue",
|
||||||
|
"name_ru": "Параиба турмалин 1.2 карата неоново-голубой",
|
||||||
|
"description": "Extremely rare 1.2 carat Paraiba tourmaline with electric neon blue color. Brazilian origin with copper inclusions.",
|
||||||
|
"description_ru": "Чрезвычайно редкий турмалин параиба 1.2 карата с электрическим неоново-голубым цветом. Бразильское происхождение с медными включениями.",
|
||||||
|
"category": "Tourmaline",
|
||||||
|
"brand": "Terra Rara",
|
||||||
|
"partnumber": "TOU-PAR-120-NB",
|
||||||
|
"price": 85000,
|
||||||
|
"purchase_price": 68000,
|
||||||
|
"quantity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Watermelon Tourmaline 8.5ct",
|
||||||
|
"name_ru": "Арбузный турмалин 8.5 карата",
|
||||||
|
"description": "Stunning 8.5 carat watermelon tourmaline with pink center and green rim. Slice cut to display bi-color.",
|
||||||
|
"description_ru": "Потрясающий арбузный турмалин 8.5 карата с розовым центром и зелёным ободком. Огранка «слайс» для демонстрации двуцветности.",
|
||||||
|
"category": "Tourmaline",
|
||||||
|
"brand": "Crystal Kingdom",
|
||||||
|
"partnumber": "TOU-WM-850",
|
||||||
|
"price": 1800,
|
||||||
|
"purchase_price": 1450,
|
||||||
|
"quantity": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rubellite Tourmaline 4.3ct",
|
||||||
|
"name_ru": "Рубеллит турмалин 4.3 карата",
|
||||||
|
"description": "Vivid 4.3 carat rubellite tourmaline with raspberry red color. Cushion cut with excellent saturation.",
|
||||||
|
"description_ru": "Яркий рубеллит турмалин 4.3 карата малиново-красного цвета. Огранка «Кушон» с отличной насыщенностью.",
|
||||||
|
"category": "Tourmaline",
|
||||||
|
"brand": "Crimson Vault",
|
||||||
|
"partnumber": "TOU-RUB-430",
|
||||||
|
"price": 3500,
|
||||||
|
"purchase_price": 2800,
|
||||||
|
"quantity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Chrome Tourmaline 2.8ct",
|
||||||
|
"name_ru": "Хромовый турмалин 2.8 карата",
|
||||||
|
"description": "Rich 2.8 carat chrome tourmaline with intense green color. From East Africa with excellent transparency.",
|
||||||
|
"description_ru": "Насыщенный хромовый турмалин 2.8 карата интенсивного зелёного цвета. Из Восточной Африки с отличной прозрачностью.",
|
||||||
|
"category": "Tourmaline",
|
||||||
|
"brand": "Evergreen Gems",
|
||||||
|
"partnumber": "TOU-CHR-280",
|
||||||
|
"price": 2200,
|
||||||
|
"purchase_price": 1750,
|
||||||
|
"quantity": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Indicolite Tourmaline 3.6ct",
|
||||||
|
"name_ru": "Индиголит турмалин 3.6 карата",
|
||||||
|
"description": "Beautiful 3.6 carat indicolite tourmaline with teal blue color. Oval cut from Afghanistan.",
|
||||||
|
"description_ru": "Прекрасный индиголит турмалин 3.6 карата сине-зелёного цвета. Овальная огранка, Афганистан.",
|
||||||
|
"category": "Tourmaline",
|
||||||
|
"brand": "Azure Dreams",
|
||||||
|
"partnumber": "TOU-IND-360",
|
||||||
|
"price": 2800,
|
||||||
|
"purchase_price": 2250,
|
||||||
|
"quantity": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vendor": {
|
||||||
|
"name": "Schon Demo",
|
||||||
|
"markup_percent": 5
|
||||||
|
},
|
||||||
|
"demo_users": {
|
||||||
|
"password": "Schon!Demo888",
|
||||||
|
"email_domain": "demo.schon.store",
|
||||||
|
"first_names": [
|
||||||
|
"Emma", "Liam", "Olivia", "Noah", "Ava", "Ethan", "Sophia", "Mason",
|
||||||
|
"Isabella", "William", "Mia", "James", "Charlotte", "Benjamin", "Amelia",
|
||||||
|
"Lucas", "Harper", "Henry", "Evelyn", "Alexander", "Abigail", "Michael",
|
||||||
|
"Emily", "Daniel", "Elizabeth", "Jacob", "Sofia", "Logan", "Avery",
|
||||||
|
"Jackson", "Ella", "Sebastian", "Scarlett", "Aiden", "Grace", "Matthew",
|
||||||
|
"Chloe", "David", "Victoria", "Joseph", "Riley", "Carter", "Aria",
|
||||||
|
"Owen", "Lily", "Wyatt", "Aurora", "John", "Zoey", "Luke", "Nora"
|
||||||
|
],
|
||||||
|
"last_names": [
|
||||||
|
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller",
|
||||||
|
"Davis", "Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzalez",
|
||||||
|
"Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin",
|
||||||
|
"Lee", "Perez", "Thompson", "White", "Harris", "Sanchez", "Clark",
|
||||||
|
"Ramirez", "Lewis", "Robinson", "Walker", "Young", "Allen", "King",
|
||||||
|
"Wright", "Scott", "Torres", "Nguyen", "Hill", "Flores", "Green",
|
||||||
|
"Adams", "Nelson", "Baker", "Hall", "Rivera", "Campbell", "Mitchell",
|
||||||
|
"Carter", "Roberts"
|
||||||
|
],
|
||||||
|
"cities": [
|
||||||
|
{"city": "New York", "region": "NY", "postal_code": "10001", "country": "USA"},
|
||||||
|
{"city": "Los Angeles", "region": "CA", "postal_code": "90001", "country": "USA"},
|
||||||
|
{"city": "Chicago", "region": "IL", "postal_code": "60601", "country": "USA"},
|
||||||
|
{"city": "Houston", "region": "TX", "postal_code": "77001", "country": "USA"},
|
||||||
|
{"city": "Phoenix", "region": "AZ", "postal_code": "85001", "country": "USA"},
|
||||||
|
{"city": "Philadelphia", "region": "PA", "postal_code": "19101", "country": "USA"},
|
||||||
|
{"city": "San Antonio", "region": "TX", "postal_code": "78201", "country": "USA"},
|
||||||
|
{"city": "San Diego", "region": "CA", "postal_code": "92101", "country": "USA"},
|
||||||
|
{"city": "Dallas", "region": "TX", "postal_code": "75201", "country": "USA"},
|
||||||
|
{"city": "San Jose", "region": "CA", "postal_code": "95101", "country": "USA"},
|
||||||
|
{"city": "Austin", "region": "TX", "postal_code": "78701", "country": "USA"},
|
||||||
|
{"city": "Jacksonville", "region": "FL", "postal_code": "32099", "country": "USA"},
|
||||||
|
{"city": "Fort Worth", "region": "TX", "postal_code": "76101", "country": "USA"},
|
||||||
|
{"city": "Columbus", "region": "OH", "postal_code": "43085", "country": "USA"},
|
||||||
|
{"city": "Charlotte", "region": "NC", "postal_code": "28201", "country": "USA"},
|
||||||
|
{"city": "London", "region": "Greater London", "postal_code": "SW1A 1AA", "country": "UK"},
|
||||||
|
{"city": "Manchester", "region": "Greater Manchester", "postal_code": "M1 1AD", "country": "UK"},
|
||||||
|
{"city": "Birmingham", "region": "West Midlands", "postal_code": "B1 1AA", "country": "UK"},
|
||||||
|
{"city": "Paris", "region": "Île-de-France", "postal_code": "75001", "country": "France"},
|
||||||
|
{"city": "Berlin", "region": "Berlin", "postal_code": "10115", "country": "Germany"},
|
||||||
|
{"city": "Munich", "region": "Bavaria", "postal_code": "80331", "country": "Germany"},
|
||||||
|
{"city": "Toronto", "region": "Ontario", "postal_code": "M5H 2N2", "country": "Canada"},
|
||||||
|
{"city": "Vancouver", "region": "British Columbia", "postal_code": "V6C 1E1", "country": "Canada"},
|
||||||
|
{"city": "Sydney", "region": "NSW", "postal_code": "2000", "country": "Australia"},
|
||||||
|
{"city": "Melbourne", "region": "VIC", "postal_code": "3000", "country": "Australia"}
|
||||||
|
],
|
||||||
|
"streets": [
|
||||||
|
"Main Street", "Oak Avenue", "Maple Drive", "Park Boulevard", "Cedar Lane",
|
||||||
|
"Elm Street", "Washington Avenue", "Lake Street", "Hill Road", "Forest Drive",
|
||||||
|
"River Road", "Sunset Boulevard", "Highland Avenue", "Valley View Drive",
|
||||||
|
"Mountain Road"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
engine/core/fixtures/demo_products_images/AME-SIB-850-DP.jpg
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
engine/core/fixtures/demo_products_images/AME-TRI-680-BC.jpg
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
engine/core/fixtures/demo_products_images/AME-URU-1230.jpg
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
engine/core/fixtures/demo_products_images/AQU-SM-420.jpg
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
engine/core/fixtures/demo_products_images/DIA-CU-300-G-VS1.jpg
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
engine/core/fixtures/demo_products_images/DIA-EM-180-D-VVS2.jpg
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
engine/core/fixtures/demo_products_images/DIA-FY-250.jpg
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
engine/core/fixtures/demo_products_images/DIA-OV-120-F-IF.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
engine/core/fixtures/demo_products_images/DIA-PC-200-E-VS2.jpg
Normal file
|
After Width: | Height: | Size: 321 KiB |
BIN
engine/core/fixtures/demo_products_images/DIA-PNK-050-FL.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |