mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-31 18:17:29 +01:00
Merge branch 'main' into parent-location-sync
This commit is contained in:
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1 +1 @@
|
||||
github: [tankerkiller125,katosdev]
|
||||
github: [tankerkiller125,katosdev,tonyaellie]
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -3,6 +3,7 @@ name: "Bug Report"
|
||||
description: "Submit a bug report for the current release"
|
||||
labels: ["🕷️ bug"]
|
||||
projects: ["sysadminsmedia/2"]
|
||||
type: "Bug"
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -3,6 +3,7 @@ name: "Feature Request"
|
||||
description: "Submit a feature request for the current release"
|
||||
labels: ["⬆️ enhancement"]
|
||||
projects: ["sysadminsmedia/2"]
|
||||
type: "Enhancement"
|
||||
body:
|
||||
- type: textarea
|
||||
id: problem-statement
|
||||
|
||||
34
.github/workflows/docker-publish-arm.yaml
vendored
34
.github/workflows/docker-publish-arm.yaml
vendored
@@ -30,7 +30,6 @@ env:
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -38,36 +37,35 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
# Step 1: Checkout repository
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Set up BuildKit Docker container builder to be able to build
|
||||
# multi-platform images and export cache
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
# Step 2: Set up Buildx without specifying driver
|
||||
# Let it use default settings to avoid the 'no remote endpoint' issue
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0 # v3.0.0
|
||||
uses: docker/setup-buildx-action@v3.0.0
|
||||
with:
|
||||
install: true # Ensure Buildx is installed and set up properly
|
||||
use: true # Use Buildx instance directly for this job
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
# Step 3: Login against Docker registry except on PR
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3.0.0 # v3.0.0
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
# Step 4: Extract metadata for Docker images
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5.0.0 # v5.0.0
|
||||
uses: docker/metadata-action@v5.0.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -80,11 +78,10 @@ jobs:
|
||||
flavor: |
|
||||
suffix=-arm,onlatest=true
|
||||
|
||||
# Build and push Docker image with Buildx (don't push on PR)
|
||||
# https://github.com/docker/build-push-action
|
||||
# Step 5: Build and push the Docker image
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v5.0.0 # v5.0.0
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
@@ -95,8 +92,9 @@ jobs:
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
# Step 6: Attest built image to prove build provenance
|
||||
- name: Attest
|
||||
uses: actions/attest-build-provenance@v1
|
||||
id: attest
|
||||
|
||||
@@ -24,14 +24,12 @@ on:
|
||||
- '.dockerignore'
|
||||
- '.github/workflows'
|
||||
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
|
||||
jobs:
|
||||
build-rootless:
|
||||
|
||||
@@ -39,36 +37,34 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
# Step 1: Checkout repository
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Set up BuildKit Docker container builder to be able to build
|
||||
# multi-platform images and export cache
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
# Step 2: Set up Buildx without specifying driver
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0 # v3.0.0
|
||||
uses: docker/setup-buildx-action@v3.0.0
|
||||
with:
|
||||
install: true # Ensure Buildx is installed and set up properly
|
||||
use: true # Use Buildx instance directly for this job
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
# Step 3: Login to Docker registry except on PR
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3.0.0 # v3.0.0
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
# Step 4: Extract metadata for Docker images
|
||||
- name: Extract Docker metadata
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v5.0.0 # v5.0.0
|
||||
uses: docker/metadata-action@v5.0.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -80,12 +76,11 @@ jobs:
|
||||
type=schedule,pattern=nightly
|
||||
flavor: |
|
||||
suffix=-rootless-arm,onlatest=true
|
||||
|
||||
# Build and push Docker image with Buildx (don't push on PR)
|
||||
# https://github.com/docker/build-push-action
|
||||
|
||||
# Step 5: Build and push the Docker image
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v5.0.0 # v5.0.0
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
@@ -98,6 +93,7 @@ jobs:
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
|
||||
# Step 6: Attest built image to prove build provenance
|
||||
- name: Attest
|
||||
uses: actions/attest-build-provenance@v1
|
||||
id: attest
|
||||
|
||||
4
.github/workflows/partial-frontend.yaml
vendored
4
.github/workflows/partial-frontend.yaml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
|
||||
- uses: pnpm/action-setup@v3.0.0
|
||||
with:
|
||||
version: 6.0.2
|
||||
version: 9.12.2
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --shamefully-hoist
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
- uses: pnpm/action-setup@v3.0.0
|
||||
with:
|
||||
version: 6.0.2
|
||||
version: 9.12.2
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
76
Dockerfile
76
Dockerfile
@@ -1,69 +1,91 @@
|
||||
# Node dependencies
|
||||
FROM node:18-alpine AS frontend-dependencies
|
||||
# Node dependencies stage
|
||||
FROM --platform=$TARGETPLATFORM node:18-alpine AS frontend-dependencies
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm globally (caching layer)
|
||||
RUN npm install -g pnpm
|
||||
|
||||
# Copy package.json and lockfile to leverage caching
|
||||
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile --shamefully-hoist
|
||||
|
||||
# Build Nuxt
|
||||
FROM node:18-alpine AS frontend-builder
|
||||
WORKDIR /app
|
||||
# Build Nuxt (frontend) stage
|
||||
FROM --platform=$TARGETPLATFORM node:18-alpine AS frontend-builder
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm globally again (it can reuse the cache if not changed)
|
||||
RUN npm install -g pnpm
|
||||
COPY frontend .
|
||||
|
||||
# Copy over source files and node_modules from dependencies stage
|
||||
COPY frontend .
|
||||
COPY --from=frontend-dependencies /app/node_modules ./node_modules
|
||||
RUN pnpm build
|
||||
|
||||
FROM golang:alpine AS builder-dependencies
|
||||
# Go dependencies stage
|
||||
FROM --platform=$TARGETPLATFORM golang:alpine AS builder-dependencies
|
||||
WORKDIR /go/src/app
|
||||
COPY ./backend .
|
||||
|
||||
# Copy go.mod and go.sum for better caching
|
||||
COPY ./backend/go.mod ./backend/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Build API
|
||||
FROM golang:alpine AS builder
|
||||
# Build API stage
|
||||
FROM --platform=$TARGETPLATFORM golang:alpine AS builder
|
||||
ARG BUILD_TIME
|
||||
ARG COMMIT
|
||||
ARG VERSION
|
||||
|
||||
# Install necessary build tools
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add --update git build-base gcc g++
|
||||
apk add --no-cache git build-base gcc g++
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
# Copy Go modules (from dependencies stage) and source code
|
||||
COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod
|
||||
COPY ./backend .
|
||||
|
||||
# Clear old public files and copy new ones from frontend build
|
||||
RUN rm -rf ./app/api/public
|
||||
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
||||
COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
|
||||
# Use cache for Go build artifacts
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||
-o /go/bin/api \
|
||||
-v ./app/api/*.go
|
||||
|
||||
FROM gcr.io/distroless/java:latest
|
||||
|
||||
# Production Stage
|
||||
FROM alpine:latest
|
||||
|
||||
# Production stage
|
||||
FROM --platform=$TARGETPLATFORM alpine:latest
|
||||
ENV HBOX_MODE=production
|
||||
ENV HBOX_STORAGE_DATA=/data/
|
||||
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1
|
||||
|
||||
RUN apk --no-cache add ca-certificates
|
||||
# Install necessary runtime dependencies
|
||||
RUN apk --no-cache add ca-certificates wget
|
||||
|
||||
# Create application directory and copy over built Go binary
|
||||
RUN mkdir /app
|
||||
COPY --from=builder /go/bin/api /app
|
||||
|
||||
RUN chmod +x /app/api
|
||||
RUN apk add --no-cache wget
|
||||
|
||||
# Labels and configuration for the final image
|
||||
LABEL Name=homebox Version=0.0.1
|
||||
LABEL org.opencontainers.image.source="https://github.com/sysadminsmedia/homebox"
|
||||
|
||||
# Expose necessary ports
|
||||
EXPOSE 7745
|
||||
WORKDIR /app
|
||||
HEALTHCHECK --interval=30s \
|
||||
--timeout=5s \
|
||||
--start-period=5s \
|
||||
--retries=3 \
|
||||
CMD [ "/usr/bin/wget", "--no-verbose", "--tries=1", "-O -", "http://localhost:7745/api/v1/status" ]
|
||||
|
||||
# Healthcheck configuration
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||
CMD [ "wget", "--no-verbose", "--tries=1", "-O", "-", "http://localhost:7745/api/v1/status" ]
|
||||
|
||||
# Persist volume
|
||||
VOLUME [ "/data" ]
|
||||
|
||||
# Entrypoint and CMD
|
||||
ENTRYPOINT [ "/app/api" ]
|
||||
CMD [ "/data/config.yml" ]
|
||||
|
||||
@@ -7,15 +7,15 @@ RUN pnpm install --frozen-lockfile --shamefully-hoist
|
||||
|
||||
# Build Nuxt
|
||||
FROM node:18-alpine AS frontend-builder
|
||||
WORKDIR /app
|
||||
RUN npm install -g pnpm
|
||||
COPY frontend .
|
||||
WORKDIR /app
|
||||
COPY frontend ./
|
||||
COPY --from=frontend-dependencies /app/node_modules ./node_modules
|
||||
RUN pnpm build
|
||||
|
||||
# Build Go dependencies
|
||||
FROM golang:alpine AS builder-dependencies
|
||||
WORKDIR /go/src/app
|
||||
COPY ./backend .
|
||||
COPY ./backend/go.mod ./backend/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Build API
|
||||
@@ -23,48 +23,51 @@ FROM golang:alpine AS builder
|
||||
ARG BUILD_TIME
|
||||
ARG COMMIT
|
||||
ARG VERSION
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add --update git build-base gcc g++
|
||||
|
||||
RUN apk update && apk upgrade && apk add --no-cache git build-base gcc g++
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY ./backend .
|
||||
RUN rm -rf ./app/api/public
|
||||
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
||||
COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
|
||||
# Use cache for Go build
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||
-o /go/bin/api \
|
||||
-v ./app/api/*.go
|
||||
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||
-o /go/bin/api ./app/api/*.go
|
||||
|
||||
FROM gcr.io/distroless/java:latest
|
||||
|
||||
# Production Stage
|
||||
# Production stage with distroless
|
||||
FROM gcr.io/distroless/static:latest
|
||||
|
||||
ENV HBOX_MODE=production
|
||||
ENV HBOX_STORAGE_DATA=/data/
|
||||
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1
|
||||
|
||||
# Copy the binary and the (empty) /data dir and
|
||||
# change the ownership to the low-privileged user
|
||||
# Copy the binary and data directory, change ownership
|
||||
COPY --from=builder --chown=nonroot /go/bin/api /app
|
||||
COPY --from=builder --chown=nonroot /data /data
|
||||
|
||||
RUN apk add --no-cache wget
|
||||
# Add wget to the image
|
||||
# Note: If using distroless, this may not be applicable
|
||||
# as distroless images do not include package managers.
|
||||
# This line may be omitted if you're relying on another way to handle healthchecks.
|
||||
COPY --from=alpine:latest /bin/wget /usr/bin/wget
|
||||
|
||||
LABEL Name=homebox Version=0.0.1
|
||||
LABEL org.opencontainers.image.source="https://github.com/sysadminsmedia/homebox"
|
||||
EXPOSE 7745
|
||||
|
||||
HEALTHCHECK --interval=30s \
|
||||
--timeout=5s \
|
||||
--start-period=5s \
|
||||
--retries=3 \
|
||||
CMD [ "/usr/bin/wget", "--no-verbose", "--tries=1", "-O -", "http://localhost:7745/api/v1/status" ]
|
||||
VOLUME [ "/data" ]
|
||||
CMD ["/usr/bin/wget", "--no-verbose", "--tries=1", "-O", "-", "http://localhost:7745/api/v1/status"]
|
||||
|
||||
# Drop root and run as low-privileged user
|
||||
VOLUME ["/data"]
|
||||
|
||||
# Drop root and run as a low-privileged user
|
||||
USER nonroot
|
||||
ENTRYPOINT [ "/app" ]
|
||||
CMD [ "/data/config.yml" ]
|
||||
ENTRYPOINT ["/app"]
|
||||
CMD ["/data/config.yml"]
|
||||
|
||||
@@ -87,11 +87,11 @@ func (r *AttachmentRepo) Get(ctx context.Context, id uuid.UUID) (*ent.Attachment
|
||||
Only(ctx)
|
||||
}
|
||||
|
||||
func (r *AttachmentRepo) Update(ctx context.Context, itemID uuid.UUID, data *ItemAttachmentUpdate) (*ent.Attachment, error) {
|
||||
func (r *AttachmentRepo) Update(ctx context.Context, id uuid.UUID, data *ItemAttachmentUpdate) (*ent.Attachment, error) {
|
||||
// TODO: execute within Tx
|
||||
typ := attachment.Type(data.Type)
|
||||
|
||||
bldr := r.db.Attachment.UpdateOneID(itemID).
|
||||
bldr := r.db.Attachment.UpdateOneID(id).
|
||||
SetType(typ)
|
||||
|
||||
// Primary only applies to photos
|
||||
@@ -101,7 +101,12 @@ func (r *AttachmentRepo) Update(ctx context.Context, itemID uuid.UUID, data *Ite
|
||||
bldr = bldr.SetPrimary(false)
|
||||
}
|
||||
|
||||
itm, err := bldr.Save(ctx)
|
||||
updatedAttachment, err := bldr.Save(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attachmentItem, err := updatedAttachment.QueryItem().Only(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -109,8 +114,8 @@ func (r *AttachmentRepo) Update(ctx context.Context, itemID uuid.UUID, data *Ite
|
||||
// Ensure all other attachments are not primary
|
||||
err = r.db.Attachment.Update().
|
||||
Where(
|
||||
attachment.HasItemWith(item.ID(itemID)),
|
||||
attachment.IDNEQ(itm.ID),
|
||||
attachment.HasItemWith(item.ID(attachmentItem.ID)),
|
||||
attachment.IDNEQ(updatedAttachment.ID),
|
||||
).
|
||||
SetPrimary(false).
|
||||
Exec(ctx)
|
||||
@@ -118,7 +123,7 @@ func (r *AttachmentRepo) Update(ctx context.Context, itemID uuid.UUID, data *Ite
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Get(ctx, itm.ID)
|
||||
return r.Get(ctx, updatedAttachment.ID)
|
||||
}
|
||||
|
||||
func (r *AttachmentRepo) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
|
||||
@@ -133,3 +133,25 @@ func TestAttachmentRepo_Delete(t *testing.T) {
|
||||
_, err = tRepos.Attachments.Get(context.Background(), entity.ID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAttachmentRepo_EnsureSinglePrimaryAttachment(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
attachments := useAttachments(t, 2)
|
||||
|
||||
setAndVerifyPrimary := func(primaryAttachmentID, nonPrimaryAttachmentID uuid.UUID) {
|
||||
primaryAttachment, err := tRepos.Attachments.Update(ctx, primaryAttachmentID, &ItemAttachmentUpdate{
|
||||
Type: attachment.TypePhoto.String(),
|
||||
Primary: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
nonPrimaryAttachment, err := tRepos.Attachments.Get(ctx, nonPrimaryAttachmentID)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.True(t, primaryAttachment.Primary)
|
||||
assert.False(t, nonPrimaryAttachment.Primary)
|
||||
}
|
||||
|
||||
setAndVerifyPrimary(attachments[0].ID, attachments[1].ID)
|
||||
setAndVerifyPrimary(attachments[1].ID, attachments[0].ID)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ swagger update command `task swag`
|
||||
|
||||
### Frontend Development Notes
|
||||
|
||||
start command `task: ui:dev`
|
||||
start command `task ui:dev`
|
||||
|
||||
1. The frontend is a Vue 3 app with Nuxt.js that uses Tailwind and DaisyUI for styling.
|
||||
2. We're using Vitest for our automated testing. You can run these with `task ui:watch`.
|
||||
|
||||
@@ -28,3 +28,61 @@
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #9B9B9B;
|
||||
}
|
||||
|
||||
.scroll-bg::-webkit-scrollbar {
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
.scroll-bg::-webkit-scrollbar-thumb {
|
||||
border-radius: 0.25rem;
|
||||
@apply bg-base-300;
|
||||
}
|
||||
|
||||
.markdown > :first-child {
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
.markdown :where(p, ul, ol, dl, blockquote, h1, h2, h3, h4, h5, h6) {
|
||||
margin-top: var(--y-gap);
|
||||
margin-bottom: var(--y-gap);
|
||||
}
|
||||
|
||||
.markdown :where(ul) {
|
||||
list-style: disc;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.markdown :where(ol) {
|
||||
list-style: decimal;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
/* Heading Styles */
|
||||
.markdown :where(h1) {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h2) {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h3) {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h4) {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h5) {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h6) {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
class="flex items-center text-3xl font-bold tracking-tight"
|
||||
:class="{
|
||||
'text-neutral-content': dark,
|
||||
'text-content': !dark,
|
||||
}"
|
||||
>
|
||||
<slot />
|
||||
|
||||
@@ -85,7 +85,10 @@
|
||||
type Props = {
|
||||
label: string;
|
||||
modelValue: SupportValues | null | undefined;
|
||||
items: string[] | object[];
|
||||
items: {
|
||||
id: string;
|
||||
treeString: string;
|
||||
}[];
|
||||
display?: string;
|
||||
multiple?: boolean;
|
||||
};
|
||||
@@ -156,11 +159,28 @@
|
||||
|
||||
const matches = index.value.search("*" + search.value + "*");
|
||||
|
||||
const resultIDs = [];
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
const match = matches[i];
|
||||
const item = props.items[parseInt(match.ref)];
|
||||
const display = extractDisplay(item);
|
||||
list.push({ id: i, display, value: item });
|
||||
resultIDs.push(item.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplementary search,
|
||||
* Resolve the issue of language not being supported
|
||||
*/
|
||||
for (let i = 0; i < props.items.length; i++) {
|
||||
const item = props.items[i];
|
||||
if (resultIDs.find(item_ => item_ === item.id) !== undefined) {
|
||||
continue;
|
||||
}
|
||||
if (item.treeString.includes(search.value)) {
|
||||
const display = extractDisplay(item);
|
||||
list.push({ id: i, display, value: item });
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
:class="{
|
||||
'text-red-600':
|
||||
typeof value === 'string' &&
|
||||
((maxLength && value.length > maxLength) || (minLength && value.length < minLength)),
|
||||
((maxLength !== -1 && value.length > maxLength) || (minLength !== -1 && value.length < minLength)),
|
||||
}"
|
||||
>
|
||||
{{ typeof value === "string" && (maxLength || minLength) ? `${value.length}/${maxLength}` : "" }}
|
||||
{{ typeof value === "string" && (maxLength !== -1 || minLength !== -1) ? `${value.length}/${maxLength}` : "" }}
|
||||
</span>
|
||||
</label>
|
||||
<textarea ref="el" v-model="value" class="textarea textarea-bordered h-28 w-full" :placeholder="placeholder" />
|
||||
@@ -21,10 +21,10 @@
|
||||
:class="{
|
||||
'text-red-600':
|
||||
typeof value === 'string' &&
|
||||
((maxLength && value.length > maxLength) || (minLength && value.length < minLength)),
|
||||
((maxLength !== -1 && value.length > maxLength) || (minLength !== -1 && value.length < minLength)),
|
||||
}"
|
||||
>
|
||||
{{ typeof value === "string" && (maxLength || minLength) ? `${value.length}/${maxLength}` : "" }}
|
||||
{{ typeof value === "string" && (maxLength !== -1 || minLength !== -1) ? `${value.length}/${maxLength}` : "" }}
|
||||
</span>
|
||||
</label>
|
||||
<textarea
|
||||
@@ -63,10 +63,12 @@
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
required: false,
|
||||
},
|
||||
minLength: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
@@ -84,7 +86,4 @@
|
||||
});
|
||||
|
||||
const value = useVModel(props, "modelValue", emit);
|
||||
const valueLen = computed(() => {
|
||||
return value.value ? value.value.length : 0;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
:class="{
|
||||
'text-red-600':
|
||||
typeof value === 'string' &&
|
||||
((maxLength && value.length > maxLength) || (minLength && value.length < minLength)),
|
||||
((maxLength !== -1 && value.length > maxLength) || (minLength !== -1 && value.length < minLength)),
|
||||
}"
|
||||
>
|
||||
{{ typeof value === "string" && (maxLength || minLength) ? `${value.length}/${maxLength}` : "" }}
|
||||
{{ typeof value === "string" && (maxLength !== -1 || minLength !== -1) ? `${value.length}/${maxLength}` : "" }}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
@@ -28,10 +28,10 @@
|
||||
:class="{
|
||||
'text-red-600':
|
||||
typeof value === 'string' &&
|
||||
((maxLength && value.length > maxLength) || (minLength && value.length < minLength)),
|
||||
((maxLength !== -1 && value.length > maxLength) || (minLength !== -1 && value.length < minLength)),
|
||||
}"
|
||||
>
|
||||
{{ typeof value === "string" && (maxLength || minLength) ? `${value.length}/${maxLength}` : "" }}
|
||||
{{ typeof value === "string" && (maxLength !== -1 || minLength !== -1) ? `${value.length}/${maxLength}` : "" }}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
@@ -76,10 +76,12 @@
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
required: false,
|
||||
},
|
||||
minLength: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
<template>
|
||||
<NuxtLink class="group card rounded-md border border-gray-300" :to="`/item/${item.id}`">
|
||||
<div class="relative h-[200px]">
|
||||
<img v-if="imageUrl" class="h-[200px] w-full rounded-t border-gray-300 object-cover shadow-sm" :src="imageUrl" />
|
||||
<div class="absolute bottom-1 left-1">
|
||||
<img
|
||||
v-if="imageUrl"
|
||||
class="h-[200px] w-full rounded-t border-gray-300 object-cover shadow-sm"
|
||||
:src="imageUrl"
|
||||
alt=""
|
||||
/>
|
||||
<div class="absolute bottom-1 left-1 text-wrap">
|
||||
<NuxtLink
|
||||
v-if="item.location"
|
||||
class="badge rounded-md text-sm shadow-md hover:link"
|
||||
:to="`/location/${item.location.id}`"
|
||||
loading="lazy"
|
||||
>
|
||||
{{ item.location.name }}
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-4 flex grow flex-col gap-y-1 rounded-b bg-base-100 p-4 pt-2">
|
||||
<h2 class="line-clamp-2 text-ellipsis text-lg font-bold">{{ item.name }}</h2>
|
||||
<h2 class="line-clamp-2 text-ellipsis text-wrap text-lg font-bold">{{ item.name }}</h2>
|
||||
<div class="divider my-0"></div>
|
||||
<div class="flex gap-2">
|
||||
<div v-if="item.insured" class="tooltip z-10" data-tip="Insured">
|
||||
|
||||
@@ -8,17 +8,27 @@
|
||||
v-model="form.name"
|
||||
:trigger-focus="focused"
|
||||
:autofocus="true"
|
||||
label="Item Name"
|
||||
:label="$t('components.item.create_modal.item_name')"
|
||||
:max-length="255"
|
||||
:min-length="1"
|
||||
/>
|
||||
<FormTextArea v-model="form.description" label="Item Description" :max-length="1000" />
|
||||
<FormMultiselect v-model="form.labels" label="Labels" :items="labels ?? []" />
|
||||
<FormTextArea
|
||||
v-model="form.description"
|
||||
:label="$t('components.item.create_modal.item_description')"
|
||||
:max-length="1000"
|
||||
/>
|
||||
<FormMultiselect v-model="form.labels" :label="$t('global.labels')" :items="labels ?? []" />
|
||||
|
||||
<div class="modal-action mb-6">
|
||||
<div>
|
||||
<label for="photo" class="btn">{{ $t("components.item.create_modal.photo_button") }}</label>
|
||||
<input id="photo" class="hidden" type="file" accept="image/png,image/jpeg,image/gif" @change="previewImage" />
|
||||
<input
|
||||
id="photo"
|
||||
class="hidden"
|
||||
type="file"
|
||||
accept="image/png,image/jpeg,image/gif,image/avif,image/webp"
|
||||
@change="previewImage"
|
||||
/>
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<div>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}"
|
||||
>
|
||||
<template v-if="typeof h === 'string'">{{ h }}</template>
|
||||
<template v-else>{{ h.text }}</template>
|
||||
<template v-else>{{ $t(h.text) }}</template>
|
||||
<div
|
||||
v-if="sortByProperty === h.value"
|
||||
:class="`inline-flex ${sortByProperty === h.value ? '' : 'opacity-0'}`"
|
||||
@@ -45,7 +45,7 @@
|
||||
}"
|
||||
>
|
||||
<template v-if="h.type === 'name'">
|
||||
<NuxtLink class="hover" :to="`/item/${d.id}`">
|
||||
<NuxtLink class="hover text-wrap" :to="`/item/${d.id}`">
|
||||
{{ d.name }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
@@ -83,7 +83,7 @@
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content rounded-box flex w-64 flex-col gap-2 bg-base-100 p-2 pl-3 shadow">
|
||||
<li>Headers:</li>
|
||||
<li v-for="(h, i) in headers" class="flex flex-row items-center gap-1">
|
||||
<li v-for="(h, i) in headers" :key="h.value" class="flex flex-row items-center gap-1">
|
||||
<button
|
||||
class="btn btn-square btn-ghost btn-xs"
|
||||
:class="{
|
||||
@@ -109,11 +109,11 @@
|
||||
:checked="h.enabled"
|
||||
@change="toggleHeader(h.value)"
|
||||
/>
|
||||
<label class="label-text" :for="h.value"> {{ h.text }} </label>
|
||||
<label class="label-text" :for="h.value"> {{ $t(h.text) }} </label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="hidden md:block">Rows per page</div>
|
||||
<div class="hidden md:block">{{ $t("components.item.view.table.rows_per_page") }}</div>
|
||||
<select v-model.number="pagination.rowsPerPage" class="select select-primary select-sm">
|
||||
<option :value="10">10</option>
|
||||
<option :value="25">25</option>
|
||||
@@ -122,7 +122,7 @@
|
||||
</select>
|
||||
<div class="btn-group">
|
||||
<button :disabled="!hasPrev" class="btn btn-sm" @click="prev()">«</button>
|
||||
<button class="btn btn-sm">Page {{ pagination.page }}</button>
|
||||
<button class="btn btn-sm">{{ $t("components.item.view.table.page") }} {{ pagination.page }}</button>
|
||||
<button :disabled="!hasNext" class="btn btn-sm" @click="next()">»</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -149,20 +149,29 @@
|
||||
const preferences = useViewPreferences();
|
||||
|
||||
const defaultHeaders = [
|
||||
{ text: "Name", value: "name", enabled: true, type: "name" },
|
||||
{ text: "Quantity", value: "quantity", align: "center", enabled: true },
|
||||
{ text: "Insured", value: "insured", align: "center", enabled: true, type: "boolean" },
|
||||
{ text: "Price", value: "purchasePrice", align: "center", enabled: true, type: "price" },
|
||||
{ text: "Location", value: "location", align: "center", enabled: false, type: "location" },
|
||||
{ text: "Archived", value: "archived", align: "center", enabled: false, type: "boolean" },
|
||||
{ text: "Created At", value: "createdAt", align: "center", enabled: false, type: "date" },
|
||||
{ text: "Updated At", value: "updatedAt", align: "center", enabled: false, type: "date" },
|
||||
{
|
||||
text: "items.name",
|
||||
value: "name",
|
||||
enabled: true,
|
||||
type: "name",
|
||||
},
|
||||
{ text: "items.quantity", value: "quantity", align: "center", enabled: true },
|
||||
{ text: "items.insured", value: "insured", align: "center", enabled: true, type: "boolean" },
|
||||
{ text: "items.purchase_price", value: "purchasePrice", align: "center", enabled: true, type: "price" },
|
||||
{ text: "items.location", value: "location", align: "center", enabled: false, type: "location" },
|
||||
{ text: "items.archived", value: "archived", align: "center", enabled: false, type: "boolean" },
|
||||
{ text: "items.created_at", value: "createdAt", align: "center", enabled: false, type: "date" },
|
||||
{ text: "items.updated_at", value: "updatedAt", align: "center", enabled: false, type: "date" },
|
||||
] satisfies TableHeader[];
|
||||
|
||||
const headers = ref<TableHeader[]>(
|
||||
(preferences.value.tableHeaders ?? []).concat(
|
||||
defaultHeaders.filter(h => !preferences.value.tableHeaders?.find(h2 => h2.value === h.value))
|
||||
)
|
||||
(preferences.value.tableHeaders ?? [])
|
||||
.concat(defaultHeaders.filter(h => !preferences.value.tableHeaders?.find(h2 => h2.value === h.value)))
|
||||
// this is a hack to make sure that any changes to the defaultHeaders are reflected in the preferences
|
||||
.map(h => ({
|
||||
...(defaultHeaders.find(h2 => h2.value === h.value) as TableHeader),
|
||||
enabled: h.enabled,
|
||||
}))
|
||||
);
|
||||
|
||||
console.log(headers.value);
|
||||
|
||||
@@ -7,11 +7,15 @@
|
||||
v-model="form.name"
|
||||
:trigger-focus="focused"
|
||||
:autofocus="true"
|
||||
label="Label Name"
|
||||
:label="$t('components.label.create_modal.label_name')"
|
||||
:max-length="255"
|
||||
:min-length="1"
|
||||
/>
|
||||
<FormTextArea v-model="form.description" label="Label Description" :max-length="255" />
|
||||
<FormTextArea
|
||||
v-model="form.description"
|
||||
:label="$t('components.label.create_modal.label_description')"
|
||||
:max-length="255"
|
||||
/>
|
||||
<div class="modal-action">
|
||||
<div class="flex justify-center">
|
||||
<BaseButton class="rounded-r-none" :loading="loading" type="submit"> {{ $t("global.create") }} </BaseButton>
|
||||
|
||||
@@ -8,11 +8,15 @@
|
||||
:trigger-focus="focused"
|
||||
:autofocus="true"
|
||||
:required="true"
|
||||
label="Location Name"
|
||||
:label="$t('components.location.create_modal.location_name')"
|
||||
:max-length="255"
|
||||
:min-length="1"
|
||||
/>
|
||||
<FormTextArea v-model="form.description" label="Location Description" :max-length="1000" />
|
||||
<FormTextArea
|
||||
v-model="form.description"
|
||||
:label="$t('components.location.create_modal.location_description')"
|
||||
:max-length="1000"
|
||||
/>
|
||||
<LocationSelector v-model="form.parent" />
|
||||
<div class="modal-action">
|
||||
<div class="flex justify-center">
|
||||
@@ -21,7 +25,7 @@
|
||||
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
||||
<MdiChevronDown class="size-5" />
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box bg-base-100 right-0 w-64 p-2 shadow">
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box right-0 w-64 bg-base-100 p-2 shadow">
|
||||
<li>
|
||||
<button type="button" @click="create(false)">{{ $t("global.create_and_add") }}</button>
|
||||
</li>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<FormAutocomplete2 v-if="locations" v-model="value" :items="locations" display="name" label="Parent Location">
|
||||
<FormAutocomplete2
|
||||
v-if="locations"
|
||||
v-model="value"
|
||||
:items="locations"
|
||||
display="name"
|
||||
:label="$t('components.location.selector.parent_location')"
|
||||
>
|
||||
<template #display="{ item, selected, active }">
|
||||
<div>
|
||||
<div class="flex w-full">
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- eslint-disable-next-line tailwindcss/no-custom-classname -->
|
||||
<div class="root border-2 p-4">
|
||||
<p v-if="locs.length === 0" class="text-center text-sm">
|
||||
{{ $t("location.tree.no_locations") }}
|
||||
|
||||
@@ -25,17 +25,17 @@
|
||||
},
|
||||
});
|
||||
|
||||
const { data: maintenanceDataList, refresh: refreshList } = useAsyncData<MaintenanceEntryWithDetails[]>(
|
||||
const { data: maintenanceDataList, refresh: refreshList } = useAsyncData(
|
||||
async () => {
|
||||
const { data } =
|
||||
props.currentItemId !== undefined
|
||||
? await api.items.maintenance.getLog(props.currentItemId, { status: maintenanceFilterStatus.value })
|
||||
: await api.maintenance.getAll({ status: maintenanceFilterStatus.value });
|
||||
console.log(data);
|
||||
return data as MaintenanceEntryWithDetails[];
|
||||
return data;
|
||||
},
|
||||
{
|
||||
watch: maintenanceFilterStatus,
|
||||
watch: [maintenanceFilterStatus],
|
||||
}
|
||||
);
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<StatCard
|
||||
v-for="stat in stats"
|
||||
:key="stat.id"
|
||||
class="stats border-l-primary block shadow-xl"
|
||||
class="stats block border-l-primary shadow-xl"
|
||||
:title="stat.title"
|
||||
:value="stat.value"
|
||||
:type="stat.type"
|
||||
@@ -189,7 +189,7 @@
|
||||
<div v-if="props.currentItemId" class="hidden first:block">
|
||||
<button
|
||||
type="button"
|
||||
class="border-base-content relative block w-full rounded-lg border-2 border-dashed p-12 text-center"
|
||||
class="relative block w-full rounded-lg border-2 border-dashed border-base-content p-12 text-center"
|
||||
@click="maintenanceEditModal?.openCreateModal(props.currentItemId)"
|
||||
>
|
||||
<MdiWrenchClock class="inline size-16" />
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<dl class="sm:divide-y sm:divide-gray-300">
|
||||
<div v-for="(detail, i) in details" :key="i" class="group py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-base-content">
|
||||
{{ detail.name }}
|
||||
{{ $t(detail.name) }}
|
||||
</dt>
|
||||
<dd class="text-start text-sm text-base-content sm:col-span-2">
|
||||
<slot :name="detail.slot || detail.name" v-bind="{ detail }">
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div class="markdown text-wrap" v-html="raw"></div>
|
||||
</template>
|
||||
|
||||
@@ -31,53 +32,4 @@
|
||||
* {
|
||||
--y-gap: 0.65rem;
|
||||
}
|
||||
|
||||
.markdown > :first-child {
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
.markdown :where(p, ul, ol, dl, blockquote, h1, h2, h3, h4, h5, h6) {
|
||||
margin-top: var(--y-gap);
|
||||
margin-bottom: var(--y-gap);
|
||||
}
|
||||
|
||||
.markdown :where(ul) {
|
||||
list-style: disc;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.markdown :where(ol) {
|
||||
list-style: decimal;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
/* Heading Styles */
|
||||
.markdown :where(h1) {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h2) {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h3) {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h4) {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h5) {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.markdown :where(h6) {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { type UseTimeAgoMessages, type UseTimeAgoUnitNamesDefault } from "@vueuse/core";
|
||||
|
||||
const cache = {
|
||||
currency: "",
|
||||
};
|
||||
@@ -37,6 +40,49 @@ function ordinalIndicator(num: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export function useLocaleTimeAgo(date: Date) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const I18N_MESSAGES: UseTimeAgoMessages<UseTimeAgoUnitNamesDefault> = {
|
||||
justNow: t("components.global.date_time.just-now"),
|
||||
past: n => (n.match(/\d/) ? t("components.global.date_time.ago", [n]) : n),
|
||||
future: n => (n.match(/\d/) ? t("components.global.date_time.in", [n]) : n),
|
||||
month: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-month")
|
||||
: t("components.global.date_time.next-month")
|
||||
: `${n} ${t(`components.global.date_time.months`)}`,
|
||||
year: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-year")
|
||||
: t("components.global.date_time.next-year")
|
||||
: `${n} ${t(`components.global.date_time.years`)}`,
|
||||
day: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.yesterday")
|
||||
: t("components.global.date_time.tomorrow")
|
||||
: `${n} ${t(`components.global.date_time.days`)}`,
|
||||
week: (n, past) =>
|
||||
n === 1
|
||||
? past
|
||||
? t("components.global.date_time.last-week")
|
||||
: t("components.global.date_time.next-week")
|
||||
: `${n} ${t(`components.global.date_time.weeks`)}`,
|
||||
hour: n => `${n} ${n === 1 ? t("components.global.date_time.hour") : t("components.global.date_time.hours")}`,
|
||||
minute: n => `${n} ${n === 1 ? t("components.global.date_time.minute") : t("components.global.date_time.minutes")}`,
|
||||
second: n => `${n} ${n === 1 ? t("components.global.date_time.second") : t("components.global.date_time.seconds")}`,
|
||||
invalid: "",
|
||||
};
|
||||
|
||||
return useTimeAgo(date, {
|
||||
fullDateFormatter: (date: Date) => date.toLocaleDateString(),
|
||||
messages: I18N_MESSAGES,
|
||||
});
|
||||
}
|
||||
|
||||
export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): string {
|
||||
const months = [
|
||||
"January",
|
||||
@@ -64,7 +110,7 @@ export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): st
|
||||
|
||||
switch (fmt) {
|
||||
case "relative":
|
||||
return useTimeAgo(dt).value + useDateFormat(dt, " (YYYY-MM-DD)").value;
|
||||
return useLocaleTimeAgo(dt).value + useDateFormat(dt, " (YYYY-MM-DD)").value;
|
||||
case "long":
|
||||
return useDateFormat(dt, "YYYY-MM-DD (dddd)").value;
|
||||
case "short":
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Ref } from "vue";
|
||||
import type { TableHeader } from "components/Item/View/Table.types";
|
||||
import type { TableHeader } from "~/components/Item/View/Table.types";
|
||||
import type { DaisyTheme } from "~~/lib/data/themes";
|
||||
|
||||
export type ViewType = "table" | "card" | "tree";
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
<AppToast />
|
||||
<div class="drawer drawer-mobile">
|
||||
<input id="my-drawer-2" v-model="drawerToggle" type="checkbox" class="drawer-toggle" />
|
||||
<div class="drawer-content bg-base-300 justify-center pt-20 lg:pt-0">
|
||||
<div class="drawer-content justify-center bg-base-300 pt-20 lg:pt-0">
|
||||
<AppHeaderDecor v-if="preferences.displayHeaderDecor" class="-mt-10 hidden lg:block" />
|
||||
<!-- Button -->
|
||||
<div class="navbar drawer-button bg-primary fixed top-0 z-[99] shadow-md lg:hidden">
|
||||
<div class="navbar drawer-button fixed top-0 z-[99] bg-primary shadow-md lg:hidden">
|
||||
<label for="my-drawer-2" class="btn btn-square btn-ghost drawer-button text-base-100 lg:hidden">
|
||||
<MdiMenu class="size-6" />
|
||||
</label>
|
||||
<NuxtLink to="/home">
|
||||
<h2 class="text-base-100 flex text-3xl font-bold tracking-tight">
|
||||
<h2 class="flex text-3xl font-bold tracking-tight text-base-100">
|
||||
HomeB
|
||||
<AppLogo class="-mb-3 w-8" />
|
||||
x
|
||||
@@ -29,7 +29,7 @@
|
||||
</div>
|
||||
|
||||
<slot></slot>
|
||||
<footer v-if="status" class="bg-base-300 text-secondary-content bottom-0 w-full pb-4 text-center">
|
||||
<footer v-if="status" class="bottom-0 w-full bg-base-300 pb-4 text-center text-secondary-content">
|
||||
<p class="text-center text-sm">
|
||||
{{ $t("global.version", { version: status.build.version }) }} ~
|
||||
{{ $t("global.build", { build: status.build.commit }) }}
|
||||
@@ -42,17 +42,17 @@
|
||||
<label for="my-drawer-2" class="drawer-overlay"></label>
|
||||
|
||||
<!-- Top Section -->
|
||||
<div class="bg-base-200 flex min-w-40 max-w-min flex-col p-5 md:py-10">
|
||||
<div class="flex min-w-40 max-w-min flex-col bg-base-200 p-5 md:py-10">
|
||||
<div class="space-y-8">
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<p>{{ $t("global.welcome", { username: username }) }}</p>
|
||||
<NuxtLink class="avatar placeholder" to="/home">
|
||||
<div class="bg-base-300 text-neutral-content w-24 rounded-full p-4">
|
||||
<div class="w-24 rounded-full bg-base-300 p-4 text-neutral-content">
|
||||
<AppLogo />
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="bg-base-200 flex flex-col">
|
||||
<div class="flex flex-col bg-base-200">
|
||||
<div class="mb-6">
|
||||
<div class="dropdown visible w-full">
|
||||
<label tabindex="0" class="text-no-transform btn btn-primary btn-block text-lg">
|
||||
@@ -61,10 +61,10 @@
|
||||
</span>
|
||||
{{ $t("global.create") }}
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box bg-base-100 w-full p-2 shadow">
|
||||
<li v-for="btn in dropdown" :key="btn.name">
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box w-full bg-base-100 p-2 shadow">
|
||||
<li v-for="btn in dropdown" :key="btn.id">
|
||||
<button @click="btn.action">
|
||||
{{ btn.name }}
|
||||
{{ btn.name.value }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -81,7 +81,7 @@
|
||||
}"
|
||||
>
|
||||
<component :is="n.icon" class="mr-4 size-6" />
|
||||
{{ n.name }}
|
||||
{{ n.name.value }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -89,7 +89,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Bottom -->
|
||||
<button class="rounded-btn hover:bg-base-300 mx-2 mt-auto p-3" @click="logout">
|
||||
<button class="rounded-btn mx-2 mt-auto p-3 hover:bg-base-300" @click="logout">
|
||||
{{ $t("global.sign_out") }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -135,19 +135,22 @@
|
||||
|
||||
const dropdown = [
|
||||
{
|
||||
name: "Item / Asset",
|
||||
id: 0,
|
||||
name: computed(() => t("menu.create_item")),
|
||||
action: () => {
|
||||
modals.item = true;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Location",
|
||||
id: 1,
|
||||
name: computed(() => t("menu.create_location")),
|
||||
action: () => {
|
||||
modals.location = true;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Label",
|
||||
id: 2,
|
||||
name: computed(() => t("menu.create_label")),
|
||||
action: () => {
|
||||
modals.label = true;
|
||||
},
|
||||
@@ -168,42 +171,42 @@
|
||||
icon: MdiHome,
|
||||
active: computed(() => route.path === "/home"),
|
||||
id: 0,
|
||||
name: t("menu.home"),
|
||||
name: computed(() => t("menu.home")),
|
||||
to: "/home",
|
||||
},
|
||||
{
|
||||
icon: MdiFileTree,
|
||||
id: 1,
|
||||
active: computed(() => route.path === "/locations"),
|
||||
name: t("menu.locations"),
|
||||
name: computed(() => t("menu.locations")),
|
||||
to: "/locations",
|
||||
},
|
||||
{
|
||||
icon: MdiMagnify,
|
||||
id: 2,
|
||||
active: computed(() => route.path === "/items"),
|
||||
name: t("menu.search"),
|
||||
name: computed(() => t("menu.search")),
|
||||
to: "/items",
|
||||
},
|
||||
{
|
||||
icon: MdiWrench,
|
||||
id: 3,
|
||||
active: computed(() => route.path === "/maintenance"),
|
||||
name: t("menu.maintenance"),
|
||||
name: computed(() => t("menu.maintenance")),
|
||||
to: "/maintenance",
|
||||
},
|
||||
{
|
||||
icon: MdiAccount,
|
||||
id: 4,
|
||||
active: computed(() => route.path === "/profile"),
|
||||
name: t("menu.profile"),
|
||||
name: computed(() => t("menu.profile")),
|
||||
to: "/profile",
|
||||
},
|
||||
{
|
||||
icon: MdiCog,
|
||||
id: 5,
|
||||
active: computed(() => route.path === "/tools"),
|
||||
name: t("menu.tools"),
|
||||
name: computed(() => t("menu.tools")),
|
||||
to: "/tools",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -148,9 +148,7 @@ describe("user should be able to create an item and add an attachment", () => {
|
||||
{
|
||||
const { response, data } = await api.items.maintenance.getLog(item.id);
|
||||
expect(response.status).toBe(200);
|
||||
expect(data.entries).toHaveLength(maintenanceEntries.length);
|
||||
expect(data.costAverage).toBeGreaterThan(0);
|
||||
expect(data.costTotal).toBeGreaterThan(0);
|
||||
expect(data).toHaveLength(maintenanceEntries.length);
|
||||
}
|
||||
|
||||
cleanup();
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {
|
||||
MaintenanceEntryCreate,
|
||||
MaintenanceEntryWithDetails,
|
||||
} from "../types/data-contracts";
|
||||
import type { AttachmentTypes, PaginationResult } from "../types/non-generated";
|
||||
import type { AttachmentTypes, ItemSummaryPaginationResult } from "../types/non-generated";
|
||||
import type { MaintenanceFilters } from "./maintenance.ts";
|
||||
import type { Requests } from "~~/lib/requests";
|
||||
|
||||
@@ -98,7 +98,7 @@ export class ItemsApi extends BaseAPI {
|
||||
}
|
||||
|
||||
getAll(q: ItemsQuery = {}) {
|
||||
return this.http.get<PaginationResult<ItemSummary>>({ url: route("/items", q) });
|
||||
return this.http.get<ItemSummaryPaginationResult<ItemSummary>>({ url: route("/items", q) });
|
||||
}
|
||||
|
||||
create(item: ItemCreate) {
|
||||
|
||||
@@ -16,3 +16,7 @@ export interface PaginationResult<T> {
|
||||
pageSize: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface ItemSummaryPaginationResult<T> extends PaginationResult<T> {
|
||||
totalPrice: number;
|
||||
}
|
||||
|
||||
52
frontend/locales/da-DK.json
Normal file
52
frontend/locales/da-DK.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"components": {
|
||||
"global": {
|
||||
"password_score": {
|
||||
"password_strength": "Adgangskodestyrke"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"photo_button": "Foto 📷",
|
||||
"title": "Opret genstand"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"card": "Kort",
|
||||
"items": "Genstande",
|
||||
"no_items": "Ingen genstande at vise",
|
||||
"table": "Tabel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"title": "Opret label"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"title": "Opret lokation"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Ingen tilgængelige lokationer. Opret nye lokationer gennem\n`<`span class=\"link-primary\">`Opret`<`/span`>` knappen i navigationslinjen."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"confirm": "Bekræft",
|
||||
"create": "Opret",
|
||||
"create_and_add": "Opret og tilføj ny",
|
||||
"created": "Oprettet",
|
||||
"email": "Email",
|
||||
"follow_dev": "Følg udvikleren",
|
||||
"github": "GitHub projekt"
|
||||
},
|
||||
"tools": {
|
||||
"import_export": "Importer/Eksporter",
|
||||
"reports": "Rapporter",
|
||||
"reports_set": {
|
||||
"bill_of_materials": "Stykliste"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,30 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} ago",
|
||||
"days": "days",
|
||||
"hour": "hour",
|
||||
"hours": "hours",
|
||||
"in": "in {0}",
|
||||
"just-now": "just now",
|
||||
"last-month": "last month",
|
||||
"last-week": "last week",
|
||||
"last-year": "last year",
|
||||
"minute": "minute",
|
||||
"minutes": "minutes",
|
||||
"months": "months",
|
||||
"next-month": "next month",
|
||||
"next-week": "next week",
|
||||
"next-year": "next year",
|
||||
"second": "second",
|
||||
"seconds": "seconds",
|
||||
"tomorrow": "tomorrow",
|
||||
"week": "week",
|
||||
"weeks": "weeks",
|
||||
"years": "years",
|
||||
"yesterday": "yesterday"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Page URL"
|
||||
},
|
||||
@@ -18,6 +42,8 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Item Description",
|
||||
"item_name": "Item Name",
|
||||
"photo_button": "Photo 📷",
|
||||
"title": "Create Item"
|
||||
},
|
||||
@@ -27,29 +53,45 @@
|
||||
"items": "Items",
|
||||
"no_items": "No Items to Display",
|
||||
"table": "Table"
|
||||
},
|
||||
"table": {
|
||||
"page": "Page",
|
||||
"rows_per_page": "Rows per page"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Label Description",
|
||||
"label_name": "Label Name",
|
||||
"title": "Create Label"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Location Description",
|
||||
"location_name": "Location Name",
|
||||
"title": "Create Location"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Parent Location"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "No locations available. Add new locations through the\n `<`span class=\"link-primary\"`>`Create`<`/span`>` button on the navigation bar."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Add",
|
||||
"build": "Build: { build }",
|
||||
"confirm": "Confirm",
|
||||
"create": "Create",
|
||||
"create_and_add": "Create and Add Another",
|
||||
"created": "Created",
|
||||
"delete": "Delete",
|
||||
"details": "Details",
|
||||
"duplicate": "Duplicate",
|
||||
"edit": "Edit",
|
||||
"email": "Email",
|
||||
"follow_dev": "Follow the Developer",
|
||||
"github": "GitHub Project",
|
||||
@@ -57,15 +99,29 @@
|
||||
"join_discord": "Join the Discord",
|
||||
"labels": "Labels",
|
||||
"locations": "Locations",
|
||||
"maintenance": "Maintenance",
|
||||
"name": "Name",
|
||||
"password": "Password",
|
||||
"read_docs": "Read the Docs",
|
||||
"save": "Save",
|
||||
"search": "Search",
|
||||
"sign_out": "Sign Out",
|
||||
"submit": "Submit",
|
||||
"update": "Update",
|
||||
"value": "Value",
|
||||
"version": "Version: { version }",
|
||||
"welcome": "Welcome, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Labels",
|
||||
"quick_statistics": "Quick Statistics",
|
||||
"recently_added": "Recently Added",
|
||||
"storage_locations": "Storage Locations",
|
||||
"total_items": "Total Items",
|
||||
"total_labels": "Total Labels",
|
||||
"total_locations": "Total Locations",
|
||||
"total_value": "Total Value"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registration Disabled",
|
||||
"dont_join_group": "Don't want to join a group?",
|
||||
@@ -80,32 +136,71 @@
|
||||
},
|
||||
"items": {
|
||||
"add": "Add",
|
||||
"advanced": "Advanced",
|
||||
"archived": "Archived",
|
||||
"asset_id": "Asset ID",
|
||||
"attachment": "Attachment",
|
||||
"attachments": "Attachments",
|
||||
"changes_persisted_immediately": "Changes to attachments will be saved immediately",
|
||||
"created_at": "Created At",
|
||||
"custom_fields": "Custom Fields",
|
||||
"description": "Description",
|
||||
"details": "Details",
|
||||
"drag_and_drop": "Drag and drop files here or click to select files",
|
||||
"edit_details": "Edit Details",
|
||||
"field_selector": "Field Selector",
|
||||
"field_value": "Field Value",
|
||||
"first": "First",
|
||||
"include_archive": "Include Archived Items",
|
||||
"insured": "Insured",
|
||||
"last": "Last",
|
||||
"lifetime_warranty": "Lifetime Warranty",
|
||||
"location": "Location",
|
||||
"manual": "Manual",
|
||||
"manuals": "Manuals",
|
||||
"manufacturer": "Manufacturer",
|
||||
"model_number": "Model Number",
|
||||
"name": "Name",
|
||||
"negate_labels": "Negate Selected Labels",
|
||||
"next_page": "Next Page",
|
||||
"no_results": "No Items Found",
|
||||
"notes": "Notes",
|
||||
"options": "Options",
|
||||
"order_by": "Order By",
|
||||
"pages": "Page { page } of { totalPages }",
|
||||
"parent_item": "Parent Item",
|
||||
"photo": "Photo",
|
||||
"photos": "Photos",
|
||||
"prev_page": "Previous Page",
|
||||
"purchase_date": "Purchase Date",
|
||||
"purchase_details": "Purchase Details",
|
||||
"purchase_price": "Purchase Price",
|
||||
"purchased_from": "Purchased From",
|
||||
"quantity": "Quantity",
|
||||
"query_id": "Querying Asset ID Number: { id }",
|
||||
"receipt": "Receipt",
|
||||
"receipts": "Receipts",
|
||||
"reset_search": "Reset Search",
|
||||
"results": "{ total } Results",
|
||||
"serial_number": "Serial Number",
|
||||
"show_advanced_view_options": "Show Advanced View Options",
|
||||
"sold_at": "Sold At",
|
||||
"sold_details": "Sold Details",
|
||||
"sold_price": "Sold Price",
|
||||
"sold_to": "Sold To",
|
||||
"tip_1": "Location and label filters use the 'OR' operation. If more than one is selected only one will be\n required for a match.",
|
||||
"tip_2": "Searches prefixed with '#'' will query for a asset ID (example '#000-001')",
|
||||
"tip_3": "Field filters use the 'OR' operation. If more than one is selected only one will be required for a\n match.",
|
||||
"tips": "Tips",
|
||||
"tips_sub": "Search Tips",
|
||||
"updated_at": "Updated At"
|
||||
"updated_at": "Updated At",
|
||||
"warranty": "Warranty",
|
||||
"warranty_details": "Warranty Details",
|
||||
"warranty_expires": "Warranty Expires"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "No Labels Found"
|
||||
"no_results": "No Labels Found",
|
||||
"update_label": "Update Label"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalan",
|
||||
@@ -115,20 +210,26 @@
|
||||
"fr": "French",
|
||||
"hu": "Hungarian",
|
||||
"it": "Italian",
|
||||
"ja-JP": "Japanese",
|
||||
"nl": "Dutch",
|
||||
"pl": "Polish",
|
||||
"pt-BR": "Portuguese (Brazil)",
|
||||
"pt-PT": "Portuguese (Portugal)",
|
||||
"ru": "Russian",
|
||||
"sl": "Slovenian",
|
||||
"sv": "Swedish",
|
||||
"tr": "Turkish",
|
||||
"uk-UA": "Ukrainian",
|
||||
"zh-CN": "Chinese (Simplified)",
|
||||
"zh-HK": "Chinese (Hong Kong)",
|
||||
"zh-MO": "Chinese (Macau)",
|
||||
"zh-TW": "Chinese (Traditional)"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "No Locations Found"
|
||||
"child_locations": "Child Locations",
|
||||
"collapse_tree": "Collapse Tree",
|
||||
"no_results": "No Locations Found",
|
||||
"update_location": "Update Location"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
@@ -137,12 +238,12 @@
|
||||
"scheduled": "Scheduled"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Complete",
|
||||
"create_first": "Create Your First Entry",
|
||||
"delete": "Delete",
|
||||
"duplicate": "Duplicate",
|
||||
"edit": "Edit",
|
||||
"new": "New",
|
||||
"complete": "Complete",
|
||||
"duplicate" : "Duplicate"
|
||||
"new": "New"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Completed Date",
|
||||
@@ -166,6 +267,9 @@
|
||||
"total_entries": "Total Entries"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Item / Asset",
|
||||
"create_label": "Label",
|
||||
"create_location": "Location",
|
||||
"home": "Home",
|
||||
"locations": "Locations",
|
||||
"maintenance": "Maintenance",
|
||||
@@ -182,6 +286,7 @@
|
||||
"delete_account_sub": "Delete your account and all its associated data. This can not be undone.",
|
||||
"display_header": "{ currentValue, select, true {Hide Header} false {Show Header} other {Not Hit}}",
|
||||
"enabled": "Enabled",
|
||||
"example": "Example",
|
||||
"gen_invite": "Generate Invite Link",
|
||||
"group_settings": "Group Settings",
|
||||
"group_settings_sub": "Shared Group Settings. You may need to refresh your browser for some settings to apply.",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Se ha modificado el comportamiento de las importaciones con import_refs existentes. Si existe una import_ref en el archivo CSV, el \nelemento se actualizará con los valores del archivo CSV.",
|
||||
"change_warning": "Se ha modificado el comportamiento de las importaciones con import_refs existentes. Si existe una import_ref en el archivo CSV, el\nelemento se actualizará con los valores del archivo CSV.",
|
||||
"description": "Importa un archivo CSV que contenga tus elementos, etiquetas y ubicaciones. Consulta la documentación para obtener más información sobre el \nformato requerido.",
|
||||
"title": "Importar Archivo CSV",
|
||||
"upload": "Subir"
|
||||
@@ -38,6 +38,9 @@
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"title": "Crear Ubicación"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "No hay ubicaciones disponibles. Añade nuevas ubicaciones mediante el botón de\n`<`span class=\"link-primary\"`>`Crear`<`/span`>` en la barra de navegación."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -101,6 +104,9 @@
|
||||
"tips_sub": "Sugerencias de Búsqueda",
|
||||
"updated_at": "Actualizado El"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Etiquetas No Encontradas"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalán",
|
||||
"de": "Alemán",
|
||||
@@ -121,6 +127,52 @@
|
||||
"zh-MO": "Chino (Macao)",
|
||||
"zh-TW": "Chino (Tradicional)"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Ubicaciones No Encontradas"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Ambos",
|
||||
"completed": "Completado",
|
||||
"scheduled": "Programado"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Completar",
|
||||
"create_first": "Crea Tu Primera Entrada",
|
||||
"delete": "Eliminar",
|
||||
"duplicate": "Duplicar",
|
||||
"edit": "Editar",
|
||||
"new": "Nuevo"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Fecha Completado",
|
||||
"cost": "Coste",
|
||||
"delete_confirmation": "¿Seguro que quieres borrar esta entrada?",
|
||||
"edit_action": "Actualizar",
|
||||
"edit_title": "Editar Entrada",
|
||||
"entry_name": "Nombre de Entrada",
|
||||
"new_action": "Crear",
|
||||
"new_title": "Nueva Entrada",
|
||||
"notes": "Notas",
|
||||
"scheduled_date": "Fecha Programada"
|
||||
},
|
||||
"monthly_average": "Promedio Mensual",
|
||||
"toast": {
|
||||
"failed_to_create": "Error al crear la entrada",
|
||||
"failed_to_delete": "Error al eliminar la entrada",
|
||||
"failed_to_update": "Error al actualizar la entrada"
|
||||
},
|
||||
"total_cost": "Coste Total",
|
||||
"total_entries": "Total de Entradas"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Inicio",
|
||||
"locations": "Ubicaciones",
|
||||
"maintenance": "Mantenimiento",
|
||||
"profile": "Perfil",
|
||||
"search": "Buscar",
|
||||
"tools": "Herramientas"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Activo",
|
||||
"change_password": "Cambiar Contraseña",
|
||||
@@ -136,6 +188,7 @@
|
||||
"inactive": "Inactivo",
|
||||
"language": "Idioma",
|
||||
"new_password": "Nueva Contraseña",
|
||||
"no_notifiers": "No hay notificadores configurados",
|
||||
"notifier_modal": "{ type, select, true {Edit} false {Create} other {Other}} Notificación",
|
||||
"notifiers": "Notificaciones",
|
||||
"notifiers_sub": "Recibe notificaciones de los próximos recordatorios de mantenimiento",
|
||||
|
||||
32
frontend/locales/fi-FI.json
Normal file
32
frontend/locales/fi-FI.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"languages": {
|
||||
"pl": "Puola"
|
||||
},
|
||||
"maintenance": {
|
||||
"list": {
|
||||
"complete": "Valmis",
|
||||
"delete": "Poista"
|
||||
},
|
||||
"modal": {
|
||||
"new_action": "Luo"
|
||||
}
|
||||
},
|
||||
"menu": {
|
||||
"home": "Koti"
|
||||
},
|
||||
"profile": {
|
||||
"delete_account": "Poista tili",
|
||||
"test": "Testi"
|
||||
},
|
||||
"tools": {
|
||||
"actions_set": {
|
||||
"set_primary_photo": "Aseta oletuskuva"
|
||||
},
|
||||
"import_export": "Tuo/Vie",
|
||||
"import_export_set": {
|
||||
"export_button": "Vie varasto",
|
||||
"import_button": "Tuo varasto"
|
||||
},
|
||||
"reports": "Raportit"
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Le comportement lors d’importations avec des import_ref existants a changé. Si une valeur pour import_ref est présente dans le fichier CSV, alors l’élément sera mis à jour avec celle-ci.",
|
||||
"description": "Importer un fichier CSV contenant vos articles, étiquettes, et emplacements. Voir la documentation pour plus d’informations sur le format requis.",
|
||||
"change_warning": "Le comportement lors d’importations avec des import_ref existants a changé. Si une valeur pour import_ref est présente dans le \nfichier CSV, alors l’élément sera mis à jour avec celle-ci.",
|
||||
"description": "Importer un fichier CSV contenant vos articles, étiquettes, et emplacements. Voir la documentation pour plus d’informations \nsur le format requis.",
|
||||
"title": "Importer un fichier CSV",
|
||||
"upload": "Téléverser"
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
"title": "Créer un emplacement"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Aucun emplacement disponible. Ajoutez votre premiers emplacements avec le bouton `<`span class=\"link-primary\"`>`Créer`<`/span`>` dans la barre de navigation."
|
||||
"no_locations": "Aucun emplacement disponible. Ajoutez votre premiers emplacements avec\nle bouton `<`span class=\"link-primary\"`>`Créer`<`/span`>` dans la barre de navigation."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -61,7 +61,7 @@
|
||||
"password": "Mot de passe",
|
||||
"read_docs": "Lire la documentation",
|
||||
"search": "Rechercher",
|
||||
"sign_out": "Déconnexion",
|
||||
"sign_out": "Se déconnecter",
|
||||
"submit": "Soumettre",
|
||||
"version": "Version : { version }",
|
||||
"welcome": "Bienvenue, { username }"
|
||||
@@ -142,15 +142,15 @@
|
||||
"delete": "Supprimer",
|
||||
"duplicate": "Dupliquer",
|
||||
"edit": "Modifier",
|
||||
"new": "Ajouter"
|
||||
"new": "Nouveau"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Date d'achèvement",
|
||||
"cost": "Coût",
|
||||
"delete_confirmation": "Êtes-vous certain de vouloir supprimer cette entrée ?",
|
||||
"edit_action": "Modifier",
|
||||
"edit_action": "Mettre à jour",
|
||||
"edit_title": "Modifier l'entrée",
|
||||
"entry_name": "Nom",
|
||||
"entry_name": "Nom de l’entrée",
|
||||
"new_action": "Créer",
|
||||
"new_title": "Nouvelle entrée",
|
||||
"notes": "Notes",
|
||||
@@ -191,7 +191,7 @@
|
||||
"no_notifiers": "Aucune notification configurée",
|
||||
"notifier_modal": "Notifications { type, select, true {Edit} false {Create} other {Other}}",
|
||||
"notifiers": "Notifications",
|
||||
"notifiers_sub": "Recevez des notifications pour vous prévenir des prochaines maintenances.",
|
||||
"notifiers_sub": "Recevez des notifications pour vous prévenir des prochaines maintenances",
|
||||
"test": "Test",
|
||||
"theme_settings": "Paramètres du thème",
|
||||
"theme_settings_sub": "Les paramètres du thème sont stockés dans le navigateur. Vous pouvez les changer à tout moment. Si vous\nrencontrez des problèmes, il est conseillé de rafraichir la page.",
|
||||
@@ -214,7 +214,8 @@
|
||||
"set_primary_photo_button": "Définir la photo principale",
|
||||
"set_primary_photo_sub": "Dans la version v0.10.0 d'Homebox, le champ d'image principal à été ajouté aux pièces jointes de type photo. Cette action définira en tant qu'image principale toute première image en pièce jointe déjà présente en base de donnée, si le champ n'est pas déjà défini. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Voir GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Remettre à zéro les dates et heures",
|
||||
"zero_datetimes_button": "Remettre à zéro les dates et heures"
|
||||
"zero_datetimes_button": "Remettre à zéro les dates et heures",
|
||||
"zero_datetimes_sub": "Réinitialise la valeur de tous les champs date/heure de votre inventaire à la date de début. Il s'agit de corriger une anomalie introduite au début du développement du site qui entraînait le stockage de la valeur temporelle avec l'heure, ce qui provoquait des problèmes avec les champs de date affichant des valeurs précises. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Voir le rapport 236 de Github pour plus de détails.'</a> '"
|
||||
},
|
||||
"actions_sub": "Appliquer des actions en masse à votre inventaire. Ces actions sont irréversibles. '<b>'Soyez vigilant.'</b>'",
|
||||
"import_export": "Importer/Exporter",
|
||||
@@ -224,13 +225,13 @@
|
||||
"export_sub": "Exporte l'inventaire au format CSV Homebox. Cela exportera l'intégralité de votre inventaire.",
|
||||
"import": "Importer l'inventaire",
|
||||
"import_button": "Importer l'inventaire",
|
||||
"import_sub": "Importer un fichier CSV au format Homebox. Sans la colonne '<code>'HB.import_ref'</code>' , cela '<b>'n'écrasera pas'</b>' d'éléments de votre inventaire actuel, seuls les nouveaux éléments seront importés. Les lignes contenant une colonne '<code>'HB.import_ref'</code>' seront fusionnées avec les éléments existants comportant le même '<code>'HB.import_ref'</code>', si existant."
|
||||
"import_sub": "Importer un fichier CSV au format Homebox. Sans la colonne '<code>'HB.import_ref'</code>' , cela '<b>'n'écrasera pas'</b>' d'éléments de votre inventaire actuel, seuls les nouveaux éléments seront importés. Les lignes contenant une colonne '<code>'HB.import_ref'</code>' seront fusionnées avec les éléments existants comportant le même import_ref, si existant."
|
||||
},
|
||||
"import_export_sub": "Importez et exportez votre inventaire vers et depuis un fichier CSV",
|
||||
"import_export_sub": "Importez et exportez votre inventaire vers et depuis un fichier CSV. Ceci est utile pour migrer votre inventaire vers une nouvelle instance de Homebox.",
|
||||
"reports": "Rapports",
|
||||
"reports_set": {
|
||||
"asset_labels": "Étiquettes d’identifiant d’actif",
|
||||
"asset_labels_button": "Générateur d’étiquettes",
|
||||
"asset_labels_button": "Générateur d'étiquettes",
|
||||
"asset_labels_sub": "Génère un fichier PDF imprimable pour une plage d'identifiants d'actifs. Ils ne sont pas spécifiques à votre inventaire donc vous pouvez les imprimer en avance et les appliquer à votre inventaire par la suite.",
|
||||
"bill_of_materials": "Nomenclature",
|
||||
"bill_of_materials_button": "Générer une nomenclature",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Il comportamento per le importazioni con import_ref esistenti è cambiato. Se un import_ref è presente nel file CSV,\n l'elemento verrà aggiornato con i valori presenti nel file CSV.",
|
||||
"description": "Importa un file CSV contenente gli oggetti, le etichette e le posizioni. Vedi la documentazione per ulteriori informazioni sul \nformato richiesto.",
|
||||
"change_warning": "Il comportamento per le importazioni con import_ref esistenti è cambiato. Se un import_ref è presente nel file CSV,\n l'articolo verrà aggiornato con i valori presenti nel file CSV.",
|
||||
"description": "Importa un file CSV contenente gli articoli, le etichette e le posizioni. Vedi la documentazione per ulteriori informazioni sul \nformato richiesto.",
|
||||
"title": "Importa File CSV",
|
||||
"upload": "Carica"
|
||||
}
|
||||
@@ -19,13 +19,13 @@
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"photo_button": "Foto 📷",
|
||||
"title": "Crea Oggetto"
|
||||
"title": "Crea Articolo"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"card": "Scheda",
|
||||
"items": "Oggetti",
|
||||
"no_items": "Nessun Oggetto da Visualizzare",
|
||||
"items": "Articoli",
|
||||
"no_items": "Nessun Articolo da Visualizzare",
|
||||
"table": "Tabella"
|
||||
}
|
||||
}
|
||||
@@ -82,8 +82,8 @@
|
||||
"add": "Aggiungi",
|
||||
"created_at": "Creato Il",
|
||||
"custom_fields": "Campi Personalizzati",
|
||||
"field_selector": "Selettore di Campo",
|
||||
"field_value": "Valore del Campo",
|
||||
"field_selector": "Campo Selezione",
|
||||
"field_value": "Campo valore",
|
||||
"first": "Primo",
|
||||
"include_archive": "Includi Articoli Archiviati",
|
||||
"last": "Ultimo",
|
||||
@@ -137,7 +137,7 @@
|
||||
"scheduled": "Pianificato"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Conferma",
|
||||
"complete": "Completa",
|
||||
"create_first": "Crea la tua prima voce",
|
||||
"delete": "Elimina",
|
||||
"duplicate": "Duplicare",
|
||||
@@ -163,7 +163,15 @@
|
||||
"failed_to_update": "Impossibile aggiornare la voce"
|
||||
},
|
||||
"total_cost": "Costo totale",
|
||||
"total_entries": "Iscrizioni totali"
|
||||
"total_entries": "Voci totali"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Home",
|
||||
"locations": "Posizioni",
|
||||
"maintenance": "Manutenzione",
|
||||
"profile": "Profilo",
|
||||
"search": "Cerca",
|
||||
"tools": "Strumenti"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Attivo",
|
||||
@@ -180,6 +188,7 @@
|
||||
"inactive": "Inattivo",
|
||||
"language": "Lingua",
|
||||
"new_password": "Nuova Password",
|
||||
"no_notifiers": "Nessun notificatore configurato",
|
||||
"notifier_modal": "{ type, select, true {Modifica} false {Crea} other {Altro}} Notifier",
|
||||
"notifiers": "Notifiche",
|
||||
"notifiers_sub": "Ricevi notifiche per i prossimi promemoria di manutenzione",
|
||||
@@ -197,15 +206,15 @@
|
||||
"actions_set": {
|
||||
"ensure_ids": "Verifica ID delle risorse",
|
||||
"ensure_ids_button": "Verifica ID delle risorse",
|
||||
"ensure_ids_sub": "Garantisce che tutti gli articoli nel tuo inventario abbiano un campo asset_id valido. Questo viene fatto trovando il campo asset_id corrente più alto nel database e applicando il valore successivo a ogni elemento che ha un campo asset_id non impostato. Questo viene fatto per il campo created_at.",
|
||||
"ensure_ids_sub": "Garantisce che tutti gli articoli nel tuo inventario abbiano un campo asset_id valido. Questo viene fatto trovando il campo asset_id corrente più alto nel database e applicando il valore successivo a ogni articolo che ha un campo asset_id non impostato. Questo viene fatto per il campo created_at.",
|
||||
"ensure_import_refs": "Verifica riferimenti di importazione",
|
||||
"ensure_import_refs_button": "Verifica riferimenti di importazione",
|
||||
"ensure_import_refs_sub": "Verifica che tutti gli articoli nel tuo inventario abbiano un campo import_ref valido. Questo viene fatto generando in modo casuale una stringa di 8 caratteri per ogni elemento che ha un campo import_ref non impostato.",
|
||||
"ensure_import_refs_sub": "Verifica che tutti gli articoli nel tuo inventario abbiano un campo import_ref valido. Questo viene fatto generando in modo casuale una stringa di 8 caratteri per ogni articolo che ha un campo import_ref non impostato.",
|
||||
"set_primary_photo": "Imposta foto principale",
|
||||
"set_primary_photo_button": "Imposta immagine principale",
|
||||
"set_primary_photo_sub": "Nella versione v0.10.0 di Homebox, il campo immagine principale è stato aggiunto agli allegati di tipo foto. Questa azione imposterà il campo immagine principale alla prima immagine nella matrice allegati nel database, se non è già impostato. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Vedi GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Azzera Data e Orario oggetti",
|
||||
"zero_datetimes_button": "Azzera Date e Ora articoli",
|
||||
"zero_datetimes": "Azzera Data e Orario articolo",
|
||||
"zero_datetimes_button": "Azzera Date e Ora articolo",
|
||||
"zero_datetimes_sub": "Reimposta il valore dell'ora per tutti i campi data e ora dell'inventario all'inizio della data. Questo è per correggere un bug che è stato introdotto all'inizio dello sviluppo del sito che ha causato il valore di orario memorizzato con il tempo che ha causato problemi con i campi data visualizzazione dei valori esatti. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Vedi Github Issue #236 per maggiori dettagli.'</a>'"
|
||||
},
|
||||
"actions_sub": "Applica Azioni massive al tuo inventario. Questo sono azioni irreversibili. '<b>'Presta attenzione.'</b>'",
|
||||
@@ -213,10 +222,10 @@
|
||||
"import_export_set": {
|
||||
"export": "Esporta Inventario",
|
||||
"export_button": "Esporta Inventario",
|
||||
"export_sub": "Esporta il formato CSV standard per Homebox. Questo esporterà tutti gli oggetti del tuo inventario.",
|
||||
"export_sub": "Esporta il formato CSV standard per Homebox. Questo esporterà tutti gli articoli del tuo inventario.",
|
||||
"import": "Importa Inventario",
|
||||
"import_button": "Importa Inventario",
|
||||
"import_sub": "Importa il formato CSV standard per Homebox. Senza una colonna '<code>'HB.import_ref'</code>' questo '<b>'non'</b>' sovrascriverà gli oggetti esistenti nel tuo inventario, aggiungerà solamente nuovi oggetti. Le righe con una colonna '<code>'HB.import_ref'</code>' saranno unite agli oggetti esistenti con lo stesso import_ref, se presente."
|
||||
"import_sub": "Importa il formato CSV standard per Homebox. Senza una colonna '<code>'HB.import_ref'</code>' questo '<b>'non'</b>' sovrascriverà gli articoli esistenti nel tuo inventario, aggiungerà solamente nuovi articoli. Le righe con una colonna '<code>'HB.import_ref'</code>' saranno unite agli articoli esistenti con lo stesso import_ref, se presente."
|
||||
},
|
||||
"import_export_sub": "Importa ed esporta il tuo inventario da e verso un file CSV. Questo è utile per migrare il tuo inventario verso una nuova istanza di Homebox.",
|
||||
"reports": "Rapporti",
|
||||
@@ -226,7 +235,7 @@
|
||||
"asset_labels_sub": "Genera una etichetta PDF stampabile per un gruppo di ID Risorsa. Le etichette non sono specifiche per il tuo inventario così puoi stamparle in anticipo ed applicarle al tuo inventario quando lo ricevi.",
|
||||
"bill_of_materials": "Distinta base",
|
||||
"bill_of_materials_button": "Genera BOM",
|
||||
"bill_of_materials_sub": "Genera un file CSV (Comma Separated Values) che può essere importato in un foglio di calcolo. Questo è un sommario del tuo inventario con informazioni di base su oggetto e prezzo."
|
||||
"bill_of_materials_sub": "Genera un file CSV (Valori Separati dalla Virgola) che può essere importato in un foglio di calcolo. Questo è un sommario del tuo inventario con informazioni di base su articoli e prezzi."
|
||||
},
|
||||
"reports_sub": "Genera diversi report per il tuo inventario."
|
||||
}
|
||||
|
||||
98
frontend/locales/ja-JP.json
Normal file
98
frontend/locales/ja-JP.json
Normal file
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "既存のimport_refsを使用したインポートの動作が変更されました",
|
||||
"upload": "アップロード"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"page_qr_code": {
|
||||
"page_url": "ページ URL"
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "パスワード強度"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"photo_button": "写真📷"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"card": "カード",
|
||||
"items": "アイテム",
|
||||
"table": "テーブル"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"title": "ラベルを作成"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"title": "ロケーションを生産する"
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"build": "ビルド: { build }",
|
||||
"email": "メール",
|
||||
"github": "GitHub プロジェクト",
|
||||
"items": "アイテム",
|
||||
"labels": "ラベル",
|
||||
"locations": "ロケーション",
|
||||
"name": "名前",
|
||||
"password": "パスワード",
|
||||
"read_docs": "ドキュメントを読む",
|
||||
"search": "サーチ"
|
||||
},
|
||||
"index": {
|
||||
"login": "ログイン",
|
||||
"set_email": "メールは何ですか?",
|
||||
"set_name": "お名前は何ですか?"
|
||||
},
|
||||
"items": {
|
||||
"add": "足す",
|
||||
"next_page": "次の ページ",
|
||||
"prev_page": "先のページ"
|
||||
},
|
||||
"languages": {
|
||||
"en": "英語",
|
||||
"es": "スペイン語",
|
||||
"fr": "フランス語",
|
||||
"hu": "ハンガリー語",
|
||||
"it": "イタリア語",
|
||||
"nl": "オランダ語",
|
||||
"pl": "ポーランド語",
|
||||
"pt-BR": "ポルトガル語 (ブラジル)",
|
||||
"ru": "ロシア語",
|
||||
"sl": "スロベニア語",
|
||||
"sv": "スウェーデン語",
|
||||
"tr": "トルコ語"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "両方"
|
||||
},
|
||||
"modal": {
|
||||
"notes": "ノート"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"language": "言語",
|
||||
"test": "テスト",
|
||||
"url": "URL"
|
||||
},
|
||||
"tools": {
|
||||
"reports": "レポート",
|
||||
"reports_set": {
|
||||
"asset_labels": "アセット ID ラベル",
|
||||
"asset_labels_button": "レベルを生成する",
|
||||
"bill_of_materials": "部品表",
|
||||
"bill_of_materials_button": "部品表を生成する"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,30 @@
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} geleden",
|
||||
"days": "dagen",
|
||||
"hour": "uur",
|
||||
"hours": "uren",
|
||||
"in": "in {0}",
|
||||
"just-now": "zojuist",
|
||||
"last-month": "afgelopen maand",
|
||||
"last-week": "vorige week",
|
||||
"last-year": "afgelopen jaar",
|
||||
"minute": "minuut",
|
||||
"minutes": "minuten",
|
||||
"months": "maanden",
|
||||
"next-month": "volgende maand",
|
||||
"next-week": "volgende week",
|
||||
"next-year": "volgend jaar",
|
||||
"second": "seconde",
|
||||
"seconds": "seconden",
|
||||
"tomorrow": "morgen",
|
||||
"week": "week",
|
||||
"weeks": "weken",
|
||||
"years": "jaren",
|
||||
"yesterday": "gisteren"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Pagina URL"
|
||||
},
|
||||
@@ -18,6 +42,8 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Artikelomschrijving",
|
||||
"item_name": "Artikelnaam",
|
||||
"photo_button": "Foto 📷",
|
||||
"title": "Maak object"
|
||||
},
|
||||
@@ -27,26 +53,45 @@
|
||||
"items": "Objecten",
|
||||
"no_items": "Geen objecten om te tonen",
|
||||
"table": "Tabel"
|
||||
},
|
||||
"table": {
|
||||
"page": "Pagina",
|
||||
"rows_per_page": "Rijen per pagina"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "label beschrijving",
|
||||
"label_name": "label naam",
|
||||
"title": "Maak label"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Locatie omschrijving",
|
||||
"location_name": "Locatie",
|
||||
"title": "Maak locatie"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Hoofd locatie"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Geen locaties beschikbaar. Voeg een nieuwe locatie toe\n via de `<`span class=\"link-primary\"`>`Creeer`<`/span`> knop op het navigatie menu."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Toevoegen",
|
||||
"build": "Bouw: { build }",
|
||||
"confirm": "Bevestigen",
|
||||
"create": "Maken",
|
||||
"create_and_add": "Maak en voeg nog een toe",
|
||||
"created": "Gemaakt",
|
||||
"delete": "Verwijderen",
|
||||
"details": "Details",
|
||||
"duplicate": "Dubbel",
|
||||
"edit": "Bewerk",
|
||||
"email": "E-mail",
|
||||
"follow_dev": "Volg de ontwikkelaar",
|
||||
"github": "GitHub Project",
|
||||
@@ -54,15 +99,29 @@
|
||||
"join_discord": "Sluit je aan bij de Discord",
|
||||
"labels": "etiketten",
|
||||
"locations": "Locaties",
|
||||
"maintenance": "Onderhoud",
|
||||
"name": "Naam",
|
||||
"password": "Wachtwoord",
|
||||
"read_docs": "Lees de documentatie",
|
||||
"save": "Opslaan",
|
||||
"search": "Zoeken",
|
||||
"sign_out": "Log uit",
|
||||
"submit": "Indienen",
|
||||
"update": "Bijwerken",
|
||||
"value": "Waarde",
|
||||
"version": "Versie: { version }",
|
||||
"welcome": "Welkom, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "etiketten",
|
||||
"quick_statistics": "Snelle statistieken",
|
||||
"recently_added": "Recent toegevoegd",
|
||||
"storage_locations": "Verblijfplaatsen",
|
||||
"total_items": "Totale items",
|
||||
"total_labels": "Totaal aantal labels",
|
||||
"total_locations": "Totaal aantal locaties",
|
||||
"total_value": "Totale Waarde"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registratie uitgeschakeld",
|
||||
"dont_join_group": "Wil je niet aan een groep deelnemen?",
|
||||
@@ -77,32 +136,71 @@
|
||||
},
|
||||
"items": {
|
||||
"add": "Toevoegen",
|
||||
"advanced": "Geavanceerd",
|
||||
"archived": "Is gearchiveerd",
|
||||
"asset_id": "Artikel ID",
|
||||
"attachment": "Bijlage",
|
||||
"attachments": "Bijlagen",
|
||||
"changes_persisted_immediately": "Gewijzigde bijlagen worden direct opgeslagen",
|
||||
"created_at": "Aangemaakt op",
|
||||
"custom_fields": "Aangepaste velden",
|
||||
"description": "Beschrijving",
|
||||
"details": "Details",
|
||||
"drag_and_drop": "Sleep bestanden hierheen en zet ze neer of klik om bestanden te selecteren",
|
||||
"edit_details": "Details bewerken",
|
||||
"field_selector": "Veld selectie",
|
||||
"field_value": "Veldwaarde",
|
||||
"first": "Eerst",
|
||||
"include_archive": "Inclusief gearchiveerde items",
|
||||
"insured": "Verzekerde",
|
||||
"last": "Achternaam",
|
||||
"lifetime_warranty": "Levenslange garantie",
|
||||
"location": "Locatie",
|
||||
"manual": "Handmatig",
|
||||
"manuals": "Handleidingen",
|
||||
"manufacturer": "Fabrikant",
|
||||
"model_number": "Modelnummer",
|
||||
"name": "Naam",
|
||||
"negate_labels": "Negeer Geselecteerde Etiketten",
|
||||
"next_page": "Volgende pagina",
|
||||
"no_results": "Geen Items Gevonden",
|
||||
"notes": "Opmerkingen",
|
||||
"options": "Opties",
|
||||
"order_by": "Sorteren op",
|
||||
"pages": "Pagina { page } van { totalPages }",
|
||||
"parent_item": "Hoofd Item",
|
||||
"photo": "Foto",
|
||||
"photos": "Foto's",
|
||||
"prev_page": "Vorige pagina",
|
||||
"purchase_date": "Aankoopdatum",
|
||||
"purchase_details": "Aankoopdetails",
|
||||
"purchase_price": "Aankoopprijs",
|
||||
"purchased_from": "Gekocht van",
|
||||
"quantity": "Aantal",
|
||||
"query_id": "ID-nummer van object opvragen: { id }",
|
||||
"receipt": "Bewijs",
|
||||
"receipts": "Bonnetjes",
|
||||
"reset_search": "Reset Zoeken",
|
||||
"results": "{ total } Resultaten",
|
||||
"serial_number": "Serienummer",
|
||||
"show_advanced_view_options": "geavanceerde opties weergeven",
|
||||
"sold_at": "Verkocht bij",
|
||||
"sold_details": "Verkochte details",
|
||||
"sold_price": "Verkoopprijs",
|
||||
"sold_to": "Verkocht Aan",
|
||||
"tip_1": "Locatie- en labelfilters gebruiken de 'OF' -werking. Als er meer dan een is geselecteerd,\nis er maar een nodig voor een overeenkomst.",
|
||||
"tip_2": "Zoekopdrachten voorafgegaan door '#'' zullen om een object-ID vragen (bijvoorbeeld '#000-001')",
|
||||
"tip_3": "Veldfilters gebruiken de 'OF' -bewerking. Indien meer dan 1 is geselecteerd\nzal er maar 1 nodig zijn voor een match.",
|
||||
"tips": "Tips",
|
||||
"tips_sub": "Zoektips",
|
||||
"updated_at": "Bijgewerkt op"
|
||||
"updated_at": "Bijgewerkt op",
|
||||
"warranty": "Garantie",
|
||||
"warranty_details": "Garantiedetails",
|
||||
"warranty_expires": "Garantie vervalt"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Geen labels gevonden"
|
||||
"no_results": "Geen labels gevonden",
|
||||
"update_label": "Etiket bijwerken"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalaans",
|
||||
@@ -112,20 +210,26 @@
|
||||
"fr": "Frans",
|
||||
"hu": "Hongaars",
|
||||
"it": "Italiaans",
|
||||
"ja-JP": "Japans",
|
||||
"nl": "Nederlands",
|
||||
"pl": "Pools",
|
||||
"pt-BR": "Portugees (Brazilië)",
|
||||
"pt-PT": "Portugees (Portugal)",
|
||||
"ru": "Russisch",
|
||||
"sl": "Sloveens",
|
||||
"sv": "Zweeds",
|
||||
"tr": "Turks",
|
||||
"uk-UA": "Oekraïens",
|
||||
"zh-CN": "Chinees (vereenvoudigd)",
|
||||
"zh-HK": "Chinees (Hong Kong)",
|
||||
"zh-MO": "Chinees (Macau)",
|
||||
"zh-TW": "Chinees (traditioneel)"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Geen locaties gevonden"
|
||||
"child_locations": "Kind Locaties",
|
||||
"collapse_tree": "Structuur invouwen",
|
||||
"no_results": "Geen locaties gevonden",
|
||||
"update_location": "Locatie bijwerken"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
@@ -156,13 +260,16 @@
|
||||
"monthly_average": "Maandelijks",
|
||||
"toast": {
|
||||
"failed_to_create": "Kan invoer niet maken",
|
||||
"failed_to_delete": "Kon item niet verwijderen.",
|
||||
"failed_to_delete": "Kon item niet verwijderen",
|
||||
"failed_to_update": "Kan invoer niet bijwerken"
|
||||
},
|
||||
"total_cost": "Totale kosten",
|
||||
"total_entries": "Totaal aantal Inzendingen"
|
||||
},
|
||||
"menu": {
|
||||
"create_item": "Artikel / Object",
|
||||
"create_label": "Label",
|
||||
"create_location": "Locatie",
|
||||
"home": "Home",
|
||||
"locations": "Locaties",
|
||||
"maintenance": "Onderhoud",
|
||||
@@ -177,10 +284,12 @@
|
||||
"current_password": "Huidig Wachtwoord",
|
||||
"delete_account": "Verwijder account",
|
||||
"delete_account_sub": "Verwijder je account en alle geassocieerde data. Deze actie kan niet ongedaan worden.",
|
||||
"display_header": "{ currentValue, select, true {Header verbergen} false {Header weergeven} other {Geen gevonden}}",
|
||||
"enabled": "ingeschakeld",
|
||||
"example": "Voorbeeld",
|
||||
"gen_invite": "Genereer Uitnodigingslink",
|
||||
"group_settings": "Groeps Instellingen",
|
||||
"group_settings_sub": "Gedeelde groepsinstellingen",
|
||||
"group_settings_sub": "Gedeelde groepsinstellingen. Het kan zijn dat je je browser moet verversen om alle instellingen te zien werken.",
|
||||
"inactive": "Inactief",
|
||||
"language": "Taal",
|
||||
"new_password": "Nieuw Wachtwoord",
|
||||
@@ -202,21 +311,26 @@
|
||||
"actions_set": {
|
||||
"ensure_ids": "Zorg voor item-ID's",
|
||||
"ensure_ids_button": "Zorg voor item-ID's",
|
||||
"ensure_ids_sub": "Zorgt ervoor dat alle artikelen in je voorraad een geldig asset_id veld hebben. Dit wordt gedaan door de hoogste huidige asset_id veld in de database te vinden en de volgende waarde toe te passen op het volgende niet ingevoerde asset_id veld. Dit gebeurt op volgorde van het created_at veld.",
|
||||
"ensure_import_refs": "Zorg ervoor dat Import Refs",
|
||||
"ensure_import_refs_button": "Zorg ervoor dat Import Refs",
|
||||
"ensure_import_refs_sub": "Zorgt ervoor dat alle artikelen in je voorraad een geldig import_ref veld hebben. Dit gebeurt door een random 8 karakter string voor elk item te maken die geen import_ref veld heeft.",
|
||||
"set_primary_photo": "Hoofdfoto instellen",
|
||||
"set_primary_photo_button": "Hoofdfoto instellen",
|
||||
"set_primary_photo_sub": "In versie v0.10.0 van Homebox is het primaire afbeeldingsveld toegevoegd aan bijlagen van het type foto. Deze actie zet de primaire afbeelding naar de eerste afbeelding in de database, indien deze nog niet ingesteld is. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Zie GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Nul item Datum Tijden",
|
||||
"zero_datetimes_button": "Nul item Datum Tijden"
|
||||
"zero_datetimes_button": "Nul item Datum Tijden",
|
||||
"zero_datetimes_sub": "Hiermee stelt u de tijdwaarde voor alle datum-/tijdvelden in uw voorraad in op het begin van de datum. Dit is een oplossing voor een fout in de applicatie geïntroduceerd in het begin van de ontwikkeling waarbij de tijd waarde verkeerd werd opgeslagen. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Zie Github Issue #236 voor alle details.'</a>'"
|
||||
},
|
||||
"actions_sub": "Acties bulksgewijs toepassen op je voorraad. Deze zijn onomkeerbaar '<b>'Wees voorzichtig.'</b>'",
|
||||
"import_export": "Importeer/Exporteer",
|
||||
"import_export_set": {
|
||||
"export": "Export voorraad",
|
||||
"export_button": "Export voorraad",
|
||||
"export_sub": "Exporteert het standaard CSV-formaat voor Homebox",
|
||||
"export_sub": "Exporteert het standaard CSV-formaat voor Homebox. Dit exporteert alle items in jouw inventaris.",
|
||||
"import": "Inventaris Importeren",
|
||||
"import_button": "Inventaris Importeren"
|
||||
"import_button": "Inventaris Importeren",
|
||||
"import_sub": "Importeert het standaard CSV-formaat voor Homebox. Zonder een '<code>'HB.import_ref'</code>' kolom zal dit '<b>'geen'</b>' bestaande waardes overschrijven, maar enkel nieuwe items toevoegen. Rijen met een '<code>'HB.import_ref'</code>' kolom zullen samengevoegd worden met bestaande items, als die bestaan."
|
||||
},
|
||||
"import_export_sub": "Importeer en exporteer je voorraad van en naar een CSV-bestand. Dit is handig voor het migreren van je voorraad naar een nieuwe HomeBox installatie.",
|
||||
"reports": "Rapportages",
|
||||
|
||||
@@ -2,13 +2,36 @@
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Zachowanie przy imporcie z istniejącymi import_ref zostało zmienione. Jeśli import_ref jest obecny w pliku CSV, \nprzedmiot zostanie zaktualizowany zgodnie z wartościami w pliku CSV.",
|
||||
"description": "Zaimportuj plik CSV zawierający Twoje przedmioty, etykiety i lokalizacje. Zobacz dokumentację, aby uzyskać \nwięcej informacji na temat wymaganego formatu.",
|
||||
"title": "Zaimportuj plik CSV",
|
||||
"upload": "Prześlij",
|
||||
"change_warning": "Zachowanie przy imporcie z istniejącymi import_ref zostało zmienione. Jeśli import_ref jest obecny w pliku CSV, \nprzedmiot zostanie zaktualizowany zgodnie z wartościami w pliku CSV."
|
||||
"upload": "Prześlij"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} temu",
|
||||
"days": "dni",
|
||||
"hour": "godzina",
|
||||
"hours": "godziny",
|
||||
"just-now": "teraz",
|
||||
"last-month": "ostatni miesiąc",
|
||||
"last-week": "ostatni tydzień",
|
||||
"last-year": "ostatni rok",
|
||||
"minute": "minuta",
|
||||
"minutes": "minuty",
|
||||
"months": "miesiące",
|
||||
"next-month": "następny miesiąc",
|
||||
"next-week": "następny tydzień",
|
||||
"next-year": "następny rok",
|
||||
"second": "sekunda",
|
||||
"seconds": "sekundy",
|
||||
"tomorrow": "jutro",
|
||||
"week": "tydzień",
|
||||
"weeks": "tygodnie",
|
||||
"years": "lat",
|
||||
"yesterday": "wczoraj"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Adres URL strony"
|
||||
},
|
||||
@@ -18,8 +41,10 @@
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"title": "Utwórz przedmiot",
|
||||
"photo_button": "Zdjęcie 📷"
|
||||
"item_description": "Opis przedmiotu",
|
||||
"item_name": "Nazwa przedmiotu",
|
||||
"photo_button": "Zdjęcie 📷",
|
||||
"title": "Utwórz przedmiot"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
@@ -27,99 +52,222 @@
|
||||
"items": "Przedmioty",
|
||||
"no_items": "Brak przedmiotów do wyświetlenia",
|
||||
"table": "Tabela"
|
||||
},
|
||||
"table": {
|
||||
"page": "Strona",
|
||||
"rows_per_page": "Wiersze na stronę"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"label_description": "Opis etykiety",
|
||||
"label_name": "Nazwa etykiety",
|
||||
"title": "Stwórz nową etykietę"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"location_description": "Opis lokalizacji",
|
||||
"location_name": "Nazwa lokalizacji",
|
||||
"title": "Utwórz lokalizację"
|
||||
},
|
||||
"selector": {
|
||||
"parent_location": "Nadrzędna lokalizacja"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Brak dostępnych lokalizacji. Dodaj nowe lokalizacje poprzez przycisk\n `<`span class=\"link-primary\"`>`Utwórz`<`/span`>` na pasku nawigacyjnym."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Dodaj",
|
||||
"build": "Kompilacja: {build}",
|
||||
"follow_dev": "Śledź dewelopera",
|
||||
"github": "Projekt na GitHubie",
|
||||
"items": "Przedmioty",
|
||||
"version": "Wersja:{version}",
|
||||
"welcome": "Witaj, {username}",
|
||||
"confirm": "Potwierdź",
|
||||
"create": "Utwórz",
|
||||
"create_and_add": "Utwórz i dodaj kolejny",
|
||||
"created": "Utworzone",
|
||||
"delete": "Usuń",
|
||||
"details": "Szczegóły",
|
||||
"duplicate": "Duplikat",
|
||||
"edit": "Edytuj",
|
||||
"email": "E-mail",
|
||||
"follow_dev": "Śledź dewelopera",
|
||||
"github": "Projekt na GitHubie",
|
||||
"items": "Przedmioty",
|
||||
"join_discord": "Dołącz do Discorda",
|
||||
"labels": "Etykiety",
|
||||
"locations": "Lokalizacje",
|
||||
"maintenance": "Konserwacja",
|
||||
"name": "Nazwa",
|
||||
"password": "Hasło",
|
||||
"read_docs": "Przeczytaj dokumentację",
|
||||
"save": "Zapisz",
|
||||
"search": "Wyszukaj",
|
||||
"sign_out": "Wyloguj się",
|
||||
"submit": "Wyślij"
|
||||
"submit": "Wyślij",
|
||||
"update": "Aktualizuj",
|
||||
"value": "Wartość",
|
||||
"version": "Wersja:{version}",
|
||||
"welcome": "Witaj, {username}"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Etykiety",
|
||||
"quick_statistics": "Szybkie statystyki",
|
||||
"recently_added": "Ostatnio dodane",
|
||||
"total_items": "Łączna liczba produktów",
|
||||
"total_labels": "Łączna liczba etykiet",
|
||||
"total_locations": "Łączna liczba lokalizacji",
|
||||
"total_value": "Łączna wartość"
|
||||
},
|
||||
"index": {
|
||||
"set_password": "Ustaw swoje hasło",
|
||||
"dont_join_group": "Nie chcesz dołączyć do grupy?",
|
||||
"disabled_registration": "Rejestracja jest wyłączona",
|
||||
"dont_join_group": "Nie chcesz dołączyć do grupy?",
|
||||
"joining_group": "Dołączasz do istniejącej grupy!",
|
||||
"login": "Zaloguj się",
|
||||
"register": "Zarejestruj się",
|
||||
"remember_me": "Zapamiętaj mnie",
|
||||
"set_email": "Jaki jest Twój adres e-mail?",
|
||||
"set_name": "Jak się nazywasz?",
|
||||
"set_password": "Ustaw swoje hasło",
|
||||
"tagline": "Śledź, organizuj i zarządzaj swoimi rzeczami."
|
||||
},
|
||||
"items": {
|
||||
"add": "Dodaj",
|
||||
"advanced": "Zaawansowane",
|
||||
"archived": "Zarchiwizowane",
|
||||
"attachment": "Załącznik",
|
||||
"attachments": "Załączniki",
|
||||
"changes_persisted_immediately": "Zmiany w załącznikach zostaną natychmiast zapisane",
|
||||
"created_at": "Data utworzenia",
|
||||
"custom_fields": "Pola niestandardowe",
|
||||
"description": "Opis",
|
||||
"details": "Szczegóły",
|
||||
"drag_and_drop": "Przeciągnij i upuść pliki tutaj lub kliknij, aby wybrać pliki",
|
||||
"edit_details": "Edytuj szczegóły",
|
||||
"field_selector": "Selektor pól",
|
||||
"field_value": "Wartość pola",
|
||||
"first": "Pierwszy",
|
||||
"include_archive": "Uwzględnij zarchiwizowane przedmioty",
|
||||
"negate_labels": "Neguj wybrane etykiety",
|
||||
"no_results": "Nie znaleziono przedmiotów",
|
||||
"query_id": "Zapytanie o numer identyfikacyjny zasobu: { id }",
|
||||
"results": "{ total } wyniki",
|
||||
"tip_3": "Filtry pól używają operacji 'LUB'. Jeśli wybrano więcej niż jeden, wystarczy jeden, \naby uzyskać dopasowanie.",
|
||||
"updated_at": "Zaktualizowano",
|
||||
"tip_1": "Filtry lokalizacji i etykiet używają operacji 'LUB'. Jeśli wybrano więcej niż jeden, wystarczy jeden, \naby uzyskać dopasowanie.",
|
||||
"pages": "Strona {page} z {totalPages}",
|
||||
"add": "Dodaj",
|
||||
"custom_fields": "Pola niestandardowe",
|
||||
"insured": "Ubezpieczony",
|
||||
"last": "Ostatni",
|
||||
"lifetime_warranty": "Dożywotnia gwarancja",
|
||||
"location": "Lokalizacja",
|
||||
"manual": "Instrukcja",
|
||||
"manuals": "Instrukcje",
|
||||
"manufacturer": "Producent",
|
||||
"model_number": "Model",
|
||||
"name": "Nazwa",
|
||||
"negate_labels": "Neguj wybrane etykiety",
|
||||
"next_page": "Następna strona",
|
||||
"no_results": "Nie znaleziono przedmiotów",
|
||||
"notes": "Notatki",
|
||||
"options": "Opcje",
|
||||
"order_by": "Ułóż według",
|
||||
"pages": "Strona {page} z {totalPages}",
|
||||
"parent_item": "Nadrzędny obiekt",
|
||||
"photo": "Zdjęcie",
|
||||
"photos": "Zdjęcia",
|
||||
"prev_page": "Poprzednia strona",
|
||||
"purchase_date": "Data zakupu",
|
||||
"purchase_details": "Szczegóły zakupu",
|
||||
"purchase_price": "Cena zakupu",
|
||||
"purchased_from": "Zakupiono od",
|
||||
"quantity": "Ilość",
|
||||
"query_id": "Zapytanie o numer identyfikacyjny zasobu: { id }",
|
||||
"receipt": "Paragon",
|
||||
"receipts": "Paragony",
|
||||
"reset_search": "Zresetuj wyszukiwanie",
|
||||
"results": "{ total } wyniki",
|
||||
"serial_number": "Numer seryjny",
|
||||
"show_advanced_view_options": "Pokaż ustawienia zaawansowane",
|
||||
"sold_at": "Sprzedane w",
|
||||
"sold_details": "Szczegóły sprzedaży",
|
||||
"sold_price": "Cena sprzedaży",
|
||||
"sold_to": "Sprzedane do",
|
||||
"tip_1": "Filtry lokalizacji i etykiet używają operacji 'LUB'. Jeśli wybrano więcej niż jeden, wystarczy jeden, \naby uzyskać dopasowanie.",
|
||||
"tip_2": "Wyszukiwania poprzedzone prefiksem \"#\" będą wysyłać zapytanie o identyfikator zasobu (na przykład \"#000-001\")",
|
||||
"tip_3": "Filtry pól używają operacji 'LUB'. Jeśli wybrano więcej niż jeden, wystarczy jeden, \naby uzyskać dopasowanie.",
|
||||
"tips": "Wskazówki",
|
||||
"tips_sub": "Wskazówki wyszukiwania",
|
||||
"order_by": "Ułóż według"
|
||||
"updated_at": "Zaktualizowano",
|
||||
"warranty": "Gwarancja",
|
||||
"warranty_details": "Szczegóły gwarancji",
|
||||
"warranty_expires": "Gwarancja wygasa"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Nie znaleziono etykiet",
|
||||
"update_label": "Aktualizuj etykietę"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Kataloński",
|
||||
"de": "Niemiecki",
|
||||
"en": "Angielski",
|
||||
"es": "Hiszpański",
|
||||
"fr": "Francuski",
|
||||
"hu": "Węgierski",
|
||||
"it": "Włoski",
|
||||
"ja-JP": "Japoński",
|
||||
"pl": "Polski",
|
||||
"ru": "Rosyjski",
|
||||
"sl": "Słoweński",
|
||||
"sv": "Szwedzki",
|
||||
"tr": "Turecki",
|
||||
"uk-UA": "Ukraiński",
|
||||
"zh-CN": "Chiński (uproszczony)",
|
||||
"zh-HK": "Chiński (Hong Kong)",
|
||||
"zh-TW": "Chiński (tradycyjny)"
|
||||
},
|
||||
"locations": {
|
||||
"child_locations": "Podlokalizacje",
|
||||
"collapse_tree": "Zwiń drzewo",
|
||||
"no_results": "Nie znaleziono lokalizacji",
|
||||
"update_location": "Zaktualizuj lokalizację"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Oba",
|
||||
"completed": "Zrealizowane",
|
||||
"scheduled": "Nadchodzące"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Zakończone",
|
||||
"create_first": "Stwórz swój pierwszy wpis",
|
||||
"delete": "Usuń",
|
||||
"duplicate": "Duplikuj",
|
||||
"edit": "Edytuj",
|
||||
"new": "Nowe"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Data zakończenia",
|
||||
"cost": "Koszt",
|
||||
"delete_confirmation": "Czy na pewno chcesz usunąć ten wpis?",
|
||||
"edit_action": "Aktualizuj",
|
||||
"edit_title": "Edytuj wpis",
|
||||
"entry_name": "Nazwa wpisu",
|
||||
"new_action": "Utwórz",
|
||||
"new_title": "Nowy wpis"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"active": "Aktywny",
|
||||
"change_password": "Zmiana hasła",
|
||||
"currency_format": "Format waluty",
|
||||
"current_password": "Bieżące hasło",
|
||||
"delete_account": "Usuń konto",
|
||||
"delete_account_sub": "Usuń swoje konto oraz wszystkie powiązane z nim dane. Tego nie można cofnąć.",
|
||||
"current_password": "Bieżące hasło",
|
||||
"enabled": "Włączone",
|
||||
"gen_invite": "Wygeneruj link z zaproszeniem",
|
||||
"group_settings": "Ustawienia grupy",
|
||||
"group_settings_sub": "Ustawienia grupy udostępnione. Możesz potrzebować odświeżyć przeglądarkę, aby niektóre ustawienia zostały zastosowane.",
|
||||
"inactive": "Nieaktywny",
|
||||
"new_password": "Nowe hasło",
|
||||
"notifier_modal": "{type, select, true {Edytuj} false {Utwórz} other {Inny}} Powiadomiacz",
|
||||
"enabled": "Włączone",
|
||||
"gen_invite": "Wygeneruj link z zaproszeniem",
|
||||
"group_settings": "Ustawienia grupy",
|
||||
"notifiers": "Powiadomiacze",
|
||||
"notifiers_sub": "Otrzymuj powiadomienia o nadchodzących przypomnieniach o konserwacji",
|
||||
"theme_settings_sub": "Ustawienia motywu są przechowywane w lokalnej pamięci przeglądarki. Możesz zmienić motyw w dowolnym momencie. \nJeśli masz problemy z ustawieniem motywu, spróbuj odświeżyć przeglądarkę.",
|
||||
"test": "Test",
|
||||
"theme_settings": "Ustawienia tematu",
|
||||
"theme_settings_sub": "Ustawienia motywu są przechowywane w lokalnej pamięci przeglądarki. Możesz zmienić motyw w dowolnym momencie. \nJeśli masz problemy z ustawieniem motywu, spróbuj odświeżyć przeglądarkę.",
|
||||
"update_group": "Zaktualizuj grupę",
|
||||
"url": "Adres URL",
|
||||
"user_profile": "Profil użytkownika",
|
||||
|
||||
@@ -75,12 +75,6 @@
|
||||
"set_password": "Defina a sua senha",
|
||||
"tagline": "Acompanhe, organize e faça a gestão das suas coisas."
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Nenhuma etiqueta encontrada"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Nenhuma localização encontrada"
|
||||
},
|
||||
"items": {
|
||||
"add": "Adicionar",
|
||||
"created_at": "Criado em",
|
||||
@@ -107,6 +101,9 @@
|
||||
"tips_sub": "Dicas de pesquisa",
|
||||
"updated_at": "Atualizado em"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Nenhuma etiqueta encontrada"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalão",
|
||||
"de": "Alemão",
|
||||
@@ -127,6 +124,9 @@
|
||||
"zh-MO": "Chinês (Macau)",
|
||||
"zh-TW": "Chinês (Tradicional)"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Nenhuma localização encontrada"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Ativo",
|
||||
"change_password": "Alterar Senha",
|
||||
@@ -138,17 +138,17 @@
|
||||
"enabled": "Ativado",
|
||||
"gen_invite": "Gerar link de convite",
|
||||
"group_settings": "Definições de Grupo",
|
||||
"group_settings_sub": "Definições de Grupo Partilhadas. Pode ter de atualizar a página para algumas definições serem aplicadas.",
|
||||
"group_settings_sub": "Definições de Grupo Partilhadas. Pode ter de atualizar a página para algumas definições serem aplicadas.",
|
||||
"inactive": "Inativo",
|
||||
"language": "Idioma",
|
||||
"new_password": "Nova Senha",
|
||||
"no_notifiers": "Nenhum notificador configurado",
|
||||
"notifier_modal": "{ type, select, true {Editar} false {Criar} other {Outro}} Notificador",
|
||||
"notifiers": "Notificadores",
|
||||
"notifiers_sub": "Receba notificações para os próximos lembretes de manutenção",
|
||||
"no_notifiers": "Nenhum notificador configurado",
|
||||
"test": "Testar",
|
||||
"theme_settings": "Definições do tema",
|
||||
"theme_settings_sub": "As configurações do tema são guardadas no armazenamento local do seu navegador. Pode alterar o tema em qualquer altura.\nSe encontrar algum problema com a alteração do tema, tente refrescar o browser.",
|
||||
"theme_settings_sub": "As configurações do tema são guardadas no armazenamento local do seu navegador. Pode alterar o tema em qualquer altura.\nSe encontrar algum problema com a alteração do tema, tente refrescar o browser.",
|
||||
"update_group": "Atualizar Grupo",
|
||||
"update_language": "Atualizar Idioma",
|
||||
"url": "URL",
|
||||
@@ -170,7 +170,7 @@
|
||||
"zero_datetimes": "Zero Item Data e Hora",
|
||||
"zero_datetimes_button": "Zero Data Horas do Item"
|
||||
},
|
||||
"actions_sub": "Aplicar Ações ao seu inventário em massa. Estas acções são irreversíveis. '<b>'Cuidado.'</b>'",
|
||||
"actions_sub": "Aplicar Ações ao seu inventário em massa. Estas acções são irreversíveis. '<b>'Cuidado.'</b>'",
|
||||
"import_export": "Importar/Exportar",
|
||||
"import_export_set": {
|
||||
"export": "Exportar Inventário",
|
||||
@@ -178,7 +178,7 @@
|
||||
"export_sub": "Exporta o formato CSV padrão para o Homebox. Isto vai exportar todos os items do inventário.",
|
||||
"import": "Importar inventário",
|
||||
"import_button": "Importar inventário",
|
||||
"import_sub": "Importa o formato standard do CSV para o Homebox. Sem uma coluna '<code>'HB.import_ref'</code>' , isto '<b>'não '</b>' vai escrever por cima de items existentes no inventário, apenas adiciona novos. As linhas com uma coluna '<code>'HB.import_ref'</code>' vão ser fundidas com os items que tenham o mesmo import_ref, se existirem."
|
||||
"import_sub": "Importa o formato standard do CSV para o Homebox. Sem uma coluna '<code>'HB.import_ref'</code>' , isto '<b>'não '</b>' vai escrever por cima de items existentes no inventário, apenas adiciona novos. As linhas com uma coluna '<code>'HB.import_ref'</code>' vão ser fundidas com os items que tenham o mesmo import_ref, se existirem."
|
||||
},
|
||||
"import_export_sub": "Importe e exporte o seu inventário de e para um ficheiro CSV. Isto é útil para migrar o inventário para uma nova instância do Homebox.",
|
||||
"reports": "Relatórios",
|
||||
|
||||
211
frontend/locales/ro-RO.json
Normal file
211
frontend/locales/ro-RO.json
Normal file
@@ -0,0 +1,211 @@
|
||||
{
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"title": "Importă fișier CSV",
|
||||
"upload": "Încarcă"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"page_qr_code": {
|
||||
"page_url": "URL Pagină"
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "Complexitate Parolă"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"photo_button": "Imagine 📷",
|
||||
"title": "Crează articol"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"card": "Cartelă",
|
||||
"items": "Articole",
|
||||
"no_items": "Nu există articole pentru afișare",
|
||||
"table": "Tabel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"title": "Crează Etichetă"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"title": "Crează Locație"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Nu există locații disponibile. Adaugă o locație nouă folosind butonul\n`<`span class=\"link-primary\"`>`Crează`<`/span`>` din bara de navigație."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"build": "Build: { build }",
|
||||
"confirm": "Confirmă",
|
||||
"create": "Crează",
|
||||
"create_and_add": "Crează și Adaugă încă un articol",
|
||||
"created": "Creat",
|
||||
"email": "Adresă de email",
|
||||
"follow_dev": "Urmărește developer-ul",
|
||||
"github": "Proiect GitHub",
|
||||
"items": "Articole",
|
||||
"join_discord": "Vino pe Discord",
|
||||
"labels": "Etichete",
|
||||
"locations": "Locații",
|
||||
"name": "Nume",
|
||||
"password": "Parolă",
|
||||
"read_docs": "Citește documentația",
|
||||
"search": "Caută",
|
||||
"sign_out": "Ieșire",
|
||||
"submit": "Trimite",
|
||||
"version": "Versiune: { version }",
|
||||
"welcome": "Bun venit, { username }"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Înregistrare Dezactivată",
|
||||
"dont_join_group": "Nu vrei sa te alături unui grup?",
|
||||
"joining_group": "Te alături unui grup existent!",
|
||||
"login": "Autentificare",
|
||||
"register": "Înregistrare",
|
||||
"remember_me": "Ține-mă minte",
|
||||
"set_email": "Care este adresa ta de email?",
|
||||
"set_name": "Care este numele tău?",
|
||||
"set_password": "Setează-ți parola",
|
||||
"tagline": "Urmărește, Organizează și Gestionează lucrurile tale."
|
||||
},
|
||||
"items": {
|
||||
"add": "Adaugă",
|
||||
"created_at": "Creat la",
|
||||
"custom_fields": "Câmpuri personalizate",
|
||||
"field_selector": "Selector Câmp",
|
||||
"field_value": "Valoare Câmp",
|
||||
"first": "Primul",
|
||||
"include_archive": "Include Articole Arhivate",
|
||||
"last": "Ultimul",
|
||||
"negate_labels": "Neagă Etichetele Selectate",
|
||||
"next_page": "Următoarea Pagină",
|
||||
"no_results": "Nu s-au găsit articole",
|
||||
"options": "Opțiuni",
|
||||
"order_by": "Ordonează După",
|
||||
"pages": "Pagina { page } din { totalPages }",
|
||||
"prev_page": "Pagina Anterioară",
|
||||
"reset_search": "Resetează Căutare",
|
||||
"results": "{ total } Rezultate",
|
||||
"tip_2": "Căutările prefixate cu '#' vor efectua o căutare după ID de activ (exemplu '#000-001')",
|
||||
"tips": "Sfaturi",
|
||||
"tips_sub": "Sfaturi Căutare",
|
||||
"updated_at": "Actualizat La"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Nu s-au găsit Etichete"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Catalană",
|
||||
"de": "Germană",
|
||||
"en": "Engleză",
|
||||
"es": "Spaniolă",
|
||||
"fr": "Franceză",
|
||||
"hu": "Maghiară",
|
||||
"it": "Italiană",
|
||||
"nl": "Olandeză",
|
||||
"pl": "Poloneză",
|
||||
"pt-BR": "Portugheză (Brazilia)",
|
||||
"ru": "Rusă",
|
||||
"sl": "Slovenă",
|
||||
"sv": "Suedeză",
|
||||
"tr": "Turcă",
|
||||
"zh-CN": "Chineză (Simplificată)",
|
||||
"zh-HK": "Chineză (Hong Kong)",
|
||||
"zh-MO": "Chineză (Macau)",
|
||||
"zh-TW": "Chineză (Tradițională)"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Nu s-au găsit Locații"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Ambele",
|
||||
"completed": "Finalizat",
|
||||
"scheduled": "Programat"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Finalizat",
|
||||
"create_first": "Crează Prima ta Înregistrare",
|
||||
"delete": "Șterge",
|
||||
"duplicate": "Duplicat",
|
||||
"edit": "Redactare",
|
||||
"new": "Nou"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Dată finalizare",
|
||||
"cost": "Preț",
|
||||
"delete_confirmation": "Ești sigur ca dorești ștergerea acestei înregistrări?",
|
||||
"edit_action": "Actualizare",
|
||||
"edit_title": "Redactare Înregistrare",
|
||||
"entry_name": "Nume Înregistrare",
|
||||
"new_action": "Crează",
|
||||
"new_title": "Înregistrare Nouă",
|
||||
"notes": "Notițe",
|
||||
"scheduled_date": "Dată Programată"
|
||||
},
|
||||
"monthly_average": "Media Lunară",
|
||||
"toast": {
|
||||
"failed_to_create": "Nu s-a putut crea înregistrarea",
|
||||
"failed_to_delete": "Nu s-a putut șterge înregistrarea",
|
||||
"failed_to_update": "Nu s-a putut actualiza înregistrarea"
|
||||
},
|
||||
"total_cost": "Preț Total",
|
||||
"total_entries": "Înregistrări Totale"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Acasă",
|
||||
"locations": "Locații",
|
||||
"maintenance": "Mentenanță",
|
||||
"profile": "Profil",
|
||||
"search": "Caută",
|
||||
"tools": "Unelte"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Activ",
|
||||
"change_password": "Schimbă Parola",
|
||||
"currency_format": "Format monedă",
|
||||
"current_password": "Parola Actuală",
|
||||
"delete_account": "Șterge Cont",
|
||||
"enabled": "Activat",
|
||||
"gen_invite": "Generează Link Invitație",
|
||||
"group_settings": "Setări Grup",
|
||||
"inactive": "Inactiv",
|
||||
"language": "Limbă",
|
||||
"new_password": "Parolă Nouă",
|
||||
"test": "Test",
|
||||
"theme_settings": "Setări Temă",
|
||||
"update_group": "Actualizare Grup",
|
||||
"update_language": "Actualizare Limbă",
|
||||
"url": "URL",
|
||||
"user_profile": "Profil Utilizator"
|
||||
},
|
||||
"tools": {
|
||||
"actions": "Acțiuni Inventar",
|
||||
"actions_set": {
|
||||
"set_primary_photo": "Setează ca Imagine Principală",
|
||||
"set_primary_photo_button": "Setează ca Imagine Principală"
|
||||
},
|
||||
"import_export": "Import/Export",
|
||||
"import_export_set": {
|
||||
"export": "Exportă Inventar",
|
||||
"export_button": "Exportă Inventar",
|
||||
"import": "Importă Inventar",
|
||||
"import_button": "Importă Inventar"
|
||||
},
|
||||
"reports": "Rapoarte",
|
||||
"reports_set": {
|
||||
"asset_labels": "Etichete de identificare a activului",
|
||||
"asset_labels_button": "Generator de etichete",
|
||||
"bill_of_materials": "Lista Materialelor",
|
||||
"bill_of_materials_button": "Generează BOM"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,12 +32,15 @@
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"title": "Создать ярлык"
|
||||
"title": "Создать метку"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"title": "Создать локацию"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Нет доступных локаций. Добавьте новую локацию, \nнажав на кнопку `<`span class=\"link-primary\"`>`Создать`<`/span`>` в навигационном меню."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -49,10 +52,10 @@
|
||||
"created": "Создано",
|
||||
"email": "Email",
|
||||
"follow_dev": "Следить за разработчиком",
|
||||
"github": "Проект Github",
|
||||
"github": "Github проект",
|
||||
"items": "Элементы",
|
||||
"join_discord": "Присоединяйтесь к Discord",
|
||||
"labels": "Ярлыки",
|
||||
"labels": "Метки",
|
||||
"locations": "Локации",
|
||||
"name": "Имя",
|
||||
"password": "Пароль",
|
||||
@@ -82,7 +85,7 @@
|
||||
"field_selector": "Поле выбора",
|
||||
"field_value": "Значение поля",
|
||||
"first": "Первый",
|
||||
"include_archive": "Включить архивированные элементы",
|
||||
"include_archive": "Включая архивированные элементы",
|
||||
"last": "Последний",
|
||||
"negate_labels": "Снять выбранные ярлыки",
|
||||
"next_page": "Следующая страница",
|
||||
@@ -92,7 +95,7 @@
|
||||
"pages": "Страница {page} из {totalPages}",
|
||||
"prev_page": "Предыдущая страница",
|
||||
"query_id": "Запрос идентификационного номера актива: { id }",
|
||||
"reset_search": "Сбросить Поиск",
|
||||
"reset_search": "Сбросить поиск",
|
||||
"results": "{ total } Результатов",
|
||||
"tip_1": "При фильтрации по локации и по ярлыкам используется логический оператор «ИЛИ». Если выбрано несколько фильтров, то для срабатывания\n требуется лишь одно совпадение.",
|
||||
"tip_2": "Поисковые запросы с префиксом \"#\" должны включать в себя ID актива (прим. '#000-001')",
|
||||
@@ -101,6 +104,75 @@
|
||||
"tips_sub": "Поисковые подсказки",
|
||||
"updated_at": "Обновлено в"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Метки не найдены"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Каталанский",
|
||||
"de": "Немецкий",
|
||||
"en": "Английский",
|
||||
"es": "Испанский",
|
||||
"fr": "французский",
|
||||
"hu": "Венгерский",
|
||||
"it": "Итальянский",
|
||||
"nl": "Голландский",
|
||||
"pl": "Польский",
|
||||
"pt-BR": "Португальский (Бразилия)",
|
||||
"ru": "Русский",
|
||||
"sl": "Словенский",
|
||||
"sv": "Шведский",
|
||||
"tr": "Турецкий",
|
||||
"zh-CN": "Китайский (упрощенный)",
|
||||
"zh-HK": "Китайский (Гонконг)",
|
||||
"zh-MO": "Китайский (Макао)",
|
||||
"zh-TW": "китайский (традиционный)"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Локаций не найдено"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Оба",
|
||||
"completed": "Завершено",
|
||||
"scheduled": "Запланировано"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Завершить",
|
||||
"create_first": "Создайте свою первую запись",
|
||||
"delete": "Удалить",
|
||||
"duplicate": "Дубликат",
|
||||
"edit": "Изменить",
|
||||
"new": "Новое"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Дата завершения",
|
||||
"cost": "Стоимость",
|
||||
"delete_confirmation": "Вы уверены, что хотите удалить эту запись?",
|
||||
"edit_action": "Обновить",
|
||||
"edit_title": "Изменить запись",
|
||||
"entry_name": "Название",
|
||||
"new_action": "Создать",
|
||||
"new_title": "Новая запись",
|
||||
"notes": "Заметки",
|
||||
"scheduled_date": "Планируемая дата"
|
||||
},
|
||||
"monthly_average": "Среднемесячный показатель",
|
||||
"toast": {
|
||||
"failed_to_create": "Не удалось создать запись",
|
||||
"failed_to_delete": "Не удалось удалить запись",
|
||||
"failed_to_update": "Ошибка обновления записи"
|
||||
},
|
||||
"total_cost": "Общая стоимость",
|
||||
"total_entries": "Всего записей"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Главная",
|
||||
"locations": "Локации",
|
||||
"maintenance": "Техническое обслуживание и ремонт",
|
||||
"profile": "Профиль",
|
||||
"search": "Поиск",
|
||||
"tools": "Инструменты"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Активный",
|
||||
"change_password": "Изменить пароль",
|
||||
@@ -108,7 +180,7 @@
|
||||
"current_password": "Текущий пароль",
|
||||
"delete_account": "Удалить аккаунт",
|
||||
"delete_account_sub": "Удалить свой аккаунт и все связанные с ним данные. Это действие невозможно отменить.",
|
||||
"display_header": "{ currentValue, select, true {Hide Header} false {Show Header} other {Not Hit}}",
|
||||
"display_header": "{ currentValue, select, true {Скрыть заголовок} false {Показать заголовок} other {Нет результатов}}",
|
||||
"enabled": "Активен",
|
||||
"gen_invite": "Сгенерировать ссылку-приглашение",
|
||||
"group_settings": "Настройки группы",
|
||||
@@ -116,9 +188,10 @@
|
||||
"inactive": "Неактивный",
|
||||
"language": "Язык",
|
||||
"new_password": "Новый пароль",
|
||||
"notifier_modal": "{ type, select, true {Edit} false {Create} other {Other}} Уведомитель",
|
||||
"no_notifiers": "Нет настроенных уведомлений",
|
||||
"notifier_modal": "{ type, select, true {Изменить} false {Создать} other {Другое}} Уведомитель",
|
||||
"notifiers": "Уведомители",
|
||||
"notifiers_sub": "Получить уведомление о предстоящем обслуживании",
|
||||
"notifiers_sub": "Получать уведомления о предстоящем обслуживании",
|
||||
"test": "Тест",
|
||||
"theme_settings": "Настройки темы",
|
||||
"theme_settings_sub": "Настройки темы хранятся в локальном хранилище браузера. Вы можете изменить тему в любое время. Если у вас\n не удается установить тему, попробуйте перезапустить браузер.",
|
||||
@@ -136,27 +209,33 @@
|
||||
"ensure_ids_sub": "Гарантирует, что все вещи в вашем инвентаре будут иметь корректное поле asset_id. Это производится при помощи поиска самого большого текущего значения поля asset_id в базе данных и применяет ко всем вещам новые значения, где они не были установлены в поле asset_id. Это производится в порядке сортировки по полю created_at.",
|
||||
"ensure_import_refs": "Проверка ссылок импорта",
|
||||
"ensure_import_refs_button": "Обеспечение импорта ссылок",
|
||||
"ensure_import_refs_sub": "Гарантирует что все вещи в Вашем инвентаре имеют корректное поле import_ref. Это производится при помощи генерации строки из 8 случайных символов для каждой вещи, где не поле import_ref не заполнено."
|
||||
"ensure_import_refs_sub": "Гарантирует что все вещи в Вашем инвентаре имеют корректное поле import_ref. Это производится при помощи генерации строки из 8 случайных символов для каждой вещи, где не поле import_ref не заполнено.",
|
||||
"set_primary_photo": "Установить основное фото",
|
||||
"set_primary_photo_button": "Установить основное фото",
|
||||
"set_primary_photo_sub": "В Homebox v0.10.0 мы добавили возможность отмечать вложенные фото как основное изображение. Это действие устанавливает первую фотографию во вложениях в качестве основной, если основное изображение еще не выбрано. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Посмотреть pull request #576'</a>'",
|
||||
"zero_datetimes": "Сбросить даты",
|
||||
"zero_datetimes_button": "Сбросить даты",
|
||||
"zero_datetimes_sub": "Сбрасывает значение полей даты и времени на начало даты в полном наборе. Это исправляет ошибку, когда сохранение значений времени на ранних этапах разработки сайта приводило к ошибке в точном отображении дат '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Посмотреть Issue #236 подробнее.'</a>'"
|
||||
},
|
||||
"actions_sub": "Применить действия ко всему Вашему инвентарю. Это необратимое действие. '<b>'Будьте осторожны.'</b>'",
|
||||
"actions_sub": "Применить действия ко всему вашему инвентарю. Это необратимое действие. '<b>'Будьте осторожны.'</b>'",
|
||||
"import_export": "Импорт/Экспорт",
|
||||
"import_export_set": {
|
||||
"export": "Экспортировать инвентарь",
|
||||
"export_button": "Экспортировать инвентарь",
|
||||
"export_sub": "Экспортирует файл в стандартном CSV формате для Homebox. Это экспортирует все Ваши вещи из Вашего инвентаря.",
|
||||
"import": "Импорт из инвентаря",
|
||||
"import": "Импортировать инвентарь",
|
||||
"import_button": "Импортировать инвентарь",
|
||||
"import_sub": "Импортирует стандартный CSV формат в Homebox. Без колонки '<code>'HB.import_ref'</code>' , это '<b>'не'</b>' перезапишет какую либо существующую вещь в вашем инвентаре, только добавит новые вещи. Строки с колонкой '<code>'HB.import_ref'</code>' будут объеденены с существующими вещами с теми же import_ref, если такие существуют."
|
||||
"import_sub": "Импортировать стандартный CSV формат в Homebox. Без колонки '<code>'HB.import_ref'</code>' , это '<b>'не'</b>' перезапишет какую либо существующую вещь в вашем инвентаре, только добавит новые вещи. Строки с колонкой '<code>'HB.import_ref'</code>' будут объеденены с существующими вещами с теми же import_ref, если такие существуют."
|
||||
},
|
||||
"import_export_sub": "Импортировать или экспортировать ваш инвентарь в или из CSV файла. Это полезно при миграции вашего инвентаря в новый экземпляр Homebox.",
|
||||
"reports": "Отчеты",
|
||||
"reports_set": {
|
||||
"asset_labels": "Этикетки с ID активов",
|
||||
"asset_labels_button": "Генератор этикеток",
|
||||
"asset_labels_sub": "Генерирует PDF с этикетками для диапазона ID активов. Отсутствует привязка к Вашему инвентарю, так что Вы можете напечатать этикетки заранее и применить их к вашему инвентарю позднее.",
|
||||
"asset_labels": "Метки с ID активов",
|
||||
"asset_labels_button": "Генератор меток",
|
||||
"asset_labels_sub": "Генерирует PDF с метками для диапазона ID активов. Отсутствует привязка к Вашему инвентарю, так что вы можете напечатать метки заранее и применить их к вашему инвентарю позже.",
|
||||
"bill_of_materials": "Ведомость материалов",
|
||||
"bill_of_materials_button": "Сгенерировать BOM",
|
||||
"bill_of_materials_sub": "Генерирует файл CSV (значения, разделенные запятой), который может быть импортировать в приложении электронных таблиц. Это сводка вашего инвентаря с базовой информацией о вещах и их цене."
|
||||
"bill_of_materials_button": "Сгенерировать список запчастей",
|
||||
"bill_of_materials_sub": "Генерирует CSV файл (значения, разделенные запятой), который может быть импортирован в приложении электронных таблиц. Это сводка вашего инвентаря с базовой информацией о вещах и их цене."
|
||||
},
|
||||
"reports_sub": "Создавайте различные отчеты для вашего инвентаря."
|
||||
}
|
||||
|
||||
@@ -1,61 +1,62 @@
|
||||
{
|
||||
"profile": {
|
||||
"notifier_modal": "{ type, select, true {Edit} false {Create} other {Other}} Anmälare",
|
||||
"change_password": "Ändra Lösenord",
|
||||
"current_password": "Nuvarande lösenord",
|
||||
"new_password": "Nytt lösenord",
|
||||
"notifiers_sub": "Få aviseringar om kommande underhållspåminnelser",
|
||||
"url": "URL",
|
||||
"test": "Test",
|
||||
"gen_invite": "Skapa inbjudningslänk",
|
||||
"user_profile": "Användarprofil",
|
||||
"user_profile_sub": "Bjud in användare och hantera ditt konto.",
|
||||
"active": "Aktiv",
|
||||
"inactive": "Inaktiv",
|
||||
"notifiers": "Notiser",
|
||||
"enabled": "Aktiverad",
|
||||
"currency_format": "Valuta format",
|
||||
"delete_account": "Radera konto",
|
||||
"delete_account_sub": "Ta bort ditt konto och alla tillhörande data. Detta kan inte ångras.",
|
||||
"group_settings": "Grupp inställningar",
|
||||
"group_settings_sub": "Inställningar för delad grupp. Du kan behöva uppdatera din webbläsare för att vissa inställningar ska gälla.",
|
||||
"theme_settings": "Temainställningar",
|
||||
"theme_settings_sub": "Temainställningar sparas i din webbläsares lokala lagring. Du kan ändra tema när du vill. Om du\nhar problem att ställa in tema, pröva att ladda om din webbläsare.",
|
||||
"update_group": "Uppdatera grupp"
|
||||
},
|
||||
"index": {
|
||||
"set_name": "Vad heter du?",
|
||||
"joining_group": "Du går med i en befintlig grupp!",
|
||||
"dont_join_group": "Vill du inte gå med i en grupp?",
|
||||
"tagline": "Spåra, organisera och hantera dina saker.",
|
||||
"disabled_registration": "Registrering avaktiverad",
|
||||
"login": "Logga in",
|
||||
"register": "Registrera",
|
||||
"remember_me": "Kom ihåg mig",
|
||||
"set_email": "Vad är din e-post?",
|
||||
"set_password": "Ställ in ditt lösenord"
|
||||
},
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"upload": "Ladda upp",
|
||||
"title": "Importera CSV fil",
|
||||
"description": "Importera en CSV-fil som innehåller dina föremål, etiketter och platser. Se dokumentationen för mer information om \nönskat format.",
|
||||
"change_warning": "Beteendet för importer med befintliga import_refs har ändrats. Om en import_ref finns i CSV-filen, \nobjektet kommer att uppdateras med värdena i CSV-filen."
|
||||
"change_warning": "Beteendet för importer med befintliga import_refs har ändrats. Om en import_ref finns i CSV-filen, \nobjektet kommer att uppdateras med värdena i CSV-filen.",
|
||||
"description": "Importera en CSV-fil som innehåller dina föremål, etiketter och platser. Se dokumentationen för mer information om formatet som krävs.",
|
||||
"title": "Importera CSV-fil",
|
||||
"upload": "Ladda upp"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"date_time": {
|
||||
"ago": "{0} sedan",
|
||||
"days": "dagar",
|
||||
"hour": "timme",
|
||||
"hours": "timmar",
|
||||
"in": "om {0}",
|
||||
"just-now": "precis nu",
|
||||
"last-month": "förra månaden",
|
||||
"last-week": "förra veckan",
|
||||
"last-year": "förra året",
|
||||
"minute": "minut",
|
||||
"minutes": "minuter",
|
||||
"months": "månader",
|
||||
"next-month": "nästa månad",
|
||||
"next-week": "nästa vecka",
|
||||
"next-year": "nästa år",
|
||||
"second": "sekund",
|
||||
"seconds": "sekunder",
|
||||
"tomorrow": "imorgon",
|
||||
"week": "vecka",
|
||||
"weeks": "veckor",
|
||||
"years": "år",
|
||||
"yesterday": "igår"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Sidans URL"
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "Lösenordsstyrka"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"item_description": "Beskrivning av föremål",
|
||||
"photo_button": "Foto 📷",
|
||||
"title": "Skapa föremål"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"card": "Kort",
|
||||
"items": "Föremål",
|
||||
"table": "Tabell",
|
||||
"no_items": "Inga föremål att visa"
|
||||
"no_items": "Inga föremål att visa",
|
||||
"table": "Tabell"
|
||||
},
|
||||
"table": {
|
||||
"page": "Sida",
|
||||
"rows_per_page": "Rader per sida"
|
||||
}
|
||||
},
|
||||
"create_modal": {
|
||||
"title": "Skapa föremål",
|
||||
"photo_button": "Foto 📷"
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
@@ -66,63 +67,182 @@
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"title": "Skapa plats"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"password_score": {
|
||||
"password_strength": "Lösenordsstyrka"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Sidans URL"
|
||||
"tree": {
|
||||
"no_locations": "Inga platser tillgängliga. Lägg till nya platser via\n `<`span class=\"link-primary\"`>`Skapa`<`/span`>`-knappen i navigationsmenyn."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"add": "Lägg till",
|
||||
"build": "Byggd: { build }",
|
||||
"github": "GitHub Projekt",
|
||||
"join_discord": "Gå med i Discord",
|
||||
"follow_dev": "Följ utvecklaren",
|
||||
"read_docs": "Läs dokumenten",
|
||||
"password": "Lösenord",
|
||||
"email": "Epost",
|
||||
"submit": "Skicka",
|
||||
"confirm": "Godkänn",
|
||||
"create": "Skapa",
|
||||
"create_and_add": "Skapa och lägg till en till",
|
||||
"created": "Skapad",
|
||||
"welcome": "Välkommen, { username }",
|
||||
"sign_out": "Logga ut",
|
||||
"create_and_add": "Skapa och lägg till en annan",
|
||||
"version": "Version: { version }",
|
||||
"details": "Detaljer",
|
||||
"duplicate": "Duplicera",
|
||||
"email": "Epost",
|
||||
"follow_dev": "Följ utvecklaren",
|
||||
"github": "GitHub-projekt",
|
||||
"items": "Föremål",
|
||||
"join_discord": "Gå med i Discord",
|
||||
"labels": "Etiketter",
|
||||
"locations": "Platser",
|
||||
"maintenance": "Underhåll",
|
||||
"name": "Namn",
|
||||
"search": "Sök"
|
||||
"password": "Lösenord",
|
||||
"read_docs": "Läs dokumentationen",
|
||||
"save": "Spara",
|
||||
"search": "Sök",
|
||||
"sign_out": "Logga ut",
|
||||
"submit": "Skicka",
|
||||
"update": "Uppdatera",
|
||||
"value": "Värde",
|
||||
"version": "Version: { version }",
|
||||
"welcome": "Välkommen, { username }"
|
||||
},
|
||||
"home": {
|
||||
"labels": "Etiketter",
|
||||
"quick_statistics": "Snabb statistik",
|
||||
"recently_added": "Nyligen tillagda",
|
||||
"total_value": "Totalt Värde"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Registrering avaktiverad",
|
||||
"dont_join_group": "Vill du inte gå med i en grupp?",
|
||||
"joining_group": "Du går med i en befintlig grupp!",
|
||||
"login": "Logga in",
|
||||
"register": "Registrera",
|
||||
"remember_me": "Kom ihåg mig",
|
||||
"set_email": "Vad är din e-post?",
|
||||
"set_name": "Vad heter du?",
|
||||
"set_password": "Ställ in ditt lösenord",
|
||||
"tagline": "Spåra, organisera och hantera dina saker."
|
||||
},
|
||||
"items": {
|
||||
"add": "Lägg till",
|
||||
"created_at": "Skapat",
|
||||
"custom_fields": "Egna fält",
|
||||
"details": "Detaljer",
|
||||
"field_selector": "Fält alternativ",
|
||||
"field_value": "Fält värde",
|
||||
"first": "Första",
|
||||
"include_archive": "Inkludera arkiverade föremål",
|
||||
"insured": "Försäkrad",
|
||||
"last": "Sista",
|
||||
"lifetime_warranty": "Livstidsgaranti",
|
||||
"location": "Plats",
|
||||
"manuals": "Manualer",
|
||||
"manufacturer": "Tillverkare",
|
||||
"model_number": "Modellnummer",
|
||||
"name": "Namn",
|
||||
"negate_labels": "Negera valda etiketter",
|
||||
"next_page": "Nästa sida",
|
||||
"no_results": "Inga föremål hittades",
|
||||
"notes": "Anteckningar",
|
||||
"options": "Alternativ",
|
||||
"order_by": "Ordning via",
|
||||
"pages": "Sida { page } av { totalPages }",
|
||||
"photos": "Foton",
|
||||
"prev_page": "Föregående sida",
|
||||
"purchase_date": "Inköpsdatum",
|
||||
"purchase_price": "Inköpspris",
|
||||
"purchased_from": "Köpt från",
|
||||
"quantity": "Antal",
|
||||
"query_id": "Fråga efter tillgångs-ID-nummer: { id }",
|
||||
"receipts": "Kvitton",
|
||||
"reset_search": "Återställ sökning",
|
||||
"results": "{ total } Resultat",
|
||||
"serial_number": "Serienummer",
|
||||
"sold_price": "Försäljningspris",
|
||||
"sold_to": "Såld till",
|
||||
"tip_1": "Platser och etiketter filter använder 'OR' funktionen. Om fler än en är valda, endast en kommer\nkrävas för en träff.",
|
||||
"tip_2": "Sökningar med prefixet '#'' kommer att fråga efter ett tillgångs-ID (exempel '#000-001')",
|
||||
"tip_3": "Fältfilter använder 'OR' funktion. Om fler än en är valda endast en kommer att bli krävande för en\nträff.",
|
||||
"tips": "Tips",
|
||||
"tips_sub": "Sök Tips",
|
||||
"updated_at": "Uppdaterad",
|
||||
"results": "{ total } Resultat"
|
||||
"warranty": "Garanti"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Inga etiketter hittades"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Katalanska",
|
||||
"de": "Tyska",
|
||||
"en": "Engelska",
|
||||
"es": "Spanska",
|
||||
"fr": "Franska",
|
||||
"hu": "Ungerska",
|
||||
"it": "Italienska",
|
||||
"nl": "Nederländska",
|
||||
"pl": "Polska",
|
||||
"pt-BR": "Portugisiska (Brasilien)",
|
||||
"ru": "Ryska",
|
||||
"sl": "Slovenska",
|
||||
"sv": "Svenska",
|
||||
"tr": "Turkiska",
|
||||
"zh-CN": "Kinesiska (förenklad)",
|
||||
"zh-HK": "kinesiska (Hongkong)",
|
||||
"zh-MO": "Kinesiska (Macao)",
|
||||
"zh-TW": "Kinesiska (traditionell)"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Inga platser hittades"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Båda",
|
||||
"completed": "Klar",
|
||||
"scheduled": "Schemalagd"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Färdig",
|
||||
"create_first": "Skapa din första post",
|
||||
"delete": "Radera",
|
||||
"duplicate": "Duplicera",
|
||||
"edit": "Redigera",
|
||||
"new": "Ny"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Slutförd datum",
|
||||
"cost": "Kostnad",
|
||||
"delete_confirmation": "Är du säker på att du vill radera denna post?",
|
||||
"edit_action": "Uppdatera",
|
||||
"edit_title": "Redigera",
|
||||
"new_action": "Skapa",
|
||||
"notes": "Anteckningar"
|
||||
}
|
||||
},
|
||||
"menu": {
|
||||
"search": "Sök",
|
||||
"tools": "Verktyg"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Aktiv",
|
||||
"change_password": "Ändra Lösenord",
|
||||
"currency_format": "Valuta format",
|
||||
"current_password": "Nuvarande lösenord",
|
||||
"delete_account": "Radera konto",
|
||||
"delete_account_sub": "Ta bort ditt konto och alla tillhörande data. Detta kan inte ångras.",
|
||||
"enabled": "Aktiverad",
|
||||
"gen_invite": "Skapa inbjudningslänk",
|
||||
"group_settings": "Grupp inställningar",
|
||||
"group_settings_sub": "Inställningar för delad grupp. Du kan behöva uppdatera din webbläsare för att vissa inställningar ska gälla.",
|
||||
"inactive": "Inaktiv",
|
||||
"language": "Språk",
|
||||
"new_password": "Nytt lösenord",
|
||||
"notifier_modal": "{ type, select, true {Edit} false {Create} other {Other}} Anmälare",
|
||||
"notifiers": "Notiser",
|
||||
"notifiers_sub": "Få aviseringar om kommande underhållspåminnelser",
|
||||
"test": "Test",
|
||||
"theme_settings": "Temainställningar",
|
||||
"theme_settings_sub": "Temainställningar sparas i din webbläsares lokala lagring. Du kan ändra tema när du vill. Om du\nhar problem att ställa in tema, pröva att ladda om din webbläsare.",
|
||||
"update_group": "Uppdatera grupp",
|
||||
"update_language": "Uppdatera språk",
|
||||
"url": "URL",
|
||||
"user_profile": "Användarprofil",
|
||||
"user_profile_sub": "Bjud in användare och hantera ditt konto."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,32 @@
|
||||
{
|
||||
"global": {
|
||||
"version": "Versiyon:{ version }",
|
||||
"password": "Şifre",
|
||||
"create": "Oluştur",
|
||||
"github": "GitHub projesi",
|
||||
"join_discord": "Discord'a Katılın",
|
||||
"follow_dev": "Geliştiriciyi takip edin",
|
||||
"read_docs": "Dokümanları okuyun",
|
||||
"email": "Elektronik posta",
|
||||
"submit": "Gönder",
|
||||
"confirm": "Onaylayın",
|
||||
"build": "Sürüm: { build }",
|
||||
"create_and_add": "Oluştur ve Bir Tane Daha Ekle",
|
||||
"created": "Oluşturuldu",
|
||||
"items": "Öğeler",
|
||||
"labels": "Etiketler",
|
||||
"locations": "Konumlar",
|
||||
"name": "İsim",
|
||||
"search": "Ara",
|
||||
"sign_out": "Oturumu kapat",
|
||||
"welcome": "Hoşgeldib, { username }"
|
||||
},
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Mevcut import_refs ile içe aktarmaların davranışı değişti. CSV dosyasında bir import_ref varsa, \nöğe CSV dosyasındaki değerlerle güncellenecektir.",
|
||||
"description": "Öğelerinizi, etiketlerinizi ve konumlarınızı içeren bir CSV dosyasını içe aktarın. Daha fazla\nbilgi için dökümanları okuyun.",
|
||||
"title": "CSV dosyasını içeri aktar",
|
||||
"upload": "Yükle",
|
||||
"description": "Öğelerinizi, etiketlerinizi ve konumlarınızı içeren bir CSV dosyasını içe aktarın. Daha fazla\nbilgi için dökümanları okuyun."
|
||||
"upload": "Yükle"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"password_score": {
|
||||
"password_strength": "Şifre güvenlik seviyesi"
|
||||
},
|
||||
"page_qr_code": {
|
||||
"page_url": "Sayfa URL'si"
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "Şifre güvenlik seviyesi"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"title": "Eşya Oluştur",
|
||||
"photo_button": "Fotoğraf 📷"
|
||||
"photo_button": "Fotoğraf 📷",
|
||||
"title": "Eşya Oluştur"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"items": "Öğeler",
|
||||
"card": "Kart",
|
||||
"table": "Tablo",
|
||||
"no_items": "Görüntülecek Öge Yok"
|
||||
"items": "Öğeler",
|
||||
"no_items": "Görüntülecek Öge Yok",
|
||||
"table": "Tablo"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -60,20 +38,45 @@
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"title": "Konum oluştur"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Mevcut konum yok. Navigasyon çubuğundaki \n`<`span class=\"link-primary\"`>`Oluştur`<`/span`>` düğmesiyle yeni konumlar ekleyin."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"build": "Sürüm: { build }",
|
||||
"confirm": "Onaylayın",
|
||||
"create": "Oluştur",
|
||||
"create_and_add": "Oluştur ve Bir Tane Daha Ekle",
|
||||
"created": "Oluşturuldu",
|
||||
"email": "Elektronik posta",
|
||||
"follow_dev": "Geliştiriciyi takip edin",
|
||||
"github": "GitHub projesi",
|
||||
"items": "Öğeler",
|
||||
"join_discord": "Discord'a Katılın",
|
||||
"labels": "Etiketler",
|
||||
"locations": "Konumlar",
|
||||
"name": "İsim",
|
||||
"password": "Şifre",
|
||||
"read_docs": "Dokümanları okuyun",
|
||||
"search": "Ara",
|
||||
"sign_out": "Oturumu kapat",
|
||||
"submit": "Gönder",
|
||||
"version": "Versiyon:{ version }",
|
||||
"welcome": "Hoşgeldin, { username }"
|
||||
},
|
||||
"index": {
|
||||
"remember_me": "Beni Hatırla",
|
||||
"tagline": "Eşyalarınızı Takip Edin, Düzenleyin ve Yönetin.",
|
||||
"disabled_registration": "Kayıt olma devre dışı",
|
||||
"dont_join_group": "Bir gruba katılmak istemiyor musunuz?",
|
||||
"joining_group": "Mevcut bir gruba katılıyorsunuz!",
|
||||
"login": "Oturum Aç",
|
||||
"register": "Kaydolun",
|
||||
"remember_me": "Beni Hatırla",
|
||||
"set_email": "E-posta adresiniz nedir?",
|
||||
"set_password": "Şifrenizi belirleyin",
|
||||
"set_name": "Adın ne?",
|
||||
"joining_group": "Mevcut bir gruba katılıyorsunuz!",
|
||||
"dont_join_group": "Bir gruba katılmak istemiyor musunuz?"
|
||||
"set_password": "Şifrenizi belirleyin",
|
||||
"tagline": "Eşyalarınızı Takip Edin, Düzenleyin ve Yönetin."
|
||||
},
|
||||
"items": {
|
||||
"add": "Ekle",
|
||||
@@ -92,37 +95,148 @@
|
||||
"pages": "Sayfa { page }/{ totalPages }",
|
||||
"prev_page": "Önceki Sayfa",
|
||||
"query_id": "Varlık Kimlik Numarası Sorgulanıyor: { id }",
|
||||
"tip_1": "Konum ve etiket filtreleri 'veya' işlemini kullanır. Eğer birden fazla seçilirse sadece biri \neşleştirme için kullanılacaktır.",
|
||||
"reset_search": "Aramayı Sıfırla",
|
||||
"tips": "İpuçları",
|
||||
"results": "{ total } Sonuç",
|
||||
"tip_1": "Konum ve etiket filtreleri 'veya' işlemini kullanır. Eğer birden fazla seçilirse sadece biri \neşleştirme için kullanılacaktır.",
|
||||
"tip_2": "'#' ile başlayan aramalar bir varlık kimliğini sorgular (örneğin '#000-001')",
|
||||
"tip_3": "Alan filtreleri 'VEYA' işlemini kullanır. Birden fazla seçenek seçilirse, eşleşme için yalnızca birinin \nkarşılanması yeterlidir.",
|
||||
"tips": "İpuçları",
|
||||
"tips_sub": "Arama İpuçları",
|
||||
"updated_at": "Güncellendiği Zaman"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Etiket Bulunamadı"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Katalanca",
|
||||
"de": "Almanca",
|
||||
"en": "İngilizce",
|
||||
"es": "İspanyolca",
|
||||
"fr": "Fransızca",
|
||||
"hu": "Macarca",
|
||||
"it": "İtalyanca",
|
||||
"nl": "Hollandaca",
|
||||
"pl": "Lehçe",
|
||||
"pt-BR": "Brezilya Portekizcesi",
|
||||
"ru": "Rusça",
|
||||
"sl": "Slovence",
|
||||
"sv": "İsveççe",
|
||||
"tr": "Türkçe",
|
||||
"zh-CN": "Basitleştirilmiş Çince",
|
||||
"zh-HK": "Çince (Hong Kong)",
|
||||
"zh-MO": "Çince (Macau)",
|
||||
"zh-TW": "Geleneksel Çince"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Konum bulunamadı"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "İkisi de",
|
||||
"completed": "Tamamlandı",
|
||||
"scheduled": "Planlanmış"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Tamamla",
|
||||
"create_first": "İlk Kaydınızı Oluşturun",
|
||||
"delete": "Sil",
|
||||
"duplicate": "Kopyala",
|
||||
"edit": "Düzenle",
|
||||
"new": "Yeni"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Tamamlanma Tarihi",
|
||||
"cost": "Maliyet",
|
||||
"delete_confirmation": "Bu kaydı silmek istediğinizden emin misiniz?",
|
||||
"edit_action": "Güncelle",
|
||||
"edit_title": "Kaydı Düzenle",
|
||||
"entry_name": "Kayıt Adı",
|
||||
"new_action": "Oluştur",
|
||||
"new_title": "Yeni Kayıt",
|
||||
"notes": "Notlar",
|
||||
"scheduled_date": "Planlanan Tarih"
|
||||
},
|
||||
"monthly_average": "Aylık Ortalama",
|
||||
"toast": {
|
||||
"failed_to_create": "Kayıt oluşturulamadı",
|
||||
"failed_to_delete": "Kayıt silinemedi",
|
||||
"failed_to_update": "Kayıt güncellenemedi"
|
||||
},
|
||||
"total_cost": "Toplam Maliyet",
|
||||
"total_entries": "Toplam Kayıt"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Ev",
|
||||
"locations": "Konumlar",
|
||||
"maintenance": "Bakım",
|
||||
"profile": "Profil",
|
||||
"search": "Ara",
|
||||
"tools": "Araçlar"
|
||||
},
|
||||
"profile": {
|
||||
"url": "URL",
|
||||
"user_profile": "Kullanıcı Profili",
|
||||
"user_profile_sub": "Kullanıcıları davet edin ve hesabınızı yönetin.",
|
||||
"active": "Aktif",
|
||||
"change_password": "Şifre Değiştir",
|
||||
"currency_format": "Para Birimi Biçimi",
|
||||
"current_password": "Mevcut Şifre",
|
||||
"delete_account": "Hesabı Sil",
|
||||
"delete_account_sub": "Hesabınızı ve ona bağlı tüm verileri silin. Bu işlem geri alınamaz.",
|
||||
"display_header": "{ currentValue, select, true {Başlığı Gizle} false {Başlığı Göster} other {Etkilenmedi}}",
|
||||
"enabled": "Etkinleştirildi",
|
||||
"gen_invite": "Davet Bağlantısı Oluştur",
|
||||
"group_settings": "Grup Ayarları",
|
||||
"group_settings_sub": "Paylaşılan Grup Ayarları. Bazı ayarların uygulanabilmesi için tarayıcınızı yenilemeniz gerekebilir.",
|
||||
"inactive": "Etkin Değil",
|
||||
"language": "Dil",
|
||||
"new_password": "Yeni Şifre",
|
||||
"no_notifiers": "Yapılandırılmış bildirimci yok",
|
||||
"notifier_modal": "{ type, select, true {Edit} false {Create} other {Other}} Bildirici",
|
||||
"notifiers": "Bildirimde Bulunanlar",
|
||||
"notifiers_sub": "Yaklaşan bakım hatırlatmaları için bildirimler alın",
|
||||
"test": "Test",
|
||||
"theme_settings": "Tema Ayarları",
|
||||
"theme_settings_sub": "Tema ayarları tarayıcınızın yerel depolama alanında saklanır. Temayı istediğiniz zaman değiştirebilirsiniz. \nTemanızı ayarlamakta sorun yaşıyorsanız, tarayıcınızı yenilemeyi deneyin.",
|
||||
"update_group": "Grubu Güncelle",
|
||||
"notifiers_sub": "Yaklaşan bakım hatırlatmaları için bildirimler alın"
|
||||
"update_language": "Dili Güncelle",
|
||||
"url": "URL",
|
||||
"user_profile": "Kullanıcı Profili",
|
||||
"user_profile_sub": "Kullanıcıları davet edin ve hesabınızı yönetin."
|
||||
},
|
||||
"tools": {
|
||||
"actions": "Envanter İşlemleri",
|
||||
"actions_set": {
|
||||
"ensure_ids": "Varlık Kimliklerini Sağlayın",
|
||||
"ensure_ids_button": "Varlık Kimliklerini Sağlayın",
|
||||
"ensure_ids_sub": "Envanterinizdeki tüm öğelerin geçerli bir asset_id alanına sahip olmasını sağlar. Bu, veritabanındaki en yüksek mevcut asset_id alanını bulup, ayarlanmamış asset_id alanına sahip her öğeye bir sonraki değeri uygulayarak yapılır. Bu işlem, created_at alanına göre sıralanarak gerçekleştirilir.",
|
||||
"ensure_import_refs": "İçe Aktarma Referanslarını Sağlayın",
|
||||
"ensure_import_refs_button": "İçe Aktarma Referanslarını Sağlayın",
|
||||
"ensure_import_refs_sub": "Envanterinizdeki tüm öğelerin geçerli bir import_ref alanına sahip olmasını sağlar. Bu, ayarlanmamış import_ref alanına sahip her öğe için rastgele 8 karakterli bir dize oluşturarak yapılır.",
|
||||
"set_primary_photo": "Ana Fotoğrafı Ayarla",
|
||||
"set_primary_photo_button": "Ana Fotoğrafı Ayarla",
|
||||
"set_primary_photo_sub": "Homebox'un v0.10.0 sürümünde, fotoğraf türündeki ekler için birincil görüntü alanı eklendi. Bu işlem, veritabanındaki ekler dizisindeki ilk görüntüyü, eğer zaten ayarlanmamışsa, birincil görüntü alanı olarak ayarlayacaktır. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'GitHub #576'yı Gör'</a>",
|
||||
"zero_datetimes": "Sıfır Öğesi Tarih Saatleri",
|
||||
"zero_datetimes_button": "Sıfır Öğe Tarih Saatleri",
|
||||
"zero_datetimes_sub": "Tarih saat alanlarındaki tüm zaman değerlerini en baştaki tarihe sıfırlar. Bu, sitenin geliştirilmesi sırasında erken aşamalarda ortaya çıkan ve zaman değerinin saklanmasına neden olan bir hatayı düzeltmek içindir; bu da tarih alanlarının doğru değerler göstermesinde sorunlara yol açıyordu. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Daha fazla bilgi için Github Sorunu #236'ya Bakın.'</a>'"
|
||||
},
|
||||
"actions_sub": "Envanterinize toplu olarak işlemler uygulayın. Bu işlemler geri alınamaz. '<b>'Dikkatli olun.'</b>",
|
||||
"import_export": "İçe Aktar/Dışa Aktar",
|
||||
"import_export_set": {
|
||||
"export": "Envanteri Dışa Aktar",
|
||||
"export_button": "Envanteri Dışa Aktar",
|
||||
"export_sub": "Homebox için standart CSV formatını dışa aktarır. Bu, envanterinizdeki tüm öğeleri dışa aktaracaktır.",
|
||||
"import": "Envanteri İçe Aktar",
|
||||
"import_button": "Envanteri İçe Aktar",
|
||||
"import_sub": "Homebox için standart CSV formatını içe aktarır. '<code>'HB.import_ref'</code>' sütunu olmadan, bu mevcut envanterinizdeki herhangi bir öğeyi '<b>'üzerine yazmaz'</b>', yalnızca yeni öğeler ekler. '<code>'HB.import_ref'</code>' sütununa sahip satırlar, varsa aynı import_ref'e sahip mevcut öğelerle birleştirilir."
|
||||
},
|
||||
"import_export_sub": "Envanterinizi bir CSV dosyasına içe ve dışa aktarın. Bu, envanterinizi yeni bir Homebox örneğine taşımak için faydalıdır.",
|
||||
"reports": "Raporlar",
|
||||
"reports_set": {
|
||||
"asset_labels": "Varlık Kimlik Etiketleri",
|
||||
"asset_labels_button": "Etiket Oluşturucu",
|
||||
"asset_labels_sub": "Bir dizi Varlık Kimliği için yazdırılabilir bir PDF etiketleri oluşturur. Bu etiketler envanterinize özgü değildir, bu nedenle etiketleri önceden yazdırabilir ve onları aldığınızda envanterinize uygulayabilirsiniz.",
|
||||
"bill_of_materials": "Malzeme Listesi",
|
||||
"bill_of_materials_button": "Malzeme Listesi Oluştur",
|
||||
"bill_of_materials_sub": "Bir elektronik tablo programına içe aktarılabilen bir CSV (Virgülle Ayrılmış Değerler) dosyası oluşturur. Bu, envanterinizin temel öğe ve fiyat bilgileriyle birlikte bir özetidir."
|
||||
},
|
||||
"reports_sub": "Envanteriniz için farklı raporlar oluşturun."
|
||||
}
|
||||
}
|
||||
|
||||
242
frontend/locales/uk-UA.json
Normal file
242
frontend/locales/uk-UA.json
Normal file
@@ -0,0 +1,242 @@
|
||||
{
|
||||
"components": {
|
||||
"app": {
|
||||
"import_dialog": {
|
||||
"change_warning": "Поведінка для імпорту з існуючим параметром import_refs змінилася. Якщо цей параметр присутній у CSV файлі, \nпредмет буде оновлений значеннями з CSV.",
|
||||
"description": "Імпортувати CSV файл з предметами, мітками і локаціями. Зверніться до документації за\nдодатковою інформацією по формату.",
|
||||
"title": "Імпортувати .CSV",
|
||||
"upload": "Завантажити"
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"page_qr_code": {
|
||||
"page_url": "URL сторінки"
|
||||
},
|
||||
"password_score": {
|
||||
"password_strength": "Міцність паролю"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"create_modal": {
|
||||
"photo_button": "Фото📷",
|
||||
"title": "Додати предмет"
|
||||
},
|
||||
"view": {
|
||||
"selectable": {
|
||||
"card": "Картка",
|
||||
"items": "Предмети",
|
||||
"no_items": "Предмети відсутні",
|
||||
"table": "Таблиця"
|
||||
}
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"create_modal": {
|
||||
"title": "Створити наліпку"
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"create_modal": {
|
||||
"title": "Створити локацію"
|
||||
},
|
||||
"tree": {
|
||||
"no_locations": "Локації відсутні. Додайте нову за допомогою \n<`span class=\"link-primary\"`>`Створити`<`/span`>` клавіші ліворуч."
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"build": "Зібрати: { build }",
|
||||
"confirm": "Зберегти",
|
||||
"create": "Створити",
|
||||
"create_and_add": "Створити і додати ще один",
|
||||
"created": "Створено",
|
||||
"email": "Email",
|
||||
"follow_dev": "Підписатись на розробника",
|
||||
"github": "GitHub проекту",
|
||||
"items": "Предмети",
|
||||
"join_discord": "Доєднатися до Discord",
|
||||
"labels": "Наліпки",
|
||||
"locations": "Локації",
|
||||
"name": "Ім'я",
|
||||
"password": "Пароль",
|
||||
"read_docs": "Переглянути документацію",
|
||||
"search": "Пошук",
|
||||
"sign_out": "Вийти",
|
||||
"submit": "Підтвердити",
|
||||
"version": "Версія: { version }",
|
||||
"welcome": "Вітаю, { username }"
|
||||
},
|
||||
"index": {
|
||||
"disabled_registration": "Реєстрація недоступна",
|
||||
"dont_join_group": "Не хочете доєднуватись до групи?",
|
||||
"joining_group": "Ви доєднуєтесь до існуючої групи!",
|
||||
"login": "Логін",
|
||||
"register": "Реєстрація",
|
||||
"remember_me": "Запам'ятати мене",
|
||||
"set_email": "Який ваш e-mail?",
|
||||
"set_name": "Як вас звуть?",
|
||||
"set_password": "Оберіть пароль",
|
||||
"tagline": "Слідкуйте, організуйте і керуйте своїми предметами."
|
||||
},
|
||||
"items": {
|
||||
"add": "Додати",
|
||||
"created_at": "Створено о",
|
||||
"custom_fields": "Власні поля",
|
||||
"field_selector": "Обрати поле",
|
||||
"field_value": "Значення поля",
|
||||
"first": "Перший",
|
||||
"include_archive": "Включити заархівовані предмети",
|
||||
"last": "Останній",
|
||||
"negate_labels": "Відмінити обрані мітки",
|
||||
"next_page": "Наступна сторінка",
|
||||
"no_results": "Предметів нема",
|
||||
"options": "Налаштування",
|
||||
"order_by": "Відсортувати за",
|
||||
"pages": "Сторінка { page } з { totalPages }",
|
||||
"prev_page": "Попередня сторінка",
|
||||
"query_id": "Шукаю за ID предмета: { id }",
|
||||
"reset_search": "Скинути пошук",
|
||||
"results": "{ total } Результатів",
|
||||
"tip_1": "Фільтри по локації і міткам використовують операцію \"АБО\". Якщо більше одного обрано, тільки один\nз них має співпасти для виводу результату.",
|
||||
"tip_2": "Пошуки, що починаються з \"#\" будуть шукати за ID предмета (наприклад, \"#000-001\")",
|
||||
"tip_3": "Пошук в полях використовує операцію \"АБО\". Якщо більше одного задіяно, достатньо буде \nспівпасти лише одному для виводу результату.",
|
||||
"tips": "Підказки",
|
||||
"tips_sub": "Підказки щодо пошуку",
|
||||
"updated_at": "Оновлено"
|
||||
},
|
||||
"labels": {
|
||||
"no_results": "Мітки не знайдено"
|
||||
},
|
||||
"languages": {
|
||||
"ca": "Каталонська",
|
||||
"de": "Німецька",
|
||||
"en": "Англійська",
|
||||
"es": "Іспанська",
|
||||
"fr": "Французька",
|
||||
"hu": "Угорська",
|
||||
"it": "Італійська",
|
||||
"nl": "Голландський",
|
||||
"pl": "Польська мова",
|
||||
"pt-BR": "Португальська (Бразилія)",
|
||||
"ru": "Російська",
|
||||
"sl": "Словенська",
|
||||
"sv": "Swedish",
|
||||
"tr": "турецька",
|
||||
"zh-CN": "Китайська (спрощена)",
|
||||
"zh-HK": "Китайська (Гонконг)",
|
||||
"zh-MO": "Китайська (Макао)",
|
||||
"zh-TW": "Китайська (традиційне письмо)"
|
||||
},
|
||||
"locations": {
|
||||
"no_results": "Локації відсутні"
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "Обидва",
|
||||
"completed": "Виконано",
|
||||
"scheduled": "Заплановано"
|
||||
},
|
||||
"list": {
|
||||
"complete": "Завершені",
|
||||
"create_first": "Створіть свій перший запис",
|
||||
"delete": "Видалити",
|
||||
"duplicate": "Дублювати",
|
||||
"edit": "Редагувати",
|
||||
"new": "Новий"
|
||||
},
|
||||
"modal": {
|
||||
"completed_date": "Дата завершення",
|
||||
"cost": "Ціна",
|
||||
"delete_confirmation": "Ви впевнені, що хочете видалити цей запис?",
|
||||
"edit_action": "Оновити",
|
||||
"edit_title": "Редагувати запис",
|
||||
"entry_name": "Назва запису",
|
||||
"new_action": "Створити",
|
||||
"new_title": "Новий запис",
|
||||
"notes": "Примітки",
|
||||
"scheduled_date": "Запланована дата"
|
||||
},
|
||||
"monthly_average": "Середнє за місяць",
|
||||
"toast": {
|
||||
"failed_to_create": "Не вдалося створити запис",
|
||||
"failed_to_delete": "Не вдалося видалити запис",
|
||||
"failed_to_update": "Не вдалося оновити запис"
|
||||
},
|
||||
"total_cost": "Загальна сума",
|
||||
"total_entries": "Всього елементів"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Головна",
|
||||
"locations": "Локації",
|
||||
"maintenance": "Обслуговування",
|
||||
"profile": "Профіль",
|
||||
"search": "Пошук",
|
||||
"tools": "Інструменти"
|
||||
},
|
||||
"profile": {
|
||||
"active": "Активний",
|
||||
"change_password": "Змінити пароль",
|
||||
"currency_format": "Формат валюти",
|
||||
"current_password": "Поточний пароль",
|
||||
"delete_account": "Видалити обліковий запис",
|
||||
"delete_account_sub": "Видалити акаунт і всі пов'язані дані. Це невідворотна дія.",
|
||||
"display_header": "{ currentValue, select, true {Приховати заголовок} false {Показати заголовок} other {Відсутнє}}",
|
||||
"enabled": "Включено",
|
||||
"gen_invite": "Створити посилання для запрошення",
|
||||
"group_settings": "Налаштування групи",
|
||||
"group_settings_sub": "Налаштування спільної групи. Можливо, вам доведеться оновити сторінку для збереження параметрів.",
|
||||
"inactive": "Неактивний",
|
||||
"language": "Мова",
|
||||
"new_password": "Новий пароль",
|
||||
"no_notifiers": "Немає налаштованих сповіщувачів",
|
||||
"notifier_modal": "{ type, select, true {Edit} false {Create} other {Other}} Сповіщувач",
|
||||
"notifiers": "Сповіщувачі",
|
||||
"notifiers_sub": "Отримувати сповіщення про майбутнє технічне обслуговування",
|
||||
"test": "Тест",
|
||||
"theme_settings": "Налаштування Теми",
|
||||
"theme_settings_sub": "Налаштування теми зберігаються в локальному сховищі вашого браузера. Ви можете змінити тему в будь-який момент. Якщо\nзберегти не вдається, спробуйте оновити сторінку (Ctrl+F5).",
|
||||
"update_group": "Оновити групу",
|
||||
"update_language": "Оновлення мови",
|
||||
"url": "URL-адреса",
|
||||
"user_profile": "Профіль користувача",
|
||||
"user_profile_sub": "Запросіть користувачів і керуйте своїм обліковим записом."
|
||||
},
|
||||
"tools": {
|
||||
"actions": "Дії з інвентарем",
|
||||
"actions_set": {
|
||||
"ensure_ids": "Перевірити наявність ID",
|
||||
"ensure_ids_button": "Перевірити наявність ID",
|
||||
"ensure_ids_sub": "Перевіряє усі ваші предмети на наявність вірного asset_id поля. Цей процес полягає в пошуці найбільшого значення asset_id у базі даних, і присвоєння настпупного за ним значення кожному предмету без asset_id. Процес йде по порядку поля created_at.",
|
||||
"ensure_import_refs": "Присвоїти дані іморту",
|
||||
"ensure_import_refs_button": "Присвоїти дані імпорту",
|
||||
"ensure_import_refs_sub": "Запевнитись, що всі предмети у вашій базі мають коректне поле import_ref. Для цього кожен предмет без встановленого import_ref отримає в це поле строку з восьми випадкових літер.",
|
||||
"set_primary_photo": "Встановити основну фотографію",
|
||||
"set_primary_photo_button": "Встановити основну фотографію",
|
||||
"set_primary_photo_sub": "У версії v0.10.0 Homebox до вкладень типу photo було додано поле зображення. Ця дія встановить основною фотографією першу картинку, що ви додали до предметів, якщо вона ще не встановлена. '<a class=\"link\" href=\"https://github.com/hay-kot/homebox/pull/576\">'Див. GitHub PR #576'</a>'",
|
||||
"zero_datetimes": "Обнулити дати предметів",
|
||||
"zero_datetimes_button": "Обнулити дати предметів",
|
||||
"zero_datetimes_sub": "Ця клавіша скидає значення \"час\" для усіх полів типу \"дата\" у списку ваших предметів. Користуйтеся для виправлення багу, що був доданий на початку розробки, і який псував збереження часу, що призводило до некоректного відображення.'<a class=\"link\" href=\"https://github.com/hay-kot/homebox/issues/236\" target=\"_blank\">'Більше даних на GitHub, #236 проблема.'</a>'"
|
||||
},
|
||||
"actions_sub": "Дії для роботи з усіма предметами одразу. Процес незворотній.'<b>'Будьте обережні.'</b>'",
|
||||
"import_export": "Імопрт/Експорт",
|
||||
"import_export_set": {
|
||||
"export": "Експортувати інвентар",
|
||||
"export_button": "Експортувати інвентар",
|
||||
"export_sub": "Експортувати у стандартному для HomeBox форматі. Це виведе у файл усі предмети з інвентара.",
|
||||
"import": "Імпортувати інвентар",
|
||||
"import_button": "Імпортувати інвентар",
|
||||
"import_sub": "Імпортувати у стандартному форматі для HomeBox .CSV-файл.Без '<code>'HB.import_ref'</code>' колонки, це '<b>не'</b>' перезапише ніякі предмети в інвентарі, лише додасть нові. Рядки з параметром '<code>'HB.import_ref'</code>' будуть злиті з існуючими предметами, якщо такі наявні і import_ref поле співпадає."
|
||||
},
|
||||
"import_export_sub": "Імпортувати і експортувати ваш інвентар у форматі .CSV. Це корисно для переносу інвентара на нову інсталяцію HomeBox.",
|
||||
"reports": "Звіти",
|
||||
"reports_set": {
|
||||
"asset_labels": "Наліпки з ID предметів",
|
||||
"asset_labels_button": "Генератор наліпок",
|
||||
"asset_labels_sub": "Створити .PDF файл з мітками, відповідно обраному діапазону ID. Ці мітки не пов'язані з присвоєними ID вашим предметам, тож ви можете надрукувати їх перед внесенням предметів у базу даних, і внести вже постфактум.",
|
||||
"bill_of_materials": "Звіт по предметам",
|
||||
"bill_of_materials_button": "Згенерувати звіт",
|
||||
"bill_of_materials_sub": "Створити .CSV файл, який можна імпортувати у відповідну програму (Excel, Spreadsheets, т.д.). Це буде повний звіт з описом усіх доданих предметів."
|
||||
},
|
||||
"reports_sub": "Створити різноманітні звіти по вашим предметам."
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@
|
||||
"password": "密码",
|
||||
"read_docs": "查阅文档",
|
||||
"search": "搜索",
|
||||
"sign_out": "注销",
|
||||
"sign_out": "登出",
|
||||
"submit": "提交",
|
||||
"version": "版本:{version}",
|
||||
"welcome": "欢迎,{username}"
|
||||
@@ -132,7 +132,7 @@
|
||||
},
|
||||
"maintenance": {
|
||||
"filter": {
|
||||
"both": "与",
|
||||
"both": "全部",
|
||||
"completed": "已完成",
|
||||
"scheduled": "已预定"
|
||||
},
|
||||
@@ -174,7 +174,7 @@
|
||||
"tools": "工具"
|
||||
},
|
||||
"profile": {
|
||||
"active": "活跃",
|
||||
"active": "启用",
|
||||
"change_password": "更改密码",
|
||||
"currency_format": "货币格式",
|
||||
"current_password": "原密码",
|
||||
@@ -185,7 +185,7 @@
|
||||
"gen_invite": "生成邀请链接",
|
||||
"group_settings": "组设置",
|
||||
"group_settings_sub": "共享组设置。您可能需要刷新浏览器来让某些设置生效。",
|
||||
"inactive": "非活跃",
|
||||
"inactive": "未启用",
|
||||
"language": "语言",
|
||||
"new_password": "新密码",
|
||||
"no_notifiers": "未配置通知程序",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"lint": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore .",
|
||||
"lint:fix": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore . --fix",
|
||||
"lint:ci": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore . --max-warnings 1",
|
||||
"typecheck": "nuxi typecheck",
|
||||
"typecheck": "pnpm dlx vue-tsc@2.1.6 --noEmit",
|
||||
"test:ci": "TEST_SHUTDOWN_API_SERVER=true vitest --run --config ./test/vitest.config.ts",
|
||||
"test:local": "TEST_SHUTDOWN_API_SERVER=false && vitest --run --config ./test/vitest.config.ts",
|
||||
"test:watch": " TEST_SHUTDOWN_API_SERVER=false vitest --config ./test/vitest.config.ts"
|
||||
@@ -23,6 +23,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"@vite-pwa/nuxt": "^0.5.0",
|
||||
"@vue/runtime-core": "^3.5.12",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
<div>
|
||||
<BaseContainer class="flex flex-col gap-12 pb-16">
|
||||
<section>
|
||||
<Subtitle> Quick Statistics </Subtitle>
|
||||
<Subtitle> {{ $t("home.quick_statistics") }} </Subtitle>
|
||||
<div class="grid grid-cols-2 gap-2 md:grid-cols-4 md:gap-6">
|
||||
<StatCard v-for="(stat, i) in stats" :key="i" :title="stat.label" :value="stat.value" :type="stat.type" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Subtitle>Recently Added</Subtitle>
|
||||
<Subtitle> {{ $t("home.recently_added") }} </Subtitle>
|
||||
|
||||
<p v-if="itemTable.items.length === 0" class="ml-2 text-sm">{{ $t("items.no_results") }}</p>
|
||||
<BaseCard v-else-if="breakpoints.lg">
|
||||
@@ -47,7 +47,7 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Subtitle> Storage Locations </Subtitle>
|
||||
<Subtitle> {{ $t("home.storage_locations") }} </Subtitle>
|
||||
<p v-if="locations.length === 0" class="ml-2 text-sm">{{ $t("locations.no_results") }}</p>
|
||||
<div v-else class="card grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3">
|
||||
<LocationCard v-for="location in locations" :key="location.id" :location="location" />
|
||||
@@ -55,7 +55,7 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Subtitle> Labels </Subtitle>
|
||||
<Subtitle> {{ $t("home.labels") }} </Subtitle>
|
||||
<p v-if="labels.length === 0" class="ml-2 text-sm">{{ $t("labels.no_results") }}</p>
|
||||
<div v-else class="flex flex-wrap gap-4">
|
||||
<LabelChip v-for="label in labels" :key="label.id" size="lg" :label="label" class="shadow-md" />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useI18n } from "vue-i18n";
|
||||
import type { UserClient } from "~~/lib/api/user";
|
||||
|
||||
type StatCard = {
|
||||
@@ -7,6 +8,8 @@ type StatCard = {
|
||||
};
|
||||
|
||||
export function statCardData(api: UserClient) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const { data: statistics } = useAsyncData(async () => {
|
||||
const { data } = await api.stats.group();
|
||||
return data;
|
||||
@@ -15,22 +18,22 @@ export function statCardData(api: UserClient) {
|
||||
return computed(() => {
|
||||
return [
|
||||
{
|
||||
label: "Total Value",
|
||||
label: t("home.total_value"),
|
||||
value: statistics.value?.totalItemPrice || 0,
|
||||
type: "currency",
|
||||
},
|
||||
{
|
||||
label: "Total Items",
|
||||
label: t("home.total_items"),
|
||||
value: statistics.value?.totalItems || 0,
|
||||
type: "number",
|
||||
},
|
||||
{
|
||||
label: "Total Locations",
|
||||
label: t("home.total_locations"),
|
||||
value: statistics.value?.totalLocations || 0,
|
||||
type: "number",
|
||||
},
|
||||
{
|
||||
label: "Total Labels",
|
||||
label: t("home.total_labels"),
|
||||
value: statistics.value?.totalLabels || 0,
|
||||
type: "number",
|
||||
},
|
||||
|
||||
@@ -153,35 +153,35 @@
|
||||
|
||||
const ret: Details = [
|
||||
{
|
||||
name: "Quantity",
|
||||
name: "items.quantity",
|
||||
text: item.value?.quantity,
|
||||
slot: "quantity",
|
||||
},
|
||||
{
|
||||
name: "Serial Number",
|
||||
name: "items.serial_number",
|
||||
text: item.value?.serialNumber,
|
||||
copyable: true,
|
||||
},
|
||||
{
|
||||
name: "Model Number",
|
||||
name: "items.model_number",
|
||||
text: item.value?.modelNumber,
|
||||
copyable: true,
|
||||
},
|
||||
{
|
||||
name: "Manufacturer",
|
||||
name: "items.manufacturer",
|
||||
text: item.value?.manufacturer,
|
||||
copyable: true,
|
||||
},
|
||||
{
|
||||
name: "Insured",
|
||||
name: "items.insured",
|
||||
text: item.value?.insured ? "Yes" : "No",
|
||||
},
|
||||
{
|
||||
name: "Archived",
|
||||
name: "items.archived",
|
||||
text: item.value?.archived ? "Yes" : "No",
|
||||
},
|
||||
{
|
||||
name: "Notes",
|
||||
name: "items.notes",
|
||||
type: "markdown",
|
||||
text: item.value?.notes,
|
||||
},
|
||||
@@ -230,28 +230,28 @@
|
||||
const attachmentDetails = computed(() => {
|
||||
const details: Detail[] = [];
|
||||
|
||||
const push = (name: string) => {
|
||||
const push = (name: string, slot: string) => {
|
||||
details.push({
|
||||
name,
|
||||
text: "",
|
||||
slot: name.toLowerCase(),
|
||||
slot,
|
||||
});
|
||||
};
|
||||
|
||||
if (attachments.value.attachments.length > 0) {
|
||||
push("Attachments");
|
||||
push("items.attachments", "attachments");
|
||||
}
|
||||
|
||||
if (attachments.value.warranty.length > 0) {
|
||||
push("Warranty");
|
||||
push("items.warranty", "warranty");
|
||||
}
|
||||
|
||||
if (attachments.value.manuals.length > 0) {
|
||||
push("Manuals");
|
||||
push("items.manuals", "manuals");
|
||||
}
|
||||
|
||||
if (attachments.value.receipts.length > 0) {
|
||||
push("Receipts");
|
||||
push("items.receipts", "receipts");
|
||||
}
|
||||
|
||||
return details;
|
||||
@@ -303,22 +303,22 @@
|
||||
if (preferences.value.showEmpty) {
|
||||
return true;
|
||||
}
|
||||
return item.value?.purchaseFrom || item.value?.purchasePrice !== "0";
|
||||
return item.value?.purchaseFrom || item.value?.purchasePrice !== 0;
|
||||
});
|
||||
|
||||
const purchaseDetails = computed<Details>(() => {
|
||||
const v: Details = [
|
||||
{
|
||||
name: "Purchased From",
|
||||
name: "items.purchased_from",
|
||||
text: item.value?.purchaseFrom || "",
|
||||
},
|
||||
{
|
||||
name: "Purchase Price",
|
||||
text: item.value?.purchasePrice || "",
|
||||
name: "items.purchase_price",
|
||||
text: String(item.value?.purchasePrice) || "",
|
||||
type: "currency",
|
||||
},
|
||||
{
|
||||
name: "Purchase Date",
|
||||
name: "items.purchase_date",
|
||||
text: item.value?.purchaseTime || "",
|
||||
type: "date",
|
||||
date: true,
|
||||
@@ -336,22 +336,22 @@
|
||||
if (preferences.value.showEmpty) {
|
||||
return true;
|
||||
}
|
||||
return item.value?.soldTo || item.value?.soldPrice !== "0";
|
||||
return item.value?.soldTo || item.value?.soldPrice !== 0;
|
||||
});
|
||||
|
||||
const soldDetails = computed<Details>(() => {
|
||||
const v: Details = [
|
||||
{
|
||||
name: "Sold To",
|
||||
name: "items.sold_to",
|
||||
text: item.value?.soldTo || "",
|
||||
},
|
||||
{
|
||||
name: "Sold Price",
|
||||
text: item.value?.soldPrice || "",
|
||||
name: "items.sold_price",
|
||||
text: String(item.value?.soldPrice) || "",
|
||||
type: "currency",
|
||||
},
|
||||
{
|
||||
name: "Sold At",
|
||||
name: "items.sold_at",
|
||||
text: item.value?.soldTime || "",
|
||||
type: "date",
|
||||
date: true,
|
||||
@@ -394,17 +394,17 @@
|
||||
return [
|
||||
{
|
||||
id: "details",
|
||||
name: "Details",
|
||||
name: "global.details",
|
||||
to: `/item/${itemId.value}`,
|
||||
},
|
||||
{
|
||||
id: "log",
|
||||
name: "Maintenance",
|
||||
name: "global.maintenance",
|
||||
to: `/item/${itemId.value}/maintenance`,
|
||||
},
|
||||
{
|
||||
id: "edit",
|
||||
name: "Edit",
|
||||
name: "global.edit",
|
||||
to: `/item/${itemId.value}/edit`,
|
||||
},
|
||||
];
|
||||
@@ -472,15 +472,15 @@
|
||||
<div>
|
||||
<div v-if="fullpath && fullpath.length > 0" class="breadcrumbs py-0 text-sm">
|
||||
<ul class="text-base-content/70">
|
||||
<li v-for="part in fullpath" :key="part.id">
|
||||
<li v-for="part in fullpath" :key="part.id" class="text-wrap">
|
||||
<NuxtLink :to="`/${part.type}/${part.id}`"> {{ part.name }}</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h1 class="pb-1 text-2xl">
|
||||
<h1 class="text-wrap pb-1 text-2xl">
|
||||
{{ item ? item.name : "" }}
|
||||
</h1>
|
||||
<div class="flex flex-wrap gap-1 text-xs">
|
||||
<div class="flex flex-wrap gap-1 text-wrap text-xs">
|
||||
<div>
|
||||
Created
|
||||
<DateTime :date="item?.createdAt" />
|
||||
@@ -509,7 +509,7 @@
|
||||
class="btn btn-sm"
|
||||
:class="`${t.to === currentPath ? 'btn-active' : ''}`"
|
||||
>
|
||||
{{ t.name }}
|
||||
{{ $t(t.name) }}
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
@@ -518,7 +518,7 @@
|
||||
<section>
|
||||
<div class="space-y-6">
|
||||
<BaseCard v-if="!hasNested" collapsable>
|
||||
<template #title> Details </template>
|
||||
<template #title> {{ $t("items.details") }} </template>
|
||||
<template #title-actions>
|
||||
<div class="mt-2 flex flex-wrap items-center justify-between gap-4">
|
||||
<label class="label cursor-pointer">
|
||||
@@ -548,7 +548,7 @@
|
||||
<NuxtPage :item="item" :page-key="itemId" />
|
||||
<template v-if="!hasNested">
|
||||
<BaseCard v-if="photos && photos.length > 0">
|
||||
<template #title> Photos </template>
|
||||
<template #title> {{ $t("items.photos") }} </template>
|
||||
<div
|
||||
class="scroll-bg container mx-auto flex max-h-[500px] flex-wrap gap-2 overflow-y-scroll border-t border-gray-300 p-4"
|
||||
>
|
||||
@@ -559,7 +559,7 @@
|
||||
</BaseCard>
|
||||
|
||||
<BaseCard v-if="showAttachments" collapsable>
|
||||
<template #title> Attachments </template>
|
||||
<template #title> {{ $t("items.attachments") }} </template>
|
||||
<DetailsSection v-if="attachmentDetails.length > 0" :details="attachmentDetails">
|
||||
<template #manuals>
|
||||
<ItemAttachmentsList
|
||||
@@ -596,17 +596,17 @@
|
||||
</BaseCard>
|
||||
|
||||
<BaseCard v-if="showPurchase" collapsable>
|
||||
<template #title> Purchase Details </template>
|
||||
<template #title> {{ $t("items.purchase_details") }} </template>
|
||||
<DetailsSection :details="purchaseDetails" />
|
||||
</BaseCard>
|
||||
|
||||
<BaseCard v-if="showWarranty" collapsable>
|
||||
<template #title> Warranty Details </template>
|
||||
<template #title> {{ $t("items.warranty_details") }} </template>
|
||||
<DetailsSection :details="warrantyDetails" />
|
||||
</BaseCard>
|
||||
|
||||
<BaseCard v-if="showSold" collapsable>
|
||||
<template #title> Sold Details </template>
|
||||
<template #title> {{ $t("items.sold_details") }} </template>
|
||||
<DetailsSection :details="soldDetails" />
|
||||
</BaseCard>
|
||||
</template>
|
||||
@@ -624,13 +624,4 @@
|
||||
dialog::backdrop {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.scroll-bg::-webkit-scrollbar {
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
.scroll-bg::-webkit-scrollbar-thumb {
|
||||
border-radius: 0.25rem;
|
||||
@apply bg-base-300;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import MdiDelete from "~icons/mdi/delete";
|
||||
import MdiPencil from "~icons/mdi/pencil";
|
||||
import MdiContentSaveOutline from "~icons/mdi/content-save-outline";
|
||||
import MdiContentCopy from "~icons/mdi/content-copy";
|
||||
|
||||
definePageMeta({
|
||||
middleware: ["auth"],
|
||||
@@ -59,6 +60,37 @@
|
||||
refresh();
|
||||
});
|
||||
|
||||
async function duplicateItem() {
|
||||
const { error, data } = await api.items.create({
|
||||
name: `${item.value.name} Copy`,
|
||||
description: item.value.description,
|
||||
locationId: item.value.location!.id,
|
||||
parentId: item.value.parent?.id,
|
||||
labelIds: item.value.labels.map(l => l.id),
|
||||
});
|
||||
|
||||
if (error) {
|
||||
toast.error("Failed to duplicate item");
|
||||
return;
|
||||
}
|
||||
|
||||
// add extra fields
|
||||
const { error: updateError } = await api.items.update(data.id, {
|
||||
...item.value,
|
||||
id: data.id,
|
||||
labelIds: data.labels.map(l => l.id),
|
||||
locationId: data.location!.id,
|
||||
name: data.name,
|
||||
});
|
||||
|
||||
if (updateError) {
|
||||
toast.error("Failed to duplicate item");
|
||||
return;
|
||||
}
|
||||
|
||||
navigateTo(`/item/${data.id}`);
|
||||
}
|
||||
|
||||
async function saveItem() {
|
||||
if (!item.value.location?.id) {
|
||||
toast.error("Failed to save item: no location selected");
|
||||
@@ -67,14 +99,20 @@
|
||||
|
||||
let purchasePrice = 0;
|
||||
let soldPrice = 0;
|
||||
let purchaseTime = null;
|
||||
if (item.value.purchasePrice) {
|
||||
purchasePrice = item.value.purchasePrice;
|
||||
}
|
||||
if (item.value.soldPrice) {
|
||||
soldPrice = item.value.soldPrice;
|
||||
}
|
||||
if (item.value.purchaseTime && typeof item.value.purchaseTime !== "string") {
|
||||
purchaseTime = new Date(item.value.purchaseTime.getTime() - item.value.purchaseTime.getTimezoneOffset() * 60000);
|
||||
}
|
||||
|
||||
console.log((item.value.purchasePrice ??= 0));
|
||||
console.log((item.value.soldPrice ??= 0));
|
||||
|
||||
const payload: ItemUpdate = {
|
||||
...item.value,
|
||||
locationId: item.value.location?.id,
|
||||
@@ -83,6 +121,7 @@
|
||||
assetId: item.value.assetId,
|
||||
purchasePrice,
|
||||
soldPrice,
|
||||
purchaseTime: purchaseTime as Date,
|
||||
};
|
||||
|
||||
const { error } = await api.items.update(itemId.value, payload);
|
||||
@@ -143,59 +182,59 @@
|
||||
const mainFields: FormField[] = [
|
||||
{
|
||||
type: "text",
|
||||
label: "Name",
|
||||
label: "items.name",
|
||||
ref: "name",
|
||||
maxLength: 255,
|
||||
minLength: 1,
|
||||
},
|
||||
{
|
||||
type: "number",
|
||||
label: "Quantity",
|
||||
label: "items.quantity",
|
||||
ref: "quantity",
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "Description",
|
||||
label: "items.description",
|
||||
ref: "description",
|
||||
maxLength: 1000,
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: "Serial Number",
|
||||
label: "items.serial_number",
|
||||
ref: "serialNumber",
|
||||
maxLength: 255,
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: "Model Number",
|
||||
label: "items.model_number",
|
||||
ref: "modelNumber",
|
||||
maxLength: 255,
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: "Manufacturer",
|
||||
label: "items.manufacturer",
|
||||
ref: "manufacturer",
|
||||
maxLength: 255,
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "Notes",
|
||||
label: "items.notes",
|
||||
ref: "notes",
|
||||
maxLength: 1000,
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
label: "Insured",
|
||||
label: "items.insured",
|
||||
ref: "insured",
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
label: "Archived",
|
||||
label: "items.archived",
|
||||
ref: "archived",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: "Asset ID",
|
||||
label: "items.asset_id",
|
||||
ref: "assetId",
|
||||
},
|
||||
];
|
||||
@@ -203,18 +242,18 @@
|
||||
const purchaseFields: FormField[] = [
|
||||
{
|
||||
type: "text",
|
||||
label: "Purchased From",
|
||||
label: "items.purchased_from",
|
||||
ref: "purchaseFrom",
|
||||
maxLength: 255,
|
||||
},
|
||||
{
|
||||
type: "number",
|
||||
label: "Purchase Price",
|
||||
label: "items.purchase_price",
|
||||
ref: "purchasePrice",
|
||||
},
|
||||
{
|
||||
type: "date",
|
||||
label: "Purchase Date",
|
||||
label: "items.purchase_date",
|
||||
// @ts-expect-error - we know this is a date
|
||||
ref: "purchaseTime",
|
||||
},
|
||||
@@ -223,18 +262,18 @@
|
||||
const warrantyFields: FormField[] = [
|
||||
{
|
||||
type: "checkbox",
|
||||
label: "Lifetime Warranty",
|
||||
label: "items.lifetime_warranty",
|
||||
ref: "lifetimeWarranty",
|
||||
},
|
||||
{
|
||||
type: "date",
|
||||
label: "Warranty Expires",
|
||||
label: "items.warranty_expires",
|
||||
// @ts-expect-error - we know this is a date
|
||||
ref: "warrantyExpires",
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "Warranty Notes",
|
||||
label: "items.warranty_details",
|
||||
ref: "warrantyDetails",
|
||||
maxLength: 1000,
|
||||
},
|
||||
@@ -243,18 +282,18 @@
|
||||
const soldFields: FormField[] = [
|
||||
{
|
||||
type: "text",
|
||||
label: "Sold To",
|
||||
label: "items.sold_to",
|
||||
ref: "soldTo",
|
||||
maxLength: 255,
|
||||
},
|
||||
{
|
||||
type: "number",
|
||||
label: "Sold Price",
|
||||
label: "items.sold_price",
|
||||
ref: "soldPrice",
|
||||
},
|
||||
{
|
||||
type: "date",
|
||||
label: "Sold At",
|
||||
label: "items.sold_at",
|
||||
// @ts-expect-error - we know this is a date
|
||||
ref: "soldTime",
|
||||
},
|
||||
@@ -521,32 +560,38 @@
|
||||
|
||||
<section class="relative">
|
||||
<div class="sticky top-1 z-10 my-4 flex items-center justify-end gap-2">
|
||||
<div class="tooltip tooltip-right mr-auto" data-tip="Show Advanced View Options">
|
||||
<div class="tooltip tooltip-right mr-auto" :data-tip="$t('items.show_advanced_view_options')">
|
||||
<label class="label mr-auto cursor-pointer">
|
||||
<input v-model="preferences.editorAdvancedView" type="checkbox" class="toggle toggle-primary" />
|
||||
<span class="label-text ml-4"> Advanced </span>
|
||||
<span class="label-text ml-4"> {{ $t("items.advanced") }} </span>
|
||||
</label>
|
||||
</div>
|
||||
<BaseButton size="sm" class="btn" @click="duplicateItem">
|
||||
<template #icon>
|
||||
<MdiContentCopy />
|
||||
</template>
|
||||
{{ $t("global.duplicate") }}
|
||||
</BaseButton>
|
||||
<BaseButton size="sm" @click="saveItem">
|
||||
<template #icon>
|
||||
<MdiContentSaveOutline />
|
||||
</template>
|
||||
Save
|
||||
{{ $t("global.save") }}
|
||||
</BaseButton>
|
||||
<BaseButton class="btn btn-error btn-sm" @click="deleteItem()">
|
||||
<MdiDelete class="mr-2" />
|
||||
Delete
|
||||
{{ $t("global.delete") }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
<div v-if="!requestPending" class="space-y-6">
|
||||
<BaseCard class="overflow-visible">
|
||||
<template #title> Edit Details </template>
|
||||
<template #title> {{ $t("items.edit_details") }} </template>
|
||||
<template #title-actions>
|
||||
<div class="mt-2 flex flex-wrap items-center justify-between gap-4"></div>
|
||||
</template>
|
||||
<div class="mb-6 grid gap-4 border-t px-5 pt-2 md:grid-cols-2">
|
||||
<LocationSelector v-model="item.location" @update:model-value="informAboutDesyncingLocationFromParent()" />
|
||||
<FormMultiselect v-model="item.labels" label="Labels" :items="labels ?? []" />
|
||||
<FormMultiselect v-model="item.labels" :label="$t('global.labels')" :items="labels ?? []" />
|
||||
<FormToggle v-model="item.syncChildItemsLocations" label="Sync child items' locations" inline @update:model-value="syncChildItemsLocations()" />
|
||||
<Autocomplete
|
||||
v-if="preferences.editorAdvancedView"
|
||||
@@ -554,7 +599,7 @@
|
||||
v-model:search="query"
|
||||
:items="results"
|
||||
item-text="name"
|
||||
label="Parent Item"
|
||||
:label="$t('items.parent_item')"
|
||||
no-results-text="Type to search..."
|
||||
@update:model-value="maybeSyncWithParentLocation()"
|
||||
/>
|
||||
@@ -566,7 +611,7 @@
|
||||
<FormTextArea
|
||||
v-if="field.type === 'textarea'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
:max-length="field.maxLength"
|
||||
:min-length="field.minLength"
|
||||
@@ -574,7 +619,7 @@
|
||||
<FormTextField
|
||||
v-else-if="field.type === 'text'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
type="text"
|
||||
:max-length="field.maxLength"
|
||||
@@ -584,19 +629,19 @@
|
||||
v-else-if="field.type === 'number'"
|
||||
v-model.number="item[field.ref]"
|
||||
type="number"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
<FormDatePicker
|
||||
v-else-if="field.type === 'date'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
<FormCheckbox
|
||||
v-else-if="field.type === 'checkbox'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
</div>
|
||||
@@ -605,7 +650,7 @@
|
||||
</BaseCard>
|
||||
|
||||
<BaseCard>
|
||||
<template #title> Custom Fields </template>
|
||||
<template #title> {{ $t("items.custom_fields") }} </template>
|
||||
<div class="space-y-4 divide-y divide-gray-300 border-t px-5">
|
||||
<div
|
||||
v-for="(field, idx) in item.fields"
|
||||
@@ -613,10 +658,10 @@
|
||||
class="grid grid-cols-2 gap-2 md:grid-cols-4"
|
||||
>
|
||||
<!-- <FormSelect v-model:value="field.type" label="Field Type" :items="fieldTypes" value-key="value" /> -->
|
||||
<FormTextField v-model="field.name" label="Name" />
|
||||
<FormTextField v-model="field.name" :label="$t('global.name')" />
|
||||
<div class="col-span-3 flex items-end">
|
||||
<FormTextField v-model="field.textValue" label="Value" :max-length="500" />
|
||||
<div class="tooltip" data-tip="Delete">
|
||||
<FormTextField v-model="field.textValue" :label="$t('global.value')" :max-length="500" />
|
||||
<div class="tooltip" :data-tip="$t('global.delete')">
|
||||
<button class="btn btn-square btn-sm mb-2 ml-2" @click="item.fields.splice(idx, 1)">
|
||||
<MdiDelete />
|
||||
</button>
|
||||
@@ -625,7 +670,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 flex justify-end px-5 pb-4">
|
||||
<BaseButton size="sm" @click="addField"> Add </BaseButton>
|
||||
<BaseButton size="sm" @click="addField"> {{ $t("global.add") }} </BaseButton>
|
||||
</div>
|
||||
</BaseCard>
|
||||
|
||||
@@ -635,16 +680,16 @@
|
||||
class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg"
|
||||
>
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg font-medium leading-6">Attachments</h3>
|
||||
<p class="text-xs">Changes to attachments will be saved immediately</p>
|
||||
<h3 class="text-lg font-medium leading-6">{{ $t("items.attachments") }}</h3>
|
||||
<p class="text-xs">{{ $t("items.changes_persisted_immediately") }}</p>
|
||||
</div>
|
||||
<div class="border-t border-gray-300 p-4">
|
||||
<div v-if="attDropZoneActive" class="grid grid-cols-4 gap-4">
|
||||
<DropZone @drop="dropPhoto"> Photo </DropZone>
|
||||
<DropZone @drop="dropWarranty"> Warranty </DropZone>
|
||||
<DropZone @drop="dropManual"> Manual </DropZone>
|
||||
<DropZone @drop="dropAttachment"> Attachment </DropZone>
|
||||
<DropZone @drop="dropReceipt"> Receipt </DropZone>
|
||||
<DropZone @drop="dropPhoto"> {{ $t("items.photos") }} </DropZone>
|
||||
<DropZone @drop="dropWarranty"> {{ $t("items.warranty") }} </DropZone>
|
||||
<DropZone @drop="dropManual"> {{ $t("items.manuals") }} </DropZone>
|
||||
<DropZone @drop="dropAttachment"> {{ $t("items.attachments") }} </DropZone>
|
||||
<DropZone @drop="dropReceipt"> {{ $t("items.receipts") }} </DropZone>
|
||||
</div>
|
||||
<button
|
||||
v-else
|
||||
@@ -652,7 +697,7 @@
|
||||
@click="clickUpload"
|
||||
>
|
||||
<input ref="refAttachmentInput" hidden type="file" @change="uploadImage" />
|
||||
<p>Drag and drop files here or click to select files</p>
|
||||
<p>{{ $t("items.drag_and_drop") }}</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -667,15 +712,15 @@
|
||||
{{ attachment.document.title }}
|
||||
</p>
|
||||
<p class="my-auto">
|
||||
{{ capitalize(attachment.type) }}
|
||||
{{ $t(`items.${attachment.type}`) }}
|
||||
</p>
|
||||
<div class="flex justify-end gap-2">
|
||||
<div class="tooltip" data-tip="Delete">
|
||||
<div class="tooltip" :data-tip="$t('global.delete')">
|
||||
<button class="btn btn-square btn-sm" @click="deleteAttachment(attachment.id)">
|
||||
<MdiDelete />
|
||||
</button>
|
||||
</div>
|
||||
<div class="tooltip" data-tip="Edit">
|
||||
<div class="tooltip" :data-tip="$t('global.edit')">
|
||||
<button class="btn btn-square btn-sm" @click="openAttachmentEditDialog(attachment)">
|
||||
<MdiPencil />
|
||||
</button>
|
||||
@@ -688,7 +733,7 @@
|
||||
|
||||
<div v-if="preferences.editorAdvancedView" class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg font-medium leading-6">Purchase Details</h3>
|
||||
<h3 class="text-lg font-medium leading-6">{{ $t("items.purchase_details") }}</h3>
|
||||
</div>
|
||||
<div class="border-t border-gray-300 sm:p-0">
|
||||
<div
|
||||
@@ -700,7 +745,7 @@
|
||||
<FormTextArea
|
||||
v-if="field.type === 'textarea'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
:max-length="field.maxLength"
|
||||
:min-length="field.minLength"
|
||||
@@ -708,7 +753,7 @@
|
||||
<FormTextField
|
||||
v-else-if="field.type === 'text'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
:max-length="field.maxLength"
|
||||
:min-length="field.minLength"
|
||||
@@ -717,19 +762,19 @@
|
||||
v-else-if="field.type === 'number'"
|
||||
v-model.number="item[field.ref]"
|
||||
type="number"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
<FormDatePicker
|
||||
v-else-if="field.type === 'date'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
<FormCheckbox
|
||||
v-else-if="field.type === 'checkbox'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
</div>
|
||||
@@ -739,7 +784,7 @@
|
||||
|
||||
<div v-if="preferences.editorAdvancedView" class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg font-medium leading-6">Warranty Details</h3>
|
||||
<h3 class="text-lg font-medium leading-6">{{ $t("items.warranty_details") }}</h3>
|
||||
</div>
|
||||
<div class="border-t border-gray-300 sm:p-0">
|
||||
<div
|
||||
@@ -751,7 +796,7 @@
|
||||
<FormTextArea
|
||||
v-if="field.type === 'textarea'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
:max-length="field.maxLength"
|
||||
:min-length="field.minLength"
|
||||
@@ -759,7 +804,7 @@
|
||||
<FormTextField
|
||||
v-else-if="field.type === 'text'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
:max-length="field.maxLength"
|
||||
:min-length="field.minLength"
|
||||
@@ -768,19 +813,19 @@
|
||||
v-else-if="field.type === 'number'"
|
||||
v-model.number="item[field.ref]"
|
||||
type="number"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
<FormDatePicker
|
||||
v-else-if="field.type === 'date'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
<FormCheckbox
|
||||
v-else-if="field.type === 'checkbox'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
</div>
|
||||
@@ -798,7 +843,7 @@
|
||||
<FormTextArea
|
||||
v-if="field.type === 'textarea'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
:max-length="field.maxLength"
|
||||
:min-length="field.minLength"
|
||||
@@ -806,7 +851,7 @@
|
||||
<FormTextField
|
||||
v-else-if="field.type === 'text'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
:max-length="field.maxLength"
|
||||
:min-length="field.minLength"
|
||||
@@ -815,19 +860,19 @@
|
||||
v-else-if="field.type === 'number'"
|
||||
v-model.number="item[field.ref]"
|
||||
type="number"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
<FormDatePicker
|
||||
v-else-if="field.type === 'date'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
<FormCheckbox
|
||||
v-else-if="field.type === 'checkbox'"
|
||||
v-model="item[field.ref]"
|
||||
:label="field.label"
|
||||
:label="$t(field.label)"
|
||||
inline
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -76,7 +76,10 @@
|
||||
|
||||
const items = computedAsync(async () => {
|
||||
if (!label.value) {
|
||||
return [];
|
||||
return {
|
||||
items: [],
|
||||
totalPrice: null,
|
||||
};
|
||||
}
|
||||
|
||||
const resp = await api.items.getAll({
|
||||
@@ -85,7 +88,10 @@
|
||||
|
||||
if (resp.error) {
|
||||
toast.error("Failed to load items");
|
||||
return [];
|
||||
return {
|
||||
items: [],
|
||||
totalPrice: null,
|
||||
};
|
||||
}
|
||||
|
||||
return resp.data;
|
||||
@@ -95,18 +101,22 @@
|
||||
<template>
|
||||
<BaseContainer>
|
||||
<BaseModal v-model="updateModal">
|
||||
<template #title> Update Label </template>
|
||||
<template #title> {{ $t("labels.update_label") }} </template>
|
||||
<form v-if="label" @submit.prevent="update">
|
||||
<FormTextField
|
||||
v-model="updateData.name"
|
||||
:autofocus="true"
|
||||
label="Label Name"
|
||||
:label="$t('components.label.create_modal.label_name')"
|
||||
:max-length="255"
|
||||
:min-length="1"
|
||||
/>
|
||||
<FormTextArea v-model="updateData.description" label="Label Description" :max-length="255" />
|
||||
<FormTextArea
|
||||
v-model="updateData.description"
|
||||
:label="$t('components.label.create_modal.label_description')"
|
||||
:max-length="255"
|
||||
/>
|
||||
<div class="modal-action">
|
||||
<BaseButton type="submit" :loading="updating"> Update </BaseButton>
|
||||
<BaseButton type="submit" :loading="updating"> {{ $t("global.update") }} </BaseButton>
|
||||
</div>
|
||||
</form>
|
||||
</BaseModal>
|
||||
|
||||
@@ -109,13 +109,23 @@
|
||||
<div>
|
||||
<!-- Update Dialog -->
|
||||
<BaseModal v-model="updateModal">
|
||||
<template #title> Update Location </template>
|
||||
<template #title> {{ $t("locations.update_location") }} </template>
|
||||
<form v-if="location" @submit.prevent="update">
|
||||
<FormTextField v-model="updateData.name" :autofocus="true" label="Location Name" :max-length="255" :min-length="1" />
|
||||
<FormTextArea v-model="updateData.description" label="Location Description" :max-length="1000" />
|
||||
<FormTextField
|
||||
v-model="updateData.name"
|
||||
:autofocus="true"
|
||||
:label="$t('components.location.create_modal.location_name')"
|
||||
:max-length="255"
|
||||
:min-length="1"
|
||||
/>
|
||||
<FormTextArea
|
||||
v-model="updateData.description"
|
||||
:label="$t('components.location.create_modal.location_description')"
|
||||
:max-length="1000"
|
||||
/>
|
||||
<LocationSelector v-model="parent" />
|
||||
<div class="modal-action">
|
||||
<BaseButton type="submit" :loading="updating"> Update </BaseButton>
|
||||
<BaseButton type="submit" :loading="updating"> {{ $t("global.update") }} </BaseButton>
|
||||
</div>
|
||||
</form>
|
||||
</BaseModal>
|
||||
@@ -152,7 +162,7 @@
|
||||
</h1>
|
||||
<div class="flex flex-wrap gap-1 text-xs">
|
||||
<div>
|
||||
Created
|
||||
{{ $t("global.created") }}
|
||||
<DateTime :date="location?.createdAt" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -162,12 +172,12 @@
|
||||
<PageQRCode class="dropdown-left" />
|
||||
<BaseButton size="sm" @click="openUpdate">
|
||||
<MdiPencil class="mr-1" name="mdi-pencil" />
|
||||
Edit
|
||||
{{ $t("global.edit") }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
<BaseButton class="btn btn-sm" @click="confirmDelete()">
|
||||
<MdiDelete name="mdi-delete" class="mr-2" />
|
||||
Delete
|
||||
{{ $t("global.delete") }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,7 +190,7 @@
|
||||
</section>
|
||||
|
||||
<section v-if="location && location.children.length > 0" class="mt-6">
|
||||
<BaseSectionHeader class="mb-5"> Child Locations </BaseSectionHeader>
|
||||
<BaseSectionHeader class="mb-5"> {{ $t("locations.child_locations") }} </BaseSectionHeader>
|
||||
<div class="grid grid-cols-1 gap-2 sm:grid-cols-3">
|
||||
<LocationCard v-for="item in location.children" :key="item.id" :location="item" />
|
||||
</div>
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<div class="p-4">
|
||||
<div class="mb-2 flex justify-end">
|
||||
<div class="btn-group">
|
||||
<button class="btn tooltip tooltip-top btn-sm" data-tip="Collapse Tree" @click="closeAll">
|
||||
<button class="btn tooltip tooltip-top btn-sm" :data-tip="$t('locations.collapse_tree')" @click="closeAll">
|
||||
<MdiCollapseAllOutline />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -105,11 +105,11 @@
|
||||
console.log(auth.user);
|
||||
return [
|
||||
{
|
||||
name: "Name",
|
||||
name: "global.name",
|
||||
text: auth.user?.name || "Unknown",
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
name: "global.email",
|
||||
text: auth.user?.email || "Unknown",
|
||||
},
|
||||
] as Detail[];
|
||||
@@ -376,14 +376,19 @@
|
||||
<label class="label">
|
||||
<span class="label-text">{{ $t("profile.language") }}</span>
|
||||
</label>
|
||||
<select v-model="$i18n.locale" class="select select-bordered">
|
||||
<select
|
||||
v-model="$i18n.locale"
|
||||
class="select select-bordered"
|
||||
@change="
|
||||
event => {
|
||||
setLanguage((event.target as HTMLSelectElement).value);
|
||||
}
|
||||
"
|
||||
>
|
||||
<option v-for="lang in $i18n.availableLocales" :key="lang" :value="lang">
|
||||
{{ $t(`languages.${lang}`) }}
|
||||
{{ $t(`languages.${lang}`) }} ({{ $t(`languages.${lang}`, 1, { locale: lang }) }})
|
||||
</option>
|
||||
</select>
|
||||
<div class="mt-4">
|
||||
<BaseButton size="sm" @click="setLanguage($i18n.locale)"> {{ $t("profile.update_language") }} </BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</BaseCard>
|
||||
|
||||
@@ -447,7 +452,7 @@
|
||||
|
||||
<div v-if="group && currencies && currencies.length > 0" class="p-5 pt-0">
|
||||
<FormSelect v-model="currency" :label="$t('profile.currency_format')" :items="currencies" />
|
||||
<p class="m-2 text-sm">Example: {{ currencyExample }}</p>
|
||||
<p class="m-2 text-sm">{{ $t("profile.example") }}: {{ currencyExample }}</p>
|
||||
|
||||
<div class="mt-4">
|
||||
<BaseButton size="sm" @click="updateGroup"> {{ $t("profile.update_group") }} </BaseButton>
|
||||
|
||||
@@ -200,7 +200,9 @@
|
||||
const { data, error } = await api.items.getAll();
|
||||
|
||||
if (error) {
|
||||
return [];
|
||||
return {
|
||||
items: [],
|
||||
};
|
||||
}
|
||||
|
||||
return data;
|
||||
@@ -219,7 +221,12 @@
|
||||
|
||||
const items: LabelData[] = [];
|
||||
for (let i = displayProperties.assetRange; i < displayProperties.assetRangeMax; i++) {
|
||||
items.push(getItem(i, allFields?.value?.items?.[i] ?? null));
|
||||
const item = allFields?.value?.items?.[i];
|
||||
if (item?.location) {
|
||||
items.push(getItem(i, item as { location: { name: string }; name: string }));
|
||||
} else {
|
||||
items.push(getItem(i, null));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
});
|
||||
@@ -419,6 +426,7 @@
|
||||
<img
|
||||
:src="item.url"
|
||||
:style="{
|
||||
minWidth: `${out.card.height * 0.9}in`,
|
||||
width: `${out.card.height * 0.9}in`,
|
||||
height: `${out.card.height * 0.9}in`,
|
||||
}"
|
||||
@@ -427,8 +435,8 @@
|
||||
<div class="ml-2 flex flex-col justify-center">
|
||||
<div class="font-bold">{{ item.assetID }}</div>
|
||||
<div class="text-xs font-light italic">Homebox</div>
|
||||
<div>{{ item.name }}</div>
|
||||
<div>{{ item.location }}</div>
|
||||
<div class="overflow-hidden text-wrap text-xs">{{ item.name }}</div>
|
||||
<div class="text-xs">{{ item.location }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<div class="divide-y divide-gray-300 border-t border-gray-300 px-6 pb-3">
|
||||
<DetailAction @action="modals.import = true">
|
||||
<template #title> {{ $t("tools.import_export_set.import") }} </template>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div v-html="$t('tools.import_export_set.import_sub')"></div>
|
||||
<template #button> {{ $t("tools.import_export_set.import_button") }} </template>
|
||||
</DetailAction>
|
||||
@@ -55,6 +56,7 @@
|
||||
<MdiAlert class="mr-2" />
|
||||
<span> {{ $t("tools.actions") }} </span>
|
||||
<template #description>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div v-html="$t('tools.actions_sub')"></div>
|
||||
</template>
|
||||
</BaseSectionHeader>
|
||||
@@ -72,11 +74,13 @@
|
||||
</DetailAction>
|
||||
<DetailAction @action="resetItemDateTimes">
|
||||
<template #title> {{ $t("tools.actions_set.zero_datetimes") }} </template>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div v-html="$t('tools.actions_set.zero_datetimes_sub')"></div>
|
||||
<template #button> {{ $t("tools.actions_set.zero_datetimes_button") }} </template>
|
||||
</DetailAction>
|
||||
<DetailAction @action="setPrimaryPhotos">
|
||||
<template #title> {{ $t("tools.actions_set.set_primary_photo") }} </template>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div v-html="$t('tools.actions_set.set_primary_photo_sub')"></div>
|
||||
<template #button> {{ $t("tools.actions_set.set_primary_photo_button") }} </template>
|
||||
</DetailAction>
|
||||
|
||||
@@ -32,7 +32,7 @@ export default defineNuxtPlugin(({ vueApp }) => {
|
||||
vueApp.use(i18n);
|
||||
});
|
||||
|
||||
export const messages: Object = () => {
|
||||
export const messages = () => {
|
||||
const messages: Record<string, any> = {};
|
||||
const modules = import.meta.glob("~//locales/**.json", { eager: true });
|
||||
for (const path in modules) {
|
||||
|
||||
37
frontend/pnpm-lock.yaml
generated
37
frontend/pnpm-lock.yaml
generated
@@ -105,6 +105,9 @@ importers:
|
||||
'@vite-pwa/nuxt':
|
||||
specifier: ^0.5.0
|
||||
version: 0.5.0(magicast@0.3.5)(rollup@4.24.0)(vite@4.5.5(@types/node@22.7.4)(terser@5.34.1))(webpack-sources@3.2.3)(workbox-build@7.1.1)(workbox-window@7.1.0)
|
||||
'@vue/runtime-core':
|
||||
specifier: ^3.5.12
|
||||
version: 3.5.12
|
||||
eslint:
|
||||
specifier: ^8.57.1
|
||||
version: 8.57.1
|
||||
@@ -2083,9 +2086,15 @@ packages:
|
||||
'@vue/reactivity@3.4.8':
|
||||
resolution: {integrity: sha512-UJYMQ3S2rqIGw9IvKomD4Xw2uS5VlcKEEmwcfboGOdrI79oqebxnCgTvXWLMClvg3M5SF0Cyn+9eDQoyGMLu9Q==}
|
||||
|
||||
'@vue/reactivity@3.5.12':
|
||||
resolution: {integrity: sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==}
|
||||
|
||||
'@vue/runtime-core@3.4.8':
|
||||
resolution: {integrity: sha512-sMRXOy89KnwY6fWG5epgPOsCWzpo/64FrA0QkjIeNeGnoA2YyZ6bBUxpFUyqhJ8VbrDhXEFH+6LHMOYrpzX/ZQ==}
|
||||
|
||||
'@vue/runtime-core@3.5.12':
|
||||
resolution: {integrity: sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==}
|
||||
|
||||
'@vue/runtime-dom@3.4.8':
|
||||
resolution: {integrity: sha512-L4gZcYo8f3d7rQqQIHkPvyczkjjQ55cJqz2G0v6Ptmqa1mO2zkqN9F8lBT6aGPYy3hd0RDiINbs4jxhSvvy10Q==}
|
||||
|
||||
@@ -2100,6 +2109,9 @@ packages:
|
||||
'@vue/shared@3.5.11':
|
||||
resolution: {integrity: sha512-W8GgysJVnFo81FthhzurdRAWP/byq3q2qIw70e0JWblzVhjgOMiC2GyovXrZTFQJnFVryYaKGP3Tc9vYzYm6PQ==}
|
||||
|
||||
'@vue/shared@3.5.12':
|
||||
resolution: {integrity: sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==}
|
||||
|
||||
'@vuepic/vue-datepicker@8.8.1':
|
||||
resolution: {integrity: sha512-8ehfUz1m69Vuc16Pm4ukgb3Mg1VT14x4EsG1ag4O/qbSNRWztTo+pUV4JnFt0FGLl5gGb6NXlxIvR7EjLgD7Gg==}
|
||||
peerDependencies:
|
||||
@@ -7271,7 +7283,7 @@ snapshots:
|
||||
|
||||
'@nuxtjs/eslint-config-typescript@12.1.0(eslint@8.57.1)(typescript@5.6.2)':
|
||||
dependencies:
|
||||
'@nuxtjs/eslint-config': 12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
|
||||
'@nuxtjs/eslint-config': 12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.2)
|
||||
eslint: 8.57.1
|
||||
@@ -7285,10 +7297,10 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@nuxtjs/eslint-config@12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)':
|
||||
'@nuxtjs/eslint-config@12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)':
|
||||
dependencies:
|
||||
eslint: 8.57.1
|
||||
eslint-config-standard: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-config-standard: 17.1.0(eslint-plugin-import@2.31.0)(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.57.1)
|
||||
eslint-plugin-node: 11.1.0(eslint@8.57.1)
|
||||
@@ -7953,11 +7965,20 @@ snapshots:
|
||||
dependencies:
|
||||
'@vue/shared': 3.4.8
|
||||
|
||||
'@vue/reactivity@3.5.12':
|
||||
dependencies:
|
||||
'@vue/shared': 3.5.12
|
||||
|
||||
'@vue/runtime-core@3.4.8':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.4.8
|
||||
'@vue/shared': 3.4.8
|
||||
|
||||
'@vue/runtime-core@3.5.12':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.12
|
||||
'@vue/shared': 3.5.12
|
||||
|
||||
'@vue/runtime-dom@3.4.8':
|
||||
dependencies:
|
||||
'@vue/runtime-core': 3.4.8
|
||||
@@ -7974,6 +7995,8 @@ snapshots:
|
||||
|
||||
'@vue/shared@3.5.11': {}
|
||||
|
||||
'@vue/shared@3.5.12': {}
|
||||
|
||||
'@vuepic/vue-datepicker@8.8.1(vue@3.4.8(typescript@5.6.2))':
|
||||
dependencies:
|
||||
date-fns: 3.6.0
|
||||
@@ -8981,7 +9004,7 @@ snapshots:
|
||||
dependencies:
|
||||
eslint: 8.57.1
|
||||
|
||||
eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0)(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
eslint: 8.57.1
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
@@ -9002,7 +9025,7 @@ snapshots:
|
||||
debug: 4.3.7
|
||||
enhanced-resolve: 5.17.1
|
||||
eslint: 8.57.1
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.8.1
|
||||
is-bun-module: 1.2.1
|
||||
@@ -9015,7 +9038,7 @@ snapshots:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
@@ -9049,7 +9072,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.15.1
|
||||
is-glob: 4.0.3
|
||||
|
||||
@@ -2,6 +2,7 @@ import path from "path";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
// @ts-ignore
|
||||
test: {
|
||||
globalSetup: "./test/setup.ts",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user