mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
fix(build): add ScrollTrigger component, fix JSX syntax, dedup i18n
- Add missing ScrollTrigger component for infinite scroll - Fix JSX placement inside ternary expression - Remove 290 duplicate i18n keys across 13 translation files - Fix it.ts duplicate memories.saveError
This commit is contained in:
@@ -1097,7 +1097,6 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
|
||||
'budget.settlement': 'التسوية',
|
||||
'budget.settlementInfo': 'انقر على صورة العضو في بند الميزانية لتحديده باللون الأخضر — وهذا يعني أنه دفع. ثم تُظهر التسوية من يدين لمن وبكم.',
|
||||
'budget.netBalances': 'الأرصدة الصافية',
|
||||
'budget.linkedToReservation': 'مرتبط بحجز — قم بتحرير الاسم هناك',
|
||||
|
||||
// Files
|
||||
'files.title': 'الملفات',
|
||||
|
||||
@@ -1066,7 +1066,6 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
||||
'budget.settlement': 'Acerto',
|
||||
'budget.settlementInfo': 'Clique no avatar de um membro em um item do orçamento para marcá-lo em verde — significa que ele pagou. O acerto mostra quem deve quanto a quem.',
|
||||
'budget.netBalances': 'Saldos líquidos',
|
||||
'budget.linkedToReservation': 'Vinculado a uma reserva — edite o nome lá',
|
||||
|
||||
// Files
|
||||
'files.title': 'Arquivos',
|
||||
@@ -1163,9 +1162,6 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
||||
'packing.template': 'Modelo',
|
||||
'packing.templateApplied': '{count} itens adicionados do modelo',
|
||||
'packing.templateError': 'Falha ao aplicar modelo',
|
||||
'packing.saveAsTemplate': 'Salvar como modelo',
|
||||
'packing.templateName': 'Nome do modelo',
|
||||
'packing.templateSaved': 'Lista de bagagem salva como modelo',
|
||||
'packing.bags': 'Malas',
|
||||
'packing.noBag': 'Sem mala',
|
||||
'packing.totalWeight': 'Peso total',
|
||||
@@ -1804,21 +1800,9 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
||||
'common.justNow': 'agora mesmo',
|
||||
'common.hoursAgo': 'há {count}h',
|
||||
'common.daysAgo': 'há {count}d',
|
||||
'budget.linkedToReservation': 'Vinculado a uma reserva — edite o nome lá',
|
||||
'packing.saveAsTemplate': 'Salvar como modelo',
|
||||
'packing.templateName': 'Nome do modelo',
|
||||
'packing.templateSaved': 'Lista de bagagem salva como modelo',
|
||||
'memories.notConnectedMultipleHint': 'Conecte qualquer um destes provedores de fotos: {provider_names} em Configurações para poder adicionar fotos a esta viagem.',
|
||||
'memories.providerUrl': 'URL do servidor',
|
||||
'memories.providerApiKey': 'Chave da API',
|
||||
'memories.providerUsername': 'Nome de usuário',
|
||||
'memories.providerPassword': 'Senha',
|
||||
'memories.saveError': 'Não foi possível salvar as configurações de {provider_name}',
|
||||
'memories.saveRouteNotConfigured': 'A rota de salvamento não está configurada para este provedor',
|
||||
'memories.testRouteNotConfigured': 'A rota de teste não está configurada para este provedor',
|
||||
'memories.fillRequiredFields': 'Por favor preencha todos os campos obrigatórios',
|
||||
'memories.selectAlbumMultiple': 'Selecionar álbum',
|
||||
'memories.selectPhotosMultiple': 'Selecionar fotos',
|
||||
'journey.title': 'Jornada',
|
||||
'journey.subtitle': 'Registre suas viagens em tempo real',
|
||||
'journey.new': 'Nova jornada',
|
||||
|
||||
@@ -1095,7 +1095,6 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
||||
'budget.settlement': 'Vyúčtování',
|
||||
'budget.settlementInfo': 'Klikněte na avatar člena u rozpočtové položky pro zelené označení – to znamená, že zaplatil. Vyúčtování pak ukazuje, kdo komu a kolik dluží.',
|
||||
'budget.netBalances': 'Čisté zůstatky',
|
||||
'budget.linkedToReservation': 'Propojeno s rezervací — upravte název tam',
|
||||
|
||||
// Soubory (Files)
|
||||
'files.title': 'Soubory',
|
||||
@@ -1806,21 +1805,9 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
||||
'common.justNow': 'právě teď',
|
||||
'common.hoursAgo': 'před {count} h',
|
||||
'common.daysAgo': 'před {count} d',
|
||||
'budget.linkedToReservation': 'Propojeno s rezervací — upravte název tam',
|
||||
'packing.saveAsTemplate': 'Uložit jako šablonu',
|
||||
'packing.templateName': 'Název šablony',
|
||||
'packing.templateSaved': 'Balicí seznam uložen jako šablona',
|
||||
'memories.notConnectedMultipleHint': 'Připojte některého z těchto poskytovatelů fotek: {provider_names} v Nastavení, abyste mohli přidávat fotky k tomuto výletu.',
|
||||
'memories.providerUrl': 'URL serveru',
|
||||
'memories.providerApiKey': 'API klíč',
|
||||
'memories.providerUsername': 'Uživatelské jméno',
|
||||
'memories.providerPassword': 'Heslo',
|
||||
'memories.saveError': 'Nepodařilo se uložit nastavení {provider_name}',
|
||||
'memories.saveRouteNotConfigured': 'Trasa uložení není nakonfigurována pro tohoto poskytovatele',
|
||||
'memories.testRouteNotConfigured': 'Testovací trasa není nakonfigurována pro tohoto poskytovatele',
|
||||
'memories.fillRequiredFields': 'Prosím vyplňte všechna povinná pole',
|
||||
'memories.selectAlbumMultiple': 'Vybrat album',
|
||||
'memories.selectPhotosMultiple': 'Vybrat fotky',
|
||||
'journey.title': 'Cestovní deník',
|
||||
'journey.subtitle': 'Zaznamenávejte své cesty průběžně',
|
||||
'journey.new': 'Nový cestovní deník',
|
||||
|
||||
@@ -2050,14 +2050,6 @@ const de: Record<string, string | { name: string; category: string }[]> = {
|
||||
'dayplan.mobile.allAssigned': 'Alle Orte zugeordnet',
|
||||
'dayplan.mobile.noMatch': 'Kein Treffer',
|
||||
'dayplan.mobile.createNew': 'Neuen Ort erstellen',
|
||||
'memories.notConnectedMultipleHint': 'Connect any of these photo providers: {provider_names} in Settings to be able add photos to this trip.',
|
||||
'memories.providerUrl': 'Server URL',
|
||||
'memories.providerApiKey': 'API Key',
|
||||
'memories.providerUsername': 'Username',
|
||||
'memories.providerPassword': 'Password',
|
||||
'memories.saveError': 'Could not save {provider_name} settings',
|
||||
'memories.selectAlbumMultiple': 'Select Album',
|
||||
'memories.selectPhotosMultiple': 'Select Photos',
|
||||
|
||||
// OAuth scope groups
|
||||
'oauth.scope.group.trips': 'Reisen',
|
||||
|
||||
@@ -1053,7 +1053,6 @@ const es: Record<string, string> = {
|
||||
'budget.settlement': 'Liquidación',
|
||||
'budget.settlementInfo': 'Haz clic en el avatar de un miembro en una partida del presupuesto para marcarlo en verde — esto significa que ha pagado. La liquidación muestra quién debe cuánto a quién.',
|
||||
'budget.netBalances': 'Saldos netos',
|
||||
'budget.linkedToReservation': 'Vinculado a una reserva — edita el nombre allí',
|
||||
|
||||
// Files
|
||||
'files.title': 'Archivos',
|
||||
@@ -1811,18 +1810,6 @@ const es: Record<string, string> = {
|
||||
'common.justNow': 'justo ahora',
|
||||
'common.hoursAgo': 'hace {count}h',
|
||||
'common.daysAgo': 'hace {count}d',
|
||||
'budget.linkedToReservation': 'Vinculado a una reserva — edita el nombre allí',
|
||||
'packing.saveAsTemplate': 'Guardar como plantilla',
|
||||
'packing.templateName': 'Nombre de la plantilla',
|
||||
'packing.templateSaved': 'Lista de equipaje guardada como plantilla',
|
||||
'memories.notConnectedMultipleHint': 'Conecta cualquiera de estos proveedores de fotos: {provider_names} en Ajustes para poder añadir fotos a este viaje.',
|
||||
'memories.providerUrl': 'URL del servidor',
|
||||
'memories.providerApiKey': 'Clave API',
|
||||
'memories.providerUsername': 'Nombre de usuario',
|
||||
'memories.providerPassword': 'Contraseña',
|
||||
'memories.saveError': 'No se pudo guardar la configuración de {provider_name}',
|
||||
'memories.selectAlbumMultiple': 'Seleccionar álbum',
|
||||
'memories.selectPhotosMultiple': 'Seleccionar fotos',
|
||||
'journey.title': 'Travesía',
|
||||
'journey.subtitle': 'Registra tus viajes en tiempo real',
|
||||
'journey.new': 'Nueva travesía',
|
||||
|
||||
@@ -1093,7 +1093,6 @@ const fr: Record<string, string> = {
|
||||
'budget.settlement': 'Règlement',
|
||||
'budget.settlementInfo': 'Cliquez sur l\'avatar d\'un membre sur un poste budgétaire pour le marquer en vert — cela signifie qu\'il a payé. Le règlement indique ensuite qui doit combien à qui.',
|
||||
'budget.netBalances': 'Soldes nets',
|
||||
'budget.linkedToReservation': 'Lié à une réservation — modifiez le nom là-bas',
|
||||
|
||||
// Files
|
||||
'files.title': 'Fichiers',
|
||||
@@ -1805,18 +1804,6 @@ const fr: Record<string, string> = {
|
||||
'common.justNow': 'à l\'instant',
|
||||
'common.hoursAgo': 'il y a {count}h',
|
||||
'common.daysAgo': 'il y a {count}j',
|
||||
'budget.linkedToReservation': 'Lié à une réservation — modifiez le nom là-bas',
|
||||
'packing.saveAsTemplate': 'Enregistrer comme modèle',
|
||||
'packing.templateName': 'Nom du modèle',
|
||||
'packing.templateSaved': 'Liste de bagages enregistrée comme modèle',
|
||||
'memories.notConnectedMultipleHint': 'Connectez l\'un de ces fournisseurs de photos : {provider_names} dans les Paramètres pour pouvoir ajouter des photos à ce voyage.',
|
||||
'memories.providerUrl': 'URL du serveur',
|
||||
'memories.providerApiKey': 'Clé API',
|
||||
'memories.providerUsername': 'Nom d\'utilisateur',
|
||||
'memories.providerPassword': 'Mot de passe',
|
||||
'memories.saveError': 'Impossible d\'enregistrer les paramètres de {provider_name}',
|
||||
'memories.selectAlbumMultiple': 'Sélectionner un album',
|
||||
'memories.selectPhotosMultiple': 'Sélectionner des photos',
|
||||
'journey.title': 'Journal de voyage',
|
||||
'journey.subtitle': 'Suivez vos voyages en temps réel',
|
||||
'journey.new': 'Nouveau journal',
|
||||
|
||||
@@ -1094,7 +1094,6 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
|
||||
'budget.settlement': 'Elszámolás',
|
||||
'budget.settlementInfo': 'Kattints egy tag avatárjára egy költségvetési tételen a zöld jelöléshez — ez azt jelenti, hogy fizetett. Az elszámolás ezután mutatja, ki kinek mennyivel tartozik.',
|
||||
'budget.netBalances': 'Nettó egyenlegek',
|
||||
'budget.linkedToReservation': 'Foglaláshoz kapcsolva — ott módosítsa a nevet',
|
||||
|
||||
// Fájlok
|
||||
'files.title': 'Fájlok',
|
||||
@@ -1803,21 +1802,9 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
|
||||
'common.justNow': 'az imént',
|
||||
'common.hoursAgo': '{count} órája',
|
||||
'common.daysAgo': '{count} napja',
|
||||
'budget.linkedToReservation': 'Foglaláshoz kapcsolva — a nevet ott módosítsd',
|
||||
'packing.saveAsTemplate': 'Mentés sablonként',
|
||||
'packing.templateName': 'Sablon neve',
|
||||
'packing.templateSaved': 'Csomaglista sablonként mentve',
|
||||
'memories.notConnectedMultipleHint': 'Csatlakoztasd valamelyik fotószolgáltatót: {provider_names} a Beállításokban, hogy fotókat adhass hozzá ehhez az úthoz.',
|
||||
'memories.providerUrl': 'Szerver URL',
|
||||
'memories.providerApiKey': 'API-kulcs',
|
||||
'memories.providerUsername': 'Felhasználónév',
|
||||
'memories.providerPassword': 'Jelszó',
|
||||
'memories.saveError': 'Nem sikerült menteni a(z) {provider_name} beállításait',
|
||||
'memories.saveRouteNotConfigured': 'A mentési útvonal nincs konfigurálva ehhez a szolgáltatóhoz',
|
||||
'memories.testRouteNotConfigured': 'A tesztútvonal nincs konfigurálva ehhez a szolgáltatóhoz',
|
||||
'memories.fillRequiredFields': 'Kérjük töltse ki az összes kötelező mezőt',
|
||||
'memories.selectAlbumMultiple': 'Album kiválasztása',
|
||||
'memories.selectPhotosMultiple': 'Fotók kiválasztása',
|
||||
'journey.title': 'Útinaplók',
|
||||
'journey.subtitle': 'Kövesse nyomon utazásait valós időben',
|
||||
'journey.new': 'Új útinapló',
|
||||
|
||||
@@ -1094,7 +1094,6 @@ const it: Record<string, string | { name: string; category: string }[]> = {
|
||||
'budget.settlement': 'Regolamento',
|
||||
'budget.settlementInfo': 'Clicca sull\'avatar di un membro su una voce di budget per contrassegnarlo in verde — significa che ha pagato. Il regolamento mostra poi chi deve quanto a chi.',
|
||||
'budget.netBalances': 'Saldi netti',
|
||||
'budget.linkedToReservation': 'Collegato a una prenotazione — modifica il nome lì',
|
||||
|
||||
// Files
|
||||
'files.title': 'File',
|
||||
@@ -1806,18 +1805,6 @@ const it: Record<string, string | { name: string; category: string }[]> = {
|
||||
'common.justNow': 'proprio ora',
|
||||
'common.hoursAgo': '{count}h fa',
|
||||
'common.daysAgo': '{count}g fa',
|
||||
'budget.linkedToReservation': 'Collegato a una prenotazione — modifica il nome lì',
|
||||
'packing.saveAsTemplate': 'Salva come modello',
|
||||
'packing.templateName': 'Nome del modello',
|
||||
'packing.templateSaved': 'Lista bagagli salvata come modello',
|
||||
'memories.notConnectedMultipleHint': 'Collega uno di questi fornitori di foto: {provider_names} nelle Impostazioni per poter aggiungere foto a questo viaggio.',
|
||||
'memories.providerUrl': 'URL del server',
|
||||
'memories.providerApiKey': 'Chiave API',
|
||||
'memories.providerUsername': 'Nome utente',
|
||||
'memories.providerPassword': 'Password',
|
||||
'memories.saveError': 'Impossibile salvare le impostazioni di {provider_name}',
|
||||
'memories.selectAlbumMultiple': 'Seleziona album',
|
||||
'memories.selectPhotosMultiple': 'Seleziona foto',
|
||||
'journey.title': 'Diario di viaggio',
|
||||
'journey.subtitle': 'Segui i tuoi viaggi in tempo reale',
|
||||
'journey.new': 'Nuovo diario',
|
||||
|
||||
@@ -1093,7 +1093,6 @@ const nl: Record<string, string> = {
|
||||
'budget.settlement': 'Afrekening',
|
||||
'budget.settlementInfo': 'Klik op de avatar van een lid bij een budgetpost om deze groen te markeren — dit betekent dat diegene heeft betaald. De afrekening toont vervolgens wie wie hoeveel verschuldigd is.',
|
||||
'budget.netBalances': 'Nettosaldi',
|
||||
'budget.linkedToReservation': 'Gekoppeld aan een reservering — bewerk de naam daar',
|
||||
|
||||
// Files
|
||||
'files.title': 'Bestanden',
|
||||
@@ -1805,18 +1804,6 @@ const nl: Record<string, string> = {
|
||||
'common.justNow': 'zojuist',
|
||||
'common.hoursAgo': '{count}u geleden',
|
||||
'common.daysAgo': '{count}d geleden',
|
||||
'budget.linkedToReservation': 'Gekoppeld aan een reservering — bewerk de naam daar',
|
||||
'packing.saveAsTemplate': 'Opslaan als sjabloon',
|
||||
'packing.templateName': 'Sjabloonnaam',
|
||||
'packing.templateSaved': 'Paklijst opgeslagen als sjabloon',
|
||||
'memories.notConnectedMultipleHint': 'Verbind een van deze foto-aanbieders: {provider_names} in Instellingen om foto\'s aan deze reis toe te voegen.',
|
||||
'memories.providerUrl': 'Server-URL',
|
||||
'memories.providerApiKey': 'API-sleutel',
|
||||
'memories.providerUsername': 'Gebruikersnaam',
|
||||
'memories.providerPassword': 'Wachtwoord',
|
||||
'memories.saveError': 'Kon {provider_name}-instellingen niet opslaan',
|
||||
'memories.selectAlbumMultiple': 'Selecteer album',
|
||||
'memories.selectPhotosMultiple': 'Selecteer foto\'s',
|
||||
'journey.title': 'Reisverslag',
|
||||
'journey.subtitle': 'Leg je reizen vast terwijl je onderweg bent',
|
||||
'journey.new': 'Nieuw reisverslag',
|
||||
|
||||
@@ -1148,9 +1148,6 @@ const pl: Record<string, string | { name: string; category: string }[]> = {
|
||||
'packing.template': 'Szablon',
|
||||
'packing.templateApplied': '{count} przedmiotów dodanych z szablonu',
|
||||
'packing.templateError': 'Nie udało się zastosować szablonu',
|
||||
'packing.saveAsTemplate': 'Zapisz jako szablon',
|
||||
'packing.templateName': 'Nazwa szablonu',
|
||||
'packing.templateSaved': 'Lista pakowania zapisana jako szablon',
|
||||
'packing.bags': 'Torby',
|
||||
'packing.noBag': 'Nieprzypisane',
|
||||
'packing.totalWeight': 'Waga całkowita',
|
||||
@@ -1614,7 +1611,6 @@ const pl: Record<string, string | { name: string; category: string }[]> = {
|
||||
'inspector.trackStats': 'Statystyki trasy',
|
||||
'budget.exportCsv': 'Eksportuj CSV',
|
||||
'budget.table.date': 'Data',
|
||||
'budget.linkedToReservation': 'Powiązane z rezerwacją — edytuj nazwę tam',
|
||||
'memories.testFirst': 'Najpierw przetestuj połączenie',
|
||||
'memories.linkAlbum': 'Połącz album',
|
||||
'memories.selectAlbum': 'Wybierz album Immich',
|
||||
@@ -1798,21 +1794,9 @@ const pl: Record<string, string | { name: string; category: string }[]> = {
|
||||
'common.justNow': 'przed chwilą',
|
||||
'common.hoursAgo': '{count} godz. temu',
|
||||
'common.daysAgo': '{count} dn. temu',
|
||||
'budget.linkedToReservation': 'Powiązane z rezerwacją — edytuj nazwę tam',
|
||||
'packing.saveAsTemplate': 'Zapisz jako szablon',
|
||||
'packing.templateName': 'Nazwa szablonu',
|
||||
'packing.templateSaved': 'Lista pakowania zapisana jako szablon',
|
||||
'memories.notConnectedMultipleHint': 'Połącz jednego z tych dostawców zdjęć: {provider_names} w Ustawieniach, aby dodawać zdjęcia do tej podróży.',
|
||||
'memories.providerUrl': 'Adres URL serwera',
|
||||
'memories.providerApiKey': 'Klucz API',
|
||||
'memories.providerUsername': 'Nazwa użytkownika',
|
||||
'memories.providerPassword': 'Hasło',
|
||||
'memories.saveError': 'Nie udało się zapisać ustawień {provider_name}',
|
||||
'memories.saveRouteNotConfigured': 'Trasa zapisu nie jest skonfigurowana dla tego dostawcy',
|
||||
'memories.testRouteNotConfigured': 'Trasa testowa nie jest skonfigurowana dla tego dostawcy',
|
||||
'memories.fillRequiredFields': 'Proszę wypełnić wszystkie wymagane pola',
|
||||
'memories.selectAlbumMultiple': 'Wybierz album',
|
||||
'memories.selectPhotosMultiple': 'Wybierz zdjęcia',
|
||||
'journey.title': 'Dziennik podróży',
|
||||
'journey.subtitle': 'Dokumentuj swoje podróże na bieżąco',
|
||||
'journey.new': 'Nowy dziennik podróży',
|
||||
|
||||
@@ -1093,7 +1093,6 @@ const ru: Record<string, string> = {
|
||||
'budget.settlement': 'Взаиморасчёт',
|
||||
'budget.settlementInfo': 'Нажмите на аватар участника в строке бюджета, чтобы отметить его зелёным — это значит, что он заплатил. Взаиморасчёт покажет, кто кому и сколько должен.',
|
||||
'budget.netBalances': 'Чистые балансы',
|
||||
'budget.linkedToReservation': 'Привязано к бронированию — измените название там',
|
||||
|
||||
// Files
|
||||
'files.title': 'Файлы',
|
||||
@@ -1802,21 +1801,9 @@ const ru: Record<string, string> = {
|
||||
'common.justNow': 'только что',
|
||||
'common.hoursAgo': '{count} ч назад',
|
||||
'common.daysAgo': '{count} д назад',
|
||||
'budget.linkedToReservation': 'Привязано к бронированию — измените название там',
|
||||
'packing.saveAsTemplate': 'Сохранить как шаблон',
|
||||
'packing.templateName': 'Название шаблона',
|
||||
'packing.templateSaved': 'Список вещей сохранён как шаблон',
|
||||
'memories.notConnectedMultipleHint': 'Подключите любого из этих фото-провайдеров: {provider_names} в Настройках, чтобы добавлять фото к этой поездке.',
|
||||
'memories.providerUrl': 'URL сервера',
|
||||
'memories.providerApiKey': 'API-ключ',
|
||||
'memories.providerUsername': 'Имя пользователя',
|
||||
'memories.providerPassword': 'Пароль',
|
||||
'memories.saveError': 'Не удалось сохранить настройки {provider_name}',
|
||||
'memories.saveRouteNotConfigured': 'Маршрут сохранения не настроен для этого провайдера',
|
||||
'memories.testRouteNotConfigured': 'Маршрут тестирования не настроен для этого провайдера',
|
||||
'memories.fillRequiredFields': 'Пожалуйста, заполните все обязательные поля',
|
||||
'memories.selectAlbumMultiple': 'Выбрать альбом',
|
||||
'memories.selectPhotosMultiple': 'Выбрать фото',
|
||||
'journey.title': 'Путешествие',
|
||||
'journey.subtitle': 'Отслеживайте свои путешествия в реальном времени',
|
||||
'journey.new': 'Новое путешествие',
|
||||
|
||||
@@ -1093,7 +1093,6 @@ const zh: Record<string, string> = {
|
||||
'budget.settlement': '结算',
|
||||
'budget.settlementInfo': '点击预算项目上的成员头像将其标记为绿色——表示该成员已付款。结算会显示谁欠谁多少。',
|
||||
'budget.netBalances': '净余额',
|
||||
'budget.linkedToReservation': '已链接到预订——在那里编辑名称',
|
||||
|
||||
// Files
|
||||
'files.title': '文件',
|
||||
@@ -1802,21 +1801,9 @@ const zh: Record<string, string> = {
|
||||
'common.justNow': '刚刚',
|
||||
'common.hoursAgo': '{count}小时前',
|
||||
'common.daysAgo': '{count}天前',
|
||||
'budget.linkedToReservation': '已关联预订 — 请在预订中编辑名称',
|
||||
'packing.saveAsTemplate': '保存为模板',
|
||||
'packing.templateName': '模板名称',
|
||||
'packing.templateSaved': '打包清单已保存为模板',
|
||||
'memories.notConnectedMultipleHint': '在设置中连接以下任一照片服务:{provider_names},以便为此旅行添加照片。',
|
||||
'memories.providerUrl': '服务器地址',
|
||||
'memories.providerApiKey': 'API 密钥',
|
||||
'memories.providerUsername': '用户名',
|
||||
'memories.providerPassword': '密码',
|
||||
'memories.saveError': '无法保存 {provider_name} 设置',
|
||||
'memories.saveRouteNotConfigured': '此提供商未配置保存路由',
|
||||
'memories.testRouteNotConfigured': '此提供商未配置测试路由',
|
||||
'memories.fillRequiredFields': '请填写所有必填字段',
|
||||
'memories.selectAlbumMultiple': '选择相册',
|
||||
'memories.selectPhotosMultiple': '选择照片',
|
||||
'journey.title': '旅程',
|
||||
'journey.subtitle': '实时记录你的旅行',
|
||||
'journey.new': '新建旅程',
|
||||
|
||||
@@ -133,8 +133,6 @@ const zhTw: Record<string, string> = {
|
||||
'dashboard.coverRemoveError': '移除失敗',
|
||||
'dashboard.titleRequired': '標題為必填項',
|
||||
'dashboard.endDateError': '結束日期必須晚於開始日期',
|
||||
'dashboard.dayCount': '天數',
|
||||
'dashboard.dayCountHint': '未設定旅行日期時的規劃天數。',
|
||||
|
||||
// Settings
|
||||
'settings.title': '設定',
|
||||
@@ -1763,21 +1761,9 @@ const zhTw: Record<string, string> = {
|
||||
'common.justNow': '剛剛',
|
||||
'common.hoursAgo': '{count}小時前',
|
||||
'common.daysAgo': '{count}天前',
|
||||
'budget.linkedToReservation': '已關聯預訂 — 請在預訂中編輯名稱',
|
||||
'packing.saveAsTemplate': '儲存為範本',
|
||||
'packing.templateName': '範本名稱',
|
||||
'packing.templateSaved': '打包清單已儲存為範本',
|
||||
'memories.notConnectedMultipleHint': '在設定中連接以下任一照片服務:{provider_names},以便為此旅行新增照片。',
|
||||
'memories.providerUrl': '伺服器位址',
|
||||
'memories.providerApiKey': 'API 金鑰',
|
||||
'memories.providerUsername': '使用者名稱',
|
||||
'memories.providerPassword': '密碼',
|
||||
'memories.saveError': '無法儲存 {provider_name} 設定',
|
||||
'memories.saveRouteNotConfigured': '此提供商未設定儲存路由',
|
||||
'memories.testRouteNotConfigured': '此提供商未設定測試路由',
|
||||
'memories.fillRequiredFields': '請填寫所有必填欄位',
|
||||
'memories.selectAlbumMultiple': '選擇相簿',
|
||||
'memories.selectPhotosMultiple': '選擇照片',
|
||||
'journey.title': '旅程',
|
||||
'journey.subtitle': '即時記錄你的旅行',
|
||||
'journey.new': '新建旅程',
|
||||
@@ -2021,112 +2007,9 @@ const zhTw: Record<string, string> = {
|
||||
'dayplan.mobile.createNew': '建立新地點',
|
||||
'admin.addons.catalog.journey.name': '旅程',
|
||||
'admin.addons.catalog.journey.description': '旅行追蹤與旅行日誌,包含打卡、照片和每日故事',
|
||||
'dashboard.dayCount': '天數',
|
||||
'dashboard.dayCountHint': '未設定旅行日期時規劃的天數。',
|
||||
'settings.tabs.display': '顯示',
|
||||
'settings.tabs.map': '地圖',
|
||||
'settings.tabs.notifications': '通知',
|
||||
'settings.tabs.integrations': '整合',
|
||||
'settings.tabs.account': '帳戶',
|
||||
'settings.tabs.about': '關於',
|
||||
'settings.notifyVersionAvailable': '有新版本可用',
|
||||
'settings.notificationPreferences.email': '電子郵件',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.inapp': '應用內',
|
||||
'settings.notificationPreferences.noChannels': '尚未設定通知管道。請聯繫管理員設定電子郵件或 Webhook 通知。',
|
||||
'settings.webhookUrl.label': 'Webhook 網址',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': '輸入你的 Discord、Slack 或自訂 Webhook 網址以接收通知。',
|
||||
'settings.webhookUrl.save': '儲存',
|
||||
'settings.webhookUrl.saved': 'Webhook 網址已儲存',
|
||||
'settings.webhookUrl.test': '測試',
|
||||
'settings.webhookUrl.testSuccess': '測試 Webhook 傳送成功',
|
||||
'settings.webhookUrl.testFailed': '測試 Webhook 失敗',
|
||||
'admin.notifications.emailPanel.title': '電子郵件 (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': '應用內',
|
||||
'admin.notifications.inappPanel.hint': '應用內通知始終處於啟用狀態,無法全域停用。',
|
||||
'admin.notifications.adminWebhookPanel.title': '管理員 Webhook',
|
||||
'admin.notifications.adminWebhookPanel.hint': '此 Webhook 僅用於管理員通知(例如版本更新提醒)。它與每位使用者的 Webhook 分開,設定後將始終觸發。',
|
||||
'admin.notifications.adminWebhookPanel.saved': '管理員 Webhook 網址已儲存',
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': '測試 Webhook 傳送成功',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': '測試 Webhook 失敗',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': '設定網址後管理員 Webhook 將始終觸發',
|
||||
'admin.notifications.adminNotificationsHint': '設定哪些管道傳送僅限管理員的通知(例如版本更新提醒)。',
|
||||
'settings.about.reportBug': '回報錯誤',
|
||||
'settings.about.reportBugHint': '發現問題?請告訴我們',
|
||||
'settings.about.featureRequest': '功能建議',
|
||||
'settings.about.featureRequestHint': '提出新功能建議',
|
||||
'settings.about.wikiHint': '文件與指南',
|
||||
'settings.about.description': 'TREK 是一個自架式旅行規劃工具,幫助你從第一個想法到最後一個回憶來組織旅行。日程規劃、預算、打包清單、照片等等——全部集中在一處,在你自己的伺服器上。',
|
||||
'settings.about.madeWith': '以',
|
||||
'settings.about.madeBy': '由 Maurice 和不斷壯大的開源社群製作。',
|
||||
'admin.tabs.notifications': '通知',
|
||||
'atlas.confirmUnmarkRegion': '將此地區從已造訪清單中移除?',
|
||||
'atlas.markRegionVisitedHint': '將此地區新增至已造訪清單',
|
||||
'trip.tabs.lists': '清單',
|
||||
'trip.tabs.listsShort': '清單',
|
||||
'reservations.price': '價格',
|
||||
'reservations.budgetCategory': '預算類別',
|
||||
'reservations.budgetCategoryPlaceholder': '例如 交通、住宿',
|
||||
'reservations.budgetCategoryAuto': '自動(依預訂類型)',
|
||||
'reservations.budgetHint': '儲存時將自動建立一筆預算項目。',
|
||||
'reservations.departureDate': '出發日期',
|
||||
'reservations.arrivalDate': '抵達日期',
|
||||
'reservations.departureTime': '出發時間',
|
||||
'reservations.arrivalTime': '抵達時間',
|
||||
'reservations.pickupDate': '取車日期',
|
||||
'reservations.returnDate': '還車日期',
|
||||
'reservations.pickupTime': '取車時間',
|
||||
'reservations.returnTime': '還車時間',
|
||||
'reservations.endDate': '結束日期',
|
||||
'reservations.meta.departureTimezone': '出發時區',
|
||||
'reservations.meta.arrivalTimezone': '抵達時區',
|
||||
'reservations.span.departure': '出發',
|
||||
'reservations.span.arrival': '抵達',
|
||||
'reservations.span.inTransit': '運輸中',
|
||||
'reservations.span.pickup': '取車',
|
||||
'reservations.span.return': '還車',
|
||||
'reservations.span.active': '使用中',
|
||||
'reservations.span.start': '開始',
|
||||
'reservations.span.end': '結束',
|
||||
'reservations.span.ongoing': '進行中',
|
||||
'reservations.validation.endBeforeStart': '結束日期/時間必須晚於開始日期/時間',
|
||||
'notifications.versionAvailable.title': '有可用更新',
|
||||
'notifications.versionAvailable.text': 'TREK {version} 現已推出。',
|
||||
'notifications.versionAvailable.button': '查看詳情',
|
||||
'todo.subtab.packing': '打包清單',
|
||||
'todo.subtab.todo': '待辦事項',
|
||||
'todo.completed': '已完成',
|
||||
'todo.filter.all': '全部',
|
||||
'todo.filter.open': '未完成',
|
||||
'todo.filter.done': '已完成',
|
||||
'todo.uncategorized': '未分類',
|
||||
'todo.namePlaceholder': '任務名稱',
|
||||
'todo.descriptionPlaceholder': '描述(可選)',
|
||||
'todo.unassigned': '未指派',
|
||||
'todo.noCategory': '無類別',
|
||||
'todo.hasDescription': '有描述',
|
||||
'todo.addItem': '新增任務...',
|
||||
'todo.newCategory': '類別名稱',
|
||||
'todo.addCategory': '新增類別',
|
||||
'todo.newItem': '新任務',
|
||||
'todo.empty': '還沒有任務。新增一個任務開始吧!',
|
||||
'todo.filter.my': '我的任務',
|
||||
'todo.filter.overdue': '已逾期',
|
||||
'todo.sidebar.tasks': '任務',
|
||||
'todo.sidebar.categories': '類別',
|
||||
'todo.detail.title': '任務',
|
||||
'todo.detail.description': '描述',
|
||||
'todo.detail.category': '類別',
|
||||
'todo.detail.dueDate': '截止日期',
|
||||
'todo.detail.assignedTo': '指派給',
|
||||
'todo.detail.delete': '刪除',
|
||||
'todo.detail.save': '儲存變更',
|
||||
'todo.sortByPrio': '優先順序',
|
||||
'todo.detail.priority': '優先順序',
|
||||
'todo.detail.noPriority': '無',
|
||||
'todo.detail.create': '建立任務',
|
||||
'notif.test.title': '[測試] 通知',
|
||||
'notif.test.simple.text': '這是一則簡單的測試通知。',
|
||||
'notif.test.boolean.text': '你是否接受這則測試通知?',
|
||||
@@ -2153,39 +2036,10 @@ const zhTw: Record<string, string> = {
|
||||
'notif.action.view_photos': '查看照片',
|
||||
'notif.action.view_vacay': '查看 Vacay',
|
||||
'notif.action.view_admin': '前往管理',
|
||||
'notifications.versionAvailable.title': '有可用更新',
|
||||
'notifications.versionAvailable.text': 'TREK {version} 現已推出。',
|
||||
'notifications.versionAvailable.button': '查看詳情',
|
||||
|
||||
// Notifications — dev test events
|
||||
'notif.test.title': '[測試] 通知',
|
||||
'notif.test.simple.text': '這是一條簡單的測試通知。',
|
||||
'notif.test.boolean.text': '您接受此測試通知嗎?',
|
||||
'notif.test.navigate.text': '點選下方前往儀表板。',
|
||||
|
||||
// Notifications
|
||||
'notif.trip_invite.title': '行程邀請',
|
||||
'notif.trip_invite.text': '{actor} 邀請您加入 {trip}',
|
||||
'notif.booking_change.title': '預訂已更新',
|
||||
'notif.booking_change.text': '{actor} 已更新 {trip} 中的預訂',
|
||||
'notif.trip_reminder.title': '行程提醒',
|
||||
'notif.trip_reminder.text': '您的行程 {trip} 即將開始!',
|
||||
'notif.vacay_invite.title': 'Vacay 合併邀請',
|
||||
'notif.vacay_invite.text': '{actor} 邀請您合併假期計畫',
|
||||
'notif.photos_shared.title': '已分享照片',
|
||||
'notif.photos_shared.text': '{actor} 在 {trip} 中分享了 {count} 張照片',
|
||||
'notif.collab_message.title': '新訊息',
|
||||
'notif.collab_message.text': '{actor} 在 {trip} 中傳送了訊息',
|
||||
'notif.packing_tagged.title': '行李指派',
|
||||
'notif.packing_tagged.text': '{actor} 在 {trip} 中將您指派至 {category}',
|
||||
'notif.version_available.title': '有新版本可用',
|
||||
'notif.version_available.text': 'TREK {version} 現已推出',
|
||||
'notif.action.view_trip': '查看行程',
|
||||
'notif.action.view_collab': '查看訊息',
|
||||
'notif.action.view_packing': '查看行李',
|
||||
'notif.action.view_photos': '查看照片',
|
||||
'notif.action.view_vacay': '查看 Vacay',
|
||||
'notif.action.view_admin': '前往管理員',
|
||||
'notif.action.view': '查看',
|
||||
'notif.action.accept': '接受',
|
||||
'notif.action.decline': '拒絕',
|
||||
|
||||
@@ -1352,6 +1352,24 @@ function WeatherChip({ weather }: { weather: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
// ── Scroll Trigger ───────────────────────────────────────────────────────
|
||||
|
||||
function ScrollTrigger({ onVisible, loading }: { onVisible: () => void; loading: boolean }) {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
useEffect(() => {
|
||||
const el = ref.current
|
||||
if (!el) return
|
||||
const obs = new IntersectionObserver(([entry]) => { if (entry.isIntersecting && !loading) onVisible() }, { rootMargin: '200px' })
|
||||
obs.observe(el)
|
||||
return () => obs.disconnect()
|
||||
}, [onVisible, loading])
|
||||
return (
|
||||
<div ref={ref} className="flex justify-center py-4 mt-2">
|
||||
<div className="w-5 h-5 border-2 border-zinc-300 border-t-zinc-900 dark:border-zinc-600 dark:border-t-white rounded-full animate-spin" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ── Provider Picker ───────────────────────────────────────────────────────
|
||||
|
||||
function ProviderPicker({ provider, userId, entries, trips, existingAssetIds, onClose, onAdd }: {
|
||||
@@ -1698,18 +1716,9 @@ function ProviderPicker({ provider, userId, entries, trips, existingAssetIds, on
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
{/* Infinite scroll trigger */}
|
||||
{hasMore && <ScrollTrigger onVisible={loadMorePhotos} loading={loadingMore} />}
|
||||
</div>
|
||||
{/* Infinite scroll trigger */}
|
||||
{hasMore && (
|
||||
<div className="flex justify-center py-4 mt-2" ref={el => {
|
||||
if (!el) return
|
||||
const obs = new IntersectionObserver(([entry]) => { if (entry.isIntersecting) loadMorePhotos() }, { rootMargin: '200px' })
|
||||
obs.observe(el)
|
||||
return () => obs.disconnect()
|
||||
}}>
|
||||
<div className="w-5 h-5 border-2 border-zinc-300 border-t-zinc-900 dark:border-zinc-600 dark:border-t-white rounded-full animate-spin" />
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user