1
Fork 0

Add UI for album downloads

This commit is contained in:
viktorstrate 2021-09-26 13:10:37 +02:00
parent 80c2019b3f
commit 929da08ea2
No known key found for this signature in database
GPG Key ID: 3F855605109C1E8A
29 changed files with 678 additions and 328 deletions

View File

@ -102,7 +102,7 @@ func (p *MediaURL) CachedPath() (string, error) {
return "", errors.New("mediaURL.Media is nil")
}
if p.Purpose == PhotoThumbnail || p.Purpose == PhotoHighRes || p.Purpose == VideoThumbnail {
if p.Purpose == PhotoThumbnail || p.Purpose == PhotoHighRes || p.Purpose == VideoThumbnail || p.Purpose == VideoWeb {
cachedPath = path.Join(utils.MediaCachePath(), strconv.Itoa(int(p.Media.AlbumID)), strconv.Itoa(int(p.MediaID)), p.MediaName)
} else if p.Purpose == MediaOriginal {
cachedPath = p.Media.Path

View File

@ -6,6 +6,7 @@ import (
"github.com/photoview/photoview/api/graphql/auth"
"github.com/photoview/photoview/api/graphql/models"
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
@ -63,7 +64,7 @@ func shareTokenFromRequest(db *gorm.DB, r *http.Request, mediaID *int, albumID *
// Check if photo is authorized with a share token
token := r.URL.Query().Get("token")
if token == "" {
return false, "unauthorized", http.StatusForbidden, nil
return false, "unauthorized", http.StatusForbidden, errors.New("share token not provided")
}
var shareToken models.ShareToken
@ -76,14 +77,14 @@ func shareTokenFromRequest(db *gorm.DB, r *http.Request, mediaID *int, albumID *
if shareToken.Password != nil {
tokenPasswordCookie, err := r.Cookie(fmt.Sprintf("share-token-pw-%s", shareToken.Value))
if err != nil {
return false, "unauthorized", http.StatusForbidden, nil
return false, "unauthorized", http.StatusForbidden, errors.Wrap(err, "get share token password cookie")
}
// tokenPassword := r.Header.Get("TokenPassword")
tokenPassword := tokenPasswordCookie.Value
if err := bcrypt.CompareHashAndPassword([]byte(*shareToken.Password), []byte(tokenPassword)); err != nil {
if err == bcrypt.ErrMismatchedHashAndPassword {
return false, "unauthorized", http.StatusForbidden, nil
return false, "unauthorized", http.StatusForbidden, errors.New("incorrect password for share token")
} else {
return false, "internal server error", http.StatusInternalServerError, err
}
@ -91,11 +92,11 @@ func shareTokenFromRequest(db *gorm.DB, r *http.Request, mediaID *int, albumID *
}
if shareToken.AlbumID != nil && albumID == nil {
return false, "unauthorized", http.StatusForbidden, nil
return false, "unauthorized", http.StatusForbidden, errors.New("share token is of type album, but no albumID was provided to function")
}
if shareToken.MediaID != nil && mediaID == nil {
return false, "unauthorized", http.StatusForbidden, nil
return false, "unauthorized", http.StatusForbidden, errors.New("share token is of type media, but no mediaID was provided to function")
}
if shareToken.AlbumID != nil && *albumID != *shareToken.AlbumID {
@ -116,12 +117,12 @@ func shareTokenFromRequest(db *gorm.DB, r *http.Request, mediaID *int, albumID *
}
if count == 0 {
return false, "unauthorized", http.StatusForbidden, nil
return false, "unauthorized", http.StatusForbidden, errors.New("no child albums found for share token")
}
}
if shareToken.MediaID != nil && *mediaID != *shareToken.MediaID {
return false, "unauthorized", http.StatusForbidden, nil
return false, "unauthorized", http.StatusForbidden, errors.New("media share token does not match mediaID")
}
return true, "", 0, nil

View File

@ -55,7 +55,7 @@ func RegisterDownloadRoutes(db *gorm.DB, router *mux.Router) {
zipWriter := zip.NewWriter(w)
for _, media := range mediaURLs {
zipFile, err := zipWriter.Create(media.MediaName)
zipFile, err := zipWriter.Create(fmt.Sprintf("%s/%s", album.Title, media.MediaName))
if err != nil {
log.Printf("ERROR: Failed to create a file in zip, when downloading album (%d): %v\n", album.ID, err)
w.WriteHeader(http.StatusInternalServerError)

View File

@ -13,7 +13,7 @@ import SharePage, {
VALIDATE_TOKEN_PASSWORD_QUERY,
} from './SharePage'
import { SIDEBAR_DOWNLOAD_QUERY } from '../../components/sidebar/SidebarDownload'
import { SIDEBAR_DOWNLOAD_QUERY } from '../../components/sidebar/SidebarDownloadMedia'
import { SHARE_ALBUM_QUERY } from './AlbumSharePage'
jest.mock('../../hooks/useScrollPagination')

View File

@ -17,9 +17,11 @@ import { MessageState } from './components/messages/Messages'
import { Message } from './components/messages/SubscriptionsHook'
import { NotificationType } from './__generated__/globalTypes'
export const GRAPHQL_ENDPOINT = process.env.REACT_APP_API_ENDPOINT
? urlJoin(process.env.REACT_APP_API_ENDPOINT as string, '/graphql')
: urlJoin(location.origin, '/api/graphql')
export const API_ENDPOINT = process.env.REACT_APP_API_ENDPOINT
? (process.env.REACT_APP_API_ENDPOINT as string)
: urlJoin(location.origin, '/api')
export const GRAPHQL_ENDPOINT = urlJoin(API_ENDPOINT, '/graphql')
const httpLink = new HttpLink({
uri: GRAPHQL_ENDPOINT,

View File

@ -65,7 +65,7 @@ export const SidebarPhotoCover = ({ cover_id }: SidebarPhotoCoverProps) => {
return (
<SidebarSection>
<SidebarSectionTitle>
{t('sidebar.album.cover_photo', 'Album cover')}
{t('sidebar.album.album_cover', 'Album cover')}
</SidebarSectionTitle>
<div>
<table className="border-collapse w-full">

View File

@ -8,6 +8,7 @@ import {
getAlbumSidebarVariables,
} from './__generated__/getAlbumSidebar'
import { SidebarAlbumCover } from './AlbumCovers'
import SidebarAlbumDownload from './SidebarDownloadAlbum'
const albumQuery = gql`
query getAlbumSidebar($id: ID!) {
@ -50,6 +51,9 @@ const AlbumSidebar = ({ albumId }: AlbumSidebarProps) => {
<div className="mt-8">
<SidebarAlbumCover id={albumId} />
</div>
<div className="mt-8">
<SidebarAlbumDownload albumID={albumId} />
</div>
</div>
)
}

View File

@ -8,7 +8,7 @@ import {
ProtectedVideoProps_Media,
} from '../photoGallery/ProtectedMedia'
import { SidebarPhotoShare } from './Sharing'
import SidebarDownload from './SidebarDownload'
import SidebarMediaDownload from './SidebarDownloadMedia'
import SidebarItem from './SidebarItem'
import { SidebarFacesOverlay } from '../facesOverlay/FacesOverlay'
import { isNil } from '../../helpers/utils'
@ -364,7 +364,7 @@ const SidebarContent = ({ media, hidePreview }: SidebarContentProps) => {
)}
</div>
<MetadataInfo media={media} />
<SidebarDownload media={media} />
<SidebarMediaDownload media={media} />
<SidebarPhotoShare id={media.id} />
<div className="mt-8">
<SidebarPhotoCover cover_id={media.id} />

View File

@ -0,0 +1,85 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import { API_ENDPOINT } from '../../apolloClient'
import { SidebarSection, SidebarSectionTitle } from './SidebarComponents'
type SidebarAlbumDownladProps = {
albumID: string
}
const SidebarAlbumDownload = ({ albumID }: SidebarAlbumDownladProps) => {
const { t } = useTranslation()
const downloads = [
{
title: t('sidebar.album.download.thumbnails.title', 'Thumbnails'),
description: t(
'sidebar.album.download.thumbnails.description',
'Low resolution images, no videos'
),
purpose: 'thumbnail,video-thumbnail',
},
{
title: t(
'sidebar.album.download.high-resolutions.title',
'High resolutions'
),
description: t(
'sidebar.album.download.high-resolutions.description',
'High resolution jpegs of RAW images'
),
purpose: 'high-res',
},
{
title: t('sidebar.album.download.originals.title', 'Originals'),
description: t(
'sidebar.album.download.originals.description',
'The original images and videos'
),
purpose: 'original',
},
{
title: t('sidebar.album.download.web-videos.title', 'Converted videos'),
description: t(
'sidebar.album.download.web-videos.description',
'Videos that have been optimized for web'
),
purpose: 'video-web',
},
]
const downloadRows = downloads.map(x => (
<tr
className="cursor-pointer border-gray-100 border-b hover:bg-gray-50 focus:bg-gray-50"
key={x.purpose}
onClick={() =>
(location.href = `${API_ENDPOINT}/download/album/${albumID}/${x.purpose}`)
}
tabIndex={0}
>
<td className="pl-4 py-2">{`${x.title}`}</td>
<td className="pr-4 py-2 text-sm text-gray-800 italic">{`${x.description}`}</td>
</tr>
))
return (
<SidebarSection>
<SidebarSectionTitle>
{t('sidebar.download.title', 'Download')}
</SidebarSectionTitle>
<table className="table-auto w-full">
<thead className="bg-[#f9f9fb]">
<tr className="text-left uppercase text-xs border-gray-100 border-b border-t">
<th className="px-4 py-2" colSpan={2}>
{t('sidebar.download.table_columns.name', 'Name')}
</th>
</tr>
</thead>
<tbody>{downloadRows}</tbody>
</table>
</SidebarSection>
)
}
export default SidebarAlbumDownload

View File

@ -1,5 +1,4 @@
import React from 'react'
import PropTypes from 'prop-types'
import { MessageState } from '../messages/Messages'
import { useLazyQuery, gql } from '@apollo/client'
import { authToken } from '../../helpers/authentication'
@ -187,11 +186,72 @@ const downloadBlob = async (blob: Blob, filename: string) => {
window.URL.revokeObjectURL(objectUrl)
}
type SidebarDownladProps = {
type SidebarDownloadTableRow = {
title: string
url: string
width: number
height: number
fileSize: number
}
type SidebarDownloadTableProps = {
rows: SidebarDownloadTableRow[]
}
const SidebarDownloadTable = ({ rows }: SidebarDownloadTableProps) => {
const { t } = useTranslation()
const extractExtension = (url: string) => {
const urlMatch = url.split(/[#?]/)
if (urlMatch == null) return
return urlMatch[0].split('.').pop()?.trim().toLowerCase()
}
const download = downloadMedia(t)
const bytes = formatBytes(t)
const downloadRows = rows.map(x => (
<tr
className="cursor-pointer border-gray-100 border-b hover:bg-gray-50 focus:bg-gray-50"
key={x.url}
onClick={() => download(x.url)}
tabIndex={0}
>
<td className="pl-4 py-2">{`${x.title}`}</td>
<td className="py-2">{`${x.width} x ${x.height}`}</td>
<td className="py-2">{`${bytes(x.fileSize)}`}</td>
<td className="pr-4 py-2">{extractExtension(x.url)}</td>
</tr>
))
return (
<table className="table-fixed w-full">
<thead className="bg-[#f9f9fb]">
<tr className="text-left uppercase text-xs border-gray-100 border-b border-t">
<th className="w-2/6 pl-4 py-2">
{t('sidebar.download.table_columns.name', 'Name')}
</th>
<th className="w-2/6 py-2">
{t('sidebar.download.table_columns.dimensions', 'Dimensions')}
</th>
<th className="w-1/6 py-2">
{t('sidebar.download.table_columns.file_size', 'Size')}
</th>
<th className="w-1/6 pr-4 py-2">
{t('sidebar.download.table_columns.file_type', 'Type')}
</th>
</tr>
</thead>
<tbody>{downloadRows}</tbody>
</table>
)
}
type SidebarMediaDownladProps = {
media: MediaSidebarMedia
}
const SidebarDownload = ({ media }: SidebarDownladProps) => {
const SidebarMediaDownload = ({ media }: SidebarMediaDownladProps) => {
const { t } = useTranslation()
if (!media || !media.id) return null
@ -214,28 +274,13 @@ const SidebarDownload = ({ media }: SidebarDownladProps) => {
}
}
const extractExtension = (url: string) => {
const urlMatch = url.split(/[#?]/)
if (urlMatch == null) return
return urlMatch[0].split('.').pop()?.trim().toLowerCase()
}
const download = downloadMedia(t)
const bytes = formatBytes(t)
const downloadRows = downloads.map(x => (
<tr
className="cursor-pointer border-gray-100 border-b hover:bg-gray-50 focus:bg-gray-50"
key={x.mediaUrl.url}
onClick={() => download(x.mediaUrl.url)}
tabIndex={0}
>
<td className="pl-4 py-2">{`${x.title}`}</td>
<td className="py-2">{`${x.mediaUrl.width} x ${x.mediaUrl.height}`}</td>
<td className="py-2">{`${bytes(x.mediaUrl.fileSize)}`}</td>
<td className="pr-4 py-2">{extractExtension(x.mediaUrl.url)}</td>
</tr>
))
const downloadRows = downloads.map<SidebarDownloadTableRow>(x => ({
title: x.title,
url: x.mediaUrl.url,
width: x.mediaUrl.width,
height: x.mediaUrl.height,
fileSize: x.mediaUrl.fileSize,
}))
return (
<SidebarSection>
@ -243,31 +288,9 @@ const SidebarDownload = ({ media }: SidebarDownladProps) => {
{t('sidebar.download.title', 'Download')}
</SidebarSectionTitle>
<table className="table-fixed w-full">
<thead className="bg-[#f9f9fb]">
<tr className="text-left uppercase text-xs border-gray-100 border-b border-t">
<th className="w-2/6 pl-4 py-2">
{t('sidebar.download.table_columns.name', 'Name')}
</th>
<th className="w-2/6 py-2">
{t('sidebar.download.table_columns.dimensions', 'Dimensions')}
</th>
<th className="w-1/6 py-2">
{t('sidebar.download.table_columns.file_size', 'Size')}
</th>
<th className="w-1/6 pr-4 py-2">
{t('sidebar.download.table_columns.file_type', 'Type')}
</th>
</tr>
</thead>
<tbody>{downloadRows}</tbody>
</table>
<SidebarDownloadTable rows={downloadRows} />
</SidebarSection>
)
}
SidebarDownload.propTypes = {
photo: PropTypes.object,
}
export default SidebarDownload
export default SidebarMediaDownload

View File

@ -62,10 +62,10 @@
},
"people_page": {
"action_label": {
"change_label": null,
"detach_face": null,
"merge_face": null,
"move_faces": null
"change_label": "Ændre navn",
"detach_face": "Løsriv billeder",
"merge_face": "Sammenflet personer",
"move_faces": "Flyt ansigter"
},
"face_group": {
"label_placeholder": "Navn",
@ -215,10 +215,27 @@
},
"sidebar": {
"album": {
"album_cover": null,
"cover_photo": null,
"reset_cover": null,
"set_cover": null,
"album_cover": "Album coverbillede",
"download": {
"high-resolutions": {
"description": "Høj opløsning JPEGs af RAW-billeder",
"title": "Høj opløsning"
},
"originals": {
"description": "De originale billeder og video",
"title": "Originaler"
},
"thumbnails": {
"description": "Billeder i lav opløsning, ingen videoer",
"title": "Thumbnails"
},
"web-videos": {
"description": "Videoer som er blevet optimeret til web",
"title": "Konverterede videoer"
}
},
"reset_cover": "Nulstil coverbillede",
"set_cover": "Set som album coverbillede",
"title_placeholder": "Albumtitel"
},
"download": {
@ -226,13 +243,13 @@
"byte": "{{count}} Byte",
"byte_plural": "{{count}} Bytes",
"giga_byte": "{{count}} GB",
"giga_byte_plural": null,
"giga_byte_plural": "",
"kilo_byte": "{{count}} KB",
"kilo_byte_plural": null,
"kilo_byte_plural": "",
"mega_byte": "{{count}} MB",
"mega_byte_plural": null,
"mega_byte_plural": "",
"tera_byte": "{{count}} TB",
"tera_byte_plural": null
"tera_byte_plural": ""
},
"table_columns": {
"dimensions": "Dimension",
@ -301,8 +318,8 @@
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
"dropdown_all": "Fra i dag",
"label": "Dato"
}
},
"title": {

View File

@ -55,7 +55,11 @@
},
"sidebar": {
"album": {
"title": "Indstillinger for album"
"title": "Indstillinger for album",
"album_cover": null,
"cover_photo": "",
"reset_cover": null,
"set_cover": null
},
"sharing": {
"table_header": "Offentlige delinger"
@ -68,5 +72,11 @@
"tera_byte_plural": null
}
}
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
}
}
}

View File

@ -1,7 +1,7 @@
{
"album_filter": {
"only_favorites": "Nur Favoriten anzeigen",
"sort": null,
"sort": "",
"sorting_options": {
"date_imported": "Importdatum",
"date_shot": "Aufnahmedatum",
@ -35,7 +35,7 @@
"placeholder": "Suche",
"result_type": {
"albums": "Alben",
"media": null
"media": ""
}
}
},
@ -62,54 +62,54 @@
},
"people_page": {
"action_label": {
"change_label": null,
"detach_face": null,
"merge_face": null,
"move_faces": null
"change_label": "",
"detach_face": "",
"merge_face": "",
"move_faces": ""
},
"face_group": {
"label_placeholder": "Zuordnung",
"unlabeled": "Nicht zugeordnet",
"unlabeled_person": null
"unlabeled_person": ""
},
"modal": {
"action": {
"merge": null
"merge": ""
},
"detach_image_faces": {
"action": {
"detach": null,
"select_images": null
"detach": "",
"select_images": ""
},
"description": null,
"title": null
"description": "",
"title": ""
},
"merge_face_groups": {
"description": null,
"description": "",
"destination_table": {
"title": null
"title": ""
},
"title": null
"title": ""
},
"move_image_faces": {
"description": null,
"description": "",
"destination_face_group_table": {
"move_action": null,
"title": null
"move_action": "",
"title": ""
},
"image_select_table": {
"next_action": null,
"title": null
"next_action": "",
"title": ""
},
"title": null
"title": ""
}
},
"recognize_unlabeled_faces_button": "Nicht zugeordnete Gesichter erkennen",
"tableselect_face_group": {
"search_faces_placeholder": null
"search_faces_placeholder": ""
},
"tableselect_image_faces": {
"search_images_placeholder": null
"search_images_placeholder": ""
}
},
"photos_page": {
@ -178,7 +178,7 @@
"table": {
"column_names": {
"action": "Aktion",
"capabilities": null,
"capabilities": "",
"photo_path": "Pfad der Medien",
"username": "Benutzername"
},
@ -206,7 +206,7 @@
},
"protected_share": {
"description": "Diese Freigabe ist passwortgeschützt.",
"password_required_error": null,
"password_required_error": "",
"title": "Passwortgeschützte Freigabe"
},
"share_not_found": "Freigabe nicht gefunden",
@ -215,24 +215,41 @@
},
"sidebar": {
"album": {
"album_cover": null,
"cover_photo": null,
"reset_cover": null,
"set_cover": null,
"title_placeholder": null
"album_cover": "",
"download": {
"high-resolutions": {
"description": "",
"title": ""
},
"originals": {
"description": "",
"title": ""
},
"thumbnails": {
"description": "",
"title": ""
},
"web-videos": {
"description": "",
"title": ""
}
},
"reset_cover": "",
"set_cover": "",
"title_placeholder": ""
},
"download": {
"filesize": {
"byte": "{{count}} Byte",
"byte_plural": "{{count}} Bytes",
"giga_byte": "{{count}} GB",
"giga_byte_plural": null,
"giga_byte_plural": "",
"kilo_byte": "{{count}} KB",
"kilo_byte_plural": null,
"kilo_byte_plural": "",
"mega_byte": "{{count}} MB",
"mega_byte_plural": null,
"mega_byte_plural": "",
"tera_byte": "{{count}} TB",
"tera_byte_plural": null
"tera_byte_plural": ""
},
"table_columns": {
"dimensions": "Dimension",
@ -285,8 +302,8 @@
"sharing": {
"add_share": "Freigabe hinzufügen",
"copy_link": "Link kopieren",
"delete": null,
"more": null,
"delete": "",
"more": "",
"no_shares_found": "Keine Freigaben gefunden",
"public_link": "Öffentlicher Link",
"title": "Freigabeoptionen"
@ -301,8 +318,8 @@
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
"dropdown_all": "",
"label": ""
}
},
"title": {

View File

@ -97,7 +97,11 @@
"sidebar": {
"album": {
"title": "Album Optionen",
"title_placeholder": null
"title_placeholder": null,
"album_cover": null,
"cover_photo": "",
"reset_cover": null,
"set_cover": null
},
"sharing": {
"table_header": "Öffentliche Freigabe",
@ -120,5 +124,11 @@
"protected_share": {
"password_required_error": null
}
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
}
}
}

View File

@ -216,7 +216,24 @@
"sidebar": {
"album": {
"album_cover": "Album cover",
"cover_photo": "Album cover",
"download": {
"high-resolutions": {
"description": "High resolution jpegs of RAW images",
"title": "High resolutions"
},
"originals": {
"description": "The original images and videos",
"title": "Originals"
},
"thumbnails": {
"description": "Low resolution images, no videos",
"title": "Thumbnails"
},
"web-videos": {
"description": "Videos that have been optimized for web",
"title": "Converted videos"
}
},
"reset_cover": "Reset cover photo",
"set_cover": "Set as album cover photo",
"title_placeholder": "Album title"

View File

@ -49,7 +49,8 @@
},
"sidebar": {
"album": {
"title": "Album options"
"title": "Album options",
"cover_photo": "Album cover"
},
"sharing": {
"table_header": "Public shares"

View File

@ -1,7 +1,7 @@
{
"album_filter": {
"only_favorites": "Solo mostrar favoritos",
"sort": null,
"sort": "",
"sorting_options": {
"date_imported": "Fecha de importado",
"date_shot": "Fecha de la foto",
@ -35,7 +35,7 @@
"placeholder": "Buscar",
"result_type": {
"albums": "Álbumes",
"media": null
"media": ""
}
}
},
@ -62,54 +62,54 @@
},
"people_page": {
"action_label": {
"change_label": null,
"detach_face": null,
"merge_face": null,
"move_faces": null
"change_label": "",
"detach_face": "",
"merge_face": "",
"move_faces": ""
},
"face_group": {
"label_placeholder": "Etiqueta",
"unlabeled": "Sin etiquetar",
"unlabeled_person": null
"unlabeled_person": ""
},
"modal": {
"action": {
"merge": null
"merge": ""
},
"detach_image_faces": {
"action": {
"detach": null,
"select_images": null
"detach": "",
"select_images": ""
},
"description": null,
"title": null
"description": "",
"title": ""
},
"merge_face_groups": {
"description": null,
"description": "",
"destination_table": {
"title": null
"title": ""
},
"title": null
"title": ""
},
"move_image_faces": {
"description": null,
"description": "",
"destination_face_group_table": {
"move_action": null,
"title": null
"move_action": "",
"title": ""
},
"image_select_table": {
"next_action": null,
"title": null
"next_action": "",
"title": ""
},
"title": null
"title": ""
}
},
"recognize_unlabeled_faces_button": "Reconocer caras sin etiquetar",
"tableselect_face_group": {
"search_faces_placeholder": null
"search_faces_placeholder": ""
},
"tableselect_image_faces": {
"search_images_placeholder": null
"search_images_placeholder": ""
}
},
"photos_page": {
@ -178,7 +178,7 @@
"table": {
"column_names": {
"action": "Acción",
"capabilities": null,
"capabilities": "",
"photo_path": "Ruta de las fotos",
"username": "Usuario"
},
@ -195,9 +195,9 @@
"title": "Usuarios"
},
"version_info": {
"build_date_title": null,
"title": null,
"version_title": null
"build_date_title": "",
"title": "",
"version_title": ""
}
},
"share_page": {
@ -206,7 +206,7 @@
},
"protected_share": {
"description": "Esta compartición está protegida por contraseña.",
"password_required_error": null,
"password_required_error": "",
"title": "Compartición protegida"
},
"share_not_found": "Compartición no encontrada",
@ -215,24 +215,41 @@
},
"sidebar": {
"album": {
"album_cover": null,
"cover_photo": null,
"reset_cover": null,
"set_cover": null,
"title_placeholder": null
"album_cover": "",
"download": {
"high-resolutions": {
"description": "",
"title": ""
},
"originals": {
"description": "",
"title": ""
},
"thumbnails": {
"description": "",
"title": ""
},
"web-videos": {
"description": "",
"title": ""
}
},
"reset_cover": "",
"set_cover": "",
"title_placeholder": ""
},
"download": {
"filesize": {
"byte": "{{count}} Byte",
"byte_plural": "{{count}} Bytes",
"giga_byte": "{{count}} GB",
"giga_byte_plural": null,
"giga_byte_plural": "",
"kilo_byte": "{{count}} KB",
"kilo_byte_plural": null,
"kilo_byte_plural": "",
"mega_byte": "{{count}} MB",
"mega_byte_plural": null,
"mega_byte_plural": "",
"tera_byte": "{{count}} TB",
"tera_byte_plural": null
"tera_byte_plural": ""
},
"table_columns": {
"dimensions": "Dimensiones",
@ -285,8 +302,8 @@
"sharing": {
"add_share": "Añadir compartido",
"copy_link": "Copiar enlace",
"delete": null,
"more": null,
"delete": "",
"more": "",
"no_shares_found": "No se encontraron compartidos",
"public_link": "Enlace público",
"title": "Opciones de compartir"
@ -301,13 +318,13 @@
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
"dropdown_all": "",
"label": ""
}
},
"title": {
"loading_album": "Cargando álbum",
"login": null,
"login": "",
"people": "Personas",
"settings": "Opciones"
}

View File

@ -102,7 +102,11 @@
"sidebar": {
"album": {
"title": "opciones de álbum",
"title_placeholder": null
"title_placeholder": null,
"album_cover": null,
"cover_photo": "",
"reset_cover": null,
"set_cover": null
},
"sharing": {
"table_header": "Compartidos públicos",
@ -128,5 +132,11 @@
"protected_share": {
"password_required_error": null
}
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
}
}
}

View File

@ -215,10 +215,27 @@
},
"sidebar": {
"album": {
"album_cover": null,
"cover_photo": null,
"reset_cover": null,
"set_cover": null,
"album_cover": "",
"download": {
"high-resolutions": {
"description": "",
"title": ""
},
"originals": {
"description": "",
"title": ""
},
"thumbnails": {
"description": "",
"title": ""
},
"web-videos": {
"description": "",
"title": ""
}
},
"reset_cover": "",
"set_cover": "",
"title_placeholder": "Titre de l'Album"
},
"download": {
@ -301,8 +318,8 @@
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
"dropdown_all": "",
"label": ""
}
},
"title": {

View File

@ -87,7 +87,11 @@
},
"sidebar": {
"album": {
"title": "Paramètres de l'album"
"title": "Paramètres de l'album",
"album_cover": null,
"cover_photo": "",
"reset_cover": null,
"set_cover": null
},
"sharing": {
"table_header": "Partages publics"
@ -95,5 +99,11 @@
},
"title": {
"login": null
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
}
}
}

View File

@ -1,7 +1,7 @@
{
"album_filter": {
"only_favorites": "Mostra solo i preferiti",
"sort": null,
"sort": "",
"sorting_options": {
"date_imported": "Data importazione",
"date_shot": "Data scatto",
@ -35,7 +35,7 @@
"placeholder": "Cerca",
"result_type": {
"albums": "Album",
"media": null
"media": ""
}
}
},
@ -62,10 +62,10 @@
},
"people_page": {
"action_label": {
"change_label": null,
"detach_face": null,
"merge_face": null,
"move_faces": null
"change_label": "",
"detach_face": "",
"merge_face": "",
"move_faces": ""
},
"face_group": {
"label_placeholder": "Etichetta",
@ -106,10 +106,10 @@
},
"recognize_unlabeled_faces_button": "Identifica facce senza etichetta",
"tableselect_face_group": {
"search_faces_placeholder": null
"search_faces_placeholder": ""
},
"tableselect_image_faces": {
"search_images_placeholder": null
"search_images_placeholder": ""
}
},
"photos_page": {
@ -178,7 +178,7 @@
"table": {
"column_names": {
"action": "Azioni",
"capabilities": null,
"capabilities": "",
"photo_path": "Percorso foto",
"username": "Username"
},
@ -206,7 +206,7 @@
},
"protected_share": {
"description": "Questa condivisione è protetta da una password.",
"password_required_error": null,
"password_required_error": "",
"title": "Condivisione protetta"
},
"share_not_found": "Condivisone non trovata",
@ -215,24 +215,41 @@
},
"sidebar": {
"album": {
"album_cover": null,
"cover_photo": null,
"reset_cover": null,
"set_cover": null,
"title_placeholder": null
"album_cover": "",
"download": {
"high-resolutions": {
"description": "",
"title": ""
},
"originals": {
"description": "",
"title": ""
},
"thumbnails": {
"description": "",
"title": ""
},
"web-videos": {
"description": "",
"title": ""
}
},
"reset_cover": "",
"set_cover": "",
"title_placeholder": ""
},
"download": {
"filesize": {
"byte": "{{count}} Byte",
"byte_plural": "{{count}} Bytes",
"giga_byte": "{{count}} GB",
"giga_byte_plural": null,
"giga_byte_plural": "",
"kilo_byte": "{{count}} KB",
"kilo_byte_plural": null,
"kilo_byte_plural": "",
"mega_byte": "{{count}} MB",
"mega_byte_plural": null,
"mega_byte_plural": "",
"tera_byte": "{{count}} TB",
"tera_byte_plural": null
"tera_byte_plural": ""
},
"table_columns": {
"dimensions": "Dimensioni",
@ -285,8 +302,8 @@
"sharing": {
"add_share": "Aggiungi condivisione",
"copy_link": "Copia il link",
"delete": null,
"more": null,
"delete": "",
"more": "",
"no_shares_found": "Nessuna condivisione trovata",
"public_link": "Link pubblico",
"title": "Opzioni di condivisione"
@ -301,8 +318,8 @@
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
"dropdown_all": "",
"label": ""
}
},
"title": {

View File

@ -64,7 +64,11 @@
"sidebar": {
"album": {
"title": "Opzioni Album",
"title_placeholder": null
"title_placeholder": null,
"album_cover": null,
"cover_photo": "",
"reset_cover": null,
"set_cover": null
},
"sharing": {
"table_header": "Condivisioni pubbliche",
@ -87,5 +91,11 @@
"protected_share": {
"password_required_error": null
}
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
}
}
}

View File

@ -1,7 +1,7 @@
{
"album_filter": {
"only_favorites": "Pokaż tylko ulubione",
"sort": null,
"sort": "",
"sorting_options": {
"date_imported": "Data zaimportowania",
"date_shot": "Data wykonania",
@ -35,7 +35,7 @@
"placeholder": "Szukaj",
"result_type": {
"albums": "Albumy",
"media": null
"media": ""
}
}
},
@ -62,54 +62,54 @@
},
"people_page": {
"action_label": {
"change_label": null,
"detach_face": null,
"merge_face": null,
"move_faces": null
"change_label": "",
"detach_face": "",
"merge_face": "",
"move_faces": ""
},
"face_group": {
"label_placeholder": "Etykieta",
"unlabeled": "Nieoznakowany",
"unlabeled_person": null
"unlabeled_person": ""
},
"modal": {
"action": {
"merge": null
"merge": ""
},
"detach_image_faces": {
"action": {
"detach": null,
"select_images": null
"detach": "",
"select_images": ""
},
"description": null,
"title": null
"description": "",
"title": ""
},
"merge_face_groups": {
"description": null,
"description": "",
"destination_table": {
"title": null
"title": ""
},
"title": null
"title": ""
},
"move_image_faces": {
"description": null,
"description": "",
"destination_face_group_table": {
"move_action": null,
"title": null
"move_action": "",
"title": ""
},
"image_select_table": {
"next_action": null,
"title": null
"next_action": "",
"title": ""
},
"title": null
"title": ""
}
},
"recognize_unlabeled_faces_button": "Rozpoznaj nieoznakowane twarze",
"tableselect_face_group": {
"search_faces_placeholder": null
"search_faces_placeholder": ""
},
"tableselect_image_faces": {
"search_images_placeholder": null
"search_images_placeholder": ""
}
},
"photos_page": {
@ -178,7 +178,7 @@
"table": {
"column_names": {
"action": "Akcja",
"capabilities": null,
"capabilities": "",
"photo_path": "Ścieżka zdjęć",
"username": "Nazwa użytkownika"
},
@ -195,9 +195,9 @@
"title": "Użytkownicy"
},
"version_info": {
"build_date_title": null,
"title": null,
"version_title": null
"build_date_title": "",
"title": "",
"version_title": ""
}
},
"share_page": {
@ -206,7 +206,7 @@
},
"protected_share": {
"description": "Ten udział jest chroniony hasłem.",
"password_required_error": null,
"password_required_error": "",
"title": "Udział chroniony"
},
"share_not_found": "Nie znaleziono udziału",
@ -215,29 +215,46 @@
},
"sidebar": {
"album": {
"album_cover": null,
"cover_photo": null,
"reset_cover": null,
"set_cover": null,
"title_placeholder": null
"album_cover": "",
"download": {
"high-resolutions": {
"description": "",
"title": ""
},
"originals": {
"description": "",
"title": ""
},
"thumbnails": {
"description": "",
"title": ""
},
"web-videos": {
"description": "",
"title": ""
}
},
"reset_cover": "",
"set_cover": "",
"title_placeholder": ""
},
"download": {
"filesize": {
"byte_0": null,
"byte_1": null,
"byte_2": null,
"giga_byte_0": null,
"giga_byte_1": null,
"giga_byte_2": null,
"kilo_byte_0": null,
"kilo_byte_1": null,
"kilo_byte_2": null,
"mega_byte_0": null,
"mega_byte_1": null,
"mega_byte_2": null,
"tera_byte_0": null,
"tera_byte_1": null,
"tera_byte_2": null
"byte_0": "",
"byte_1": "",
"byte_2": "",
"giga_byte_0": "",
"giga_byte_1": "",
"giga_byte_2": "",
"kilo_byte_0": "",
"kilo_byte_1": "",
"kilo_byte_2": "",
"mega_byte_0": "",
"mega_byte_1": "",
"mega_byte_2": "",
"tera_byte_0": "",
"tera_byte_1": "",
"tera_byte_2": ""
},
"table_columns": {
"dimensions": "Wymiary",
@ -290,8 +307,8 @@
"sharing": {
"add_share": "Dodaj udział",
"copy_link": "Skopiuj link",
"delete": null,
"more": null,
"delete": "",
"more": "",
"no_shares_found": "Nie znaleziono udostępnionych",
"public_link": "Link publiczny",
"title": "Opcje udostępniania"
@ -306,13 +323,13 @@
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
"dropdown_all": "",
"label": ""
}
},
"title": {
"loading_album": "Ładowanie albumu",
"login": null,
"login": "",
"people": "Ludzie",
"settings": "Ustawienia"
}

View File

@ -102,7 +102,11 @@
"sidebar": {
"album": {
"title": "Opcje albumu",
"title_placeholder": null
"title_placeholder": null,
"album_cover": null,
"cover_photo": "",
"reset_cover": null,
"set_cover": null
},
"download": {
"filesize": {
@ -145,5 +149,11 @@
"protected_share": {
"password_required_error": null
}
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
}
}
}

View File

@ -1,7 +1,7 @@
{
"album_filter": {
"only_favorites": "Показать только избранные",
"sort": null,
"sort": "",
"sorting_options": {
"date_imported": "Дата импортирования",
"date_shot": "Дата снимка",
@ -35,7 +35,7 @@
"placeholder": "Поиск",
"result_type": {
"albums": "Альбомы",
"media": null
"media": ""
}
}
},
@ -62,10 +62,10 @@
},
"people_page": {
"action_label": {
"change_label": null,
"detach_face": null,
"merge_face": null,
"move_faces": null
"change_label": "",
"detach_face": "",
"merge_face": "",
"move_faces": ""
},
"face_group": {
"label_placeholder": "Метка",
@ -106,10 +106,10 @@
},
"recognize_unlabeled_faces_button": "Распознавать непомеченные лица",
"tableselect_face_group": {
"search_faces_placeholder": null
"search_faces_placeholder": ""
},
"tableselect_image_faces": {
"search_images_placeholder": null
"search_images_placeholder": ""
}
},
"photos_page": {
@ -178,7 +178,7 @@
"table": {
"column_names": {
"action": "Действие",
"capabilities": null,
"capabilities": "",
"photo_path": "Путь к фото",
"username": "Имя пользователя"
},
@ -206,7 +206,7 @@
},
"protected_share": {
"description": "Это общее медиа защищено паролем.",
"password_required_error": null,
"password_required_error": "",
"title": "Защищённое медиа"
},
"share_not_found": "Общее медиа не найдено",
@ -215,29 +215,46 @@
},
"sidebar": {
"album": {
"album_cover": null,
"cover_photo": null,
"reset_cover": null,
"set_cover": null,
"title_placeholder": null
"album_cover": "",
"download": {
"high-resolutions": {
"description": "",
"title": ""
},
"originals": {
"description": "",
"title": ""
},
"thumbnails": {
"description": "",
"title": ""
},
"web-videos": {
"description": "",
"title": ""
}
},
"reset_cover": "",
"set_cover": "",
"title_placeholder": ""
},
"download": {
"filesize": {
"byte_0": null,
"byte_1": null,
"byte_2": null,
"giga_byte_0": null,
"giga_byte_1": null,
"giga_byte_2": null,
"kilo_byte_0": null,
"kilo_byte_1": null,
"kilo_byte_2": null,
"mega_byte_0": null,
"mega_byte_1": null,
"mega_byte_2": null,
"tera_byte_0": null,
"tera_byte_1": null,
"tera_byte_2": null
"byte_0": "",
"byte_1": "",
"byte_2": "",
"giga_byte_0": "",
"giga_byte_1": "",
"giga_byte_2": "",
"kilo_byte_0": "",
"kilo_byte_1": "",
"kilo_byte_2": "",
"mega_byte_0": "",
"mega_byte_1": "",
"mega_byte_2": "",
"tera_byte_0": "",
"tera_byte_1": "",
"tera_byte_2": ""
},
"table_columns": {
"dimensions": "Габариты",
@ -290,8 +307,8 @@
"sharing": {
"add_share": "Поделится",
"copy_link": "Скопировать ссылку",
"delete": null,
"more": null,
"delete": "",
"more": "",
"no_shares_found": "Нет доступа",
"public_link": "Общедоступная ссылка",
"title": "Настройки доступа"
@ -306,8 +323,8 @@
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
"dropdown_all": "",
"label": ""
}
},
"title": {

View File

@ -64,7 +64,11 @@
"sidebar": {
"album": {
"title": "Свойства альбома",
"title_placeholder": null
"title_placeholder": null,
"album_cover": null,
"cover_photo": "",
"reset_cover": null,
"set_cover": null
},
"download": {
"filesize": {
@ -104,5 +108,11 @@
"protected_share": {
"password_required_error": null
}
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
}
}
}

View File

@ -1,7 +1,7 @@
{
"album_filter": {
"only_favorites": "Visa endast favoriter",
"sort": null,
"sort": "",
"sorting_options": {
"date_imported": "Datum för import",
"date_shot": "Datum",
@ -35,7 +35,7 @@
"placeholder": "Sök",
"result_type": {
"albums": "Album",
"media": null
"media": ""
}
}
},
@ -62,61 +62,61 @@
},
"people_page": {
"action_label": {
"change_label": null,
"detach_face": null,
"merge_face": null,
"move_faces": null
"change_label": "",
"detach_face": "",
"merge_face": "",
"move_faces": ""
},
"face_group": {
"label_placeholder": "Märkning",
"unlabeled": "Omärkt",
"unlabeled_person": null
"unlabeled_person": ""
},
"modal": {
"action": {
"merge": null
"merge": ""
},
"detach_image_faces": {
"action": {
"detach": null,
"select_images": null
"detach": "",
"select_images": ""
},
"description": null,
"title": null
"description": "",
"title": ""
},
"merge_face_groups": {
"description": null,
"description": "",
"destination_table": {
"title": null
"title": ""
},
"title": null
"title": ""
},
"move_image_faces": {
"description": null,
"description": "",
"destination_face_group_table": {
"move_action": null,
"title": null
"move_action": "",
"title": ""
},
"image_select_table": {
"next_action": null,
"title": null
"next_action": "",
"title": ""
},
"title": null
"title": ""
}
},
"recognize_unlabeled_faces_button": "Känna igen omärkta ansikten",
"tableselect_face_group": {
"search_faces_placeholder": null
"search_faces_placeholder": ""
},
"tableselect_image_faces": {
"search_images_placeholder": null
"search_images_placeholder": ""
}
},
"photos_page": {
"title": "Bilder"
},
"places_page": {
"title": null
"title": ""
},
"routes": {
"page_not_found": "Sidan hittades inte"
@ -178,7 +178,7 @@
"table": {
"column_names": {
"action": "Åtgärd",
"capabilities": null,
"capabilities": "",
"photo_path": "Sökväg till bild",
"username": "Användarnamn"
},
@ -195,9 +195,9 @@
"title": "Användare"
},
"version_info": {
"build_date_title": null,
"title": null,
"version_title": null
"build_date_title": "",
"title": "",
"version_title": ""
}
},
"share_page": {
@ -206,7 +206,7 @@
},
"protected_share": {
"description": "Denna delning är skyddad med ett lösenord.",
"password_required_error": null,
"password_required_error": "",
"title": "Skyddad delning"
},
"share_not_found": "Delning hittades inte",
@ -215,24 +215,41 @@
},
"sidebar": {
"album": {
"album_cover": null,
"cover_photo": null,
"reset_cover": null,
"set_cover": null,
"title_placeholder": null
"album_cover": "",
"download": {
"high-resolutions": {
"description": "",
"title": ""
},
"originals": {
"description": "",
"title": ""
},
"thumbnails": {
"description": "",
"title": ""
},
"web-videos": {
"description": "",
"title": ""
}
},
"reset_cover": "",
"set_cover": "",
"title_placeholder": ""
},
"download": {
"filesize": {
"byte": "{{count}} Byte",
"byte_plural": "{{count}} Bytes",
"giga_byte": "{{count}} GB",
"giga_byte_plural": null,
"giga_byte_plural": "",
"kilo_byte": "{{count}} KB",
"kilo_byte_plural": null,
"kilo_byte_plural": "",
"mega_byte": "{{count}} MB",
"mega_byte_plural": null,
"mega_byte_plural": "",
"tera_byte": "{{count}} TB",
"tera_byte_plural": null
"tera_byte_plural": ""
},
"table_columns": {
"dimensions": "Mått",
@ -285,8 +302,8 @@
"sharing": {
"add_share": "Dela",
"copy_link": "Kopiera länk",
"delete": null,
"more": null,
"delete": "",
"more": "",
"no_shares_found": "Inga delningar hittades",
"public_link": "Publika länkar",
"title": "Delningsinställningar"
@ -301,13 +318,13 @@
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
"dropdown_all": "",
"label": ""
}
},
"title": {
"loading_album": "Laddar album",
"login": null,
"login": "",
"people": "Personer",
"settings": "Inställningar"
}

View File

@ -105,7 +105,11 @@
"sidebar": {
"album": {
"title": "Albuminställningar",
"title_placeholder": null
"title_placeholder": null,
"album_cover": null,
"cover_photo": "",
"reset_cover": null,
"set_cover": null
},
"sharing": {
"table_header": "Publika delningar",
@ -131,5 +135,11 @@
"protected_share": {
"password_required_error": null
}
},
"timeline_filter": {
"date": {
"dropdown_all": null,
"label": null
}
}
}

View File

@ -21,6 +21,7 @@ export function setupLocalization(): void {
lng: 'en',
fallbackLng: 'en',
returnNull: false,
returnEmptyString: false,
interpolation: {
escapeValue: false,