diff --git a/client/src/components/Packing/PackingListPanel.test.tsx b/client/src/components/Packing/PackingListPanel.test.tsx index 883a1e8e3..9918b05a0 100644 --- a/client/src/components/Packing/PackingListPanel.test.tsx +++ b/client/src/components/Packing/PackingListPanel.test.tsx @@ -236,6 +236,44 @@ describe('PackingListPanel', () => { expect(screen.getByText('No items match this filter')).toBeInTheDocument(); }); + it('FE-COMP-PACKING-093: the A to Z switch sorts each list by name and a second click restores the manual order', async () => { + const user = userEvent.setup(); + const items = [ + buildPackingItem({ id: 1, name: 'Toothbrush', category: 'Bag' }), + buildPackingItem({ id: 2, name: 'adapter', category: 'Bag' }), + buildPackingItem({ id: 3, name: 'Shirt', category: 'Bag' }), + ]; + render(); + const order = () => ['Toothbrush', 'adapter', 'Shirt'] + .map(n => [n, screen.getByText(n)] as const) + .sort(([, a], [, b]) => (a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1)) + .map(([n]) => n); + const toggle = screen.getByRole('button', { name: 'A to Z' }); + + expect(order()).toEqual(['Toothbrush', 'adapter', 'Shirt']); + expect(toggle).toHaveAttribute('aria-pressed', 'false'); + + await user.click(toggle); + expect(order()).toEqual(['adapter', 'Shirt', 'Toothbrush']); + expect(toggle).toHaveAttribute('aria-pressed', 'true'); + expect(localStorage.getItem('trek:packing-sort')).toBe('name'); + + await user.click(toggle); + expect(order()).toEqual(['Toothbrush', 'adapter', 'Shirt']); + expect(localStorage.getItem('trek:packing-sort')).toBe('manual'); + }); + + it('FE-COMP-PACKING-094: sorted A to Z the rows cannot be dragged, and the choice is remembered', () => { + localStorage.setItem('trek:packing-sort', 'name'); + const items = [ + buildPackingItem({ id: 1, name: 'Toothbrush', category: 'Bag' }), + buildPackingItem({ id: 2, name: 'adapter', category: 'Bag' }), + ]; + const { container } = render(); + expect(screen.getByRole('button', { name: 'A to Z' })).toHaveAttribute('aria-pressed', 'true'); + expect(container.querySelector('[draggable="true"]')).toBeNull(); + }); + it('FE-COMP-PACKING-023: inline edit item name via pencil icon calls PUT', async () => { const user = userEvent.setup(); const item = buildPackingItem({ id: 42, name: 'Sunscreen', category: 'Toiletries' }); diff --git a/client/src/components/Packing/PackingListPanelCategoryGroup.tsx b/client/src/components/Packing/PackingListPanelCategoryGroup.tsx index 3654fc0c2..ac2521749 100644 --- a/client/src/components/Packing/PackingListPanelCategoryGroup.tsx +++ b/client/src/components/Packing/PackingListPanelCategoryGroup.tsx @@ -35,6 +35,9 @@ interface KategorieGruppeProps { // order is global, so a within-category drag is mapped back onto the full list. allItems: PackingItem[] onReorder: (orderedIds: number[]) => void + // Off while the list is shown A-Z: a drop there would move an item in an order + // the reader cannot see. + reorderable?: boolean // Three-tier sharing (#858) — threaded down to each item's share control. currentUserId?: number onSetSharing?: (id: number, visibility: 'common' | 'personal' | 'shared', recipientIds: number[]) => void @@ -43,7 +46,7 @@ interface KategorieGruppeProps { onLeave?: (id: number, userId: number) => void } -export function KategorieGruppe({ kategorie, items, tripId, allCategories, onRename, onDeleteAll, onDeleteItem, onAddItem, assignees, tripMembers, onSetAssignees, bagTrackingEnabled, bags, onCreateBag, canEdit = true, allItems, onReorder, currentUserId, onSetSharing, onClone, onJoin, onLeave }: KategorieGruppeProps) { +export function KategorieGruppe({ kategorie, items, tripId, allCategories, onRename, onDeleteAll, onDeleteItem, onAddItem, assignees, tripMembers, onSetAssignees, bagTrackingEnabled, bags, onCreateBag, canEdit = true, allItems, onReorder, reorderable = true, currentUserId, onSetSharing, onClone, onJoin, onLeave }: KategorieGruppeProps) { const [offen, setOffen] = useState(true) const [dragId, setDragId] = useState(null) const [overId, setOverId] = useState(null) @@ -280,7 +283,7 @@ export function KategorieGruppe({ kategorie, items, tripId, allCategories, onRen {}} onDelete={onDeleteItem} bagTrackingEnabled={bagTrackingEnabled} bags={bags} onCreateBag={onCreateBag} canEdit={canEdit} divider={index > 0} tripMembers={tripMembers} currentUserId={currentUserId} onSetSharing={onSetSharing} onClone={onClone} onJoin={onJoin} onLeave={onLeave} - drag={canEdit ? { + drag={canEdit && reorderable ? { isDragging: dragId === item.id, isOver: overId === item.id && dragId !== null && dragId !== item.id, onStart: (id) => { setDragId(id); setOverId(null) }, diff --git a/client/src/components/Packing/PackingListPanelItemRow.tsx b/client/src/components/Packing/PackingListPanelItemRow.tsx index 0af802eff..b1ca760f2 100644 --- a/client/src/components/Packing/PackingListPanelItemRow.tsx +++ b/client/src/components/Packing/PackingListPanelItemRow.tsx @@ -161,6 +161,8 @@ export function ArtikelZeile({ item, tripId, categories, onCategoryChange: _onCa )} + {/* Sorted A-Z there is nothing to drag, but the box keeps its column. */} + {!canDrag && canEdit && !isPlaceholder && } {/* The phone's box: filled with the accent once packed, an outline until then. */} + + )} ) } diff --git a/client/src/components/Packing/packingListPanel.helpers.test.ts b/client/src/components/Packing/packingListPanel.helpers.test.ts index 87ccf071f..30f09d5bc 100644 --- a/client/src/components/Packing/packingListPanel.helpers.test.ts +++ b/client/src/components/Packing/packingListPanel.helpers.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { katColor, itemWeight, bagFillPct, bagTotalWeight, countsTowardsMyLoad, isMarkdownList, parseCsvLine, parseImportLines, unassignedTotalWeight } from './packingListPanel.helpers' +import { katColor, itemWeight, bagFillPct, bagTotalWeight, countsTowardsMyLoad, isMarkdownList, parseCsvLine, parseImportLines, sortItemsByName, unassignedTotalWeight } from './packingListPanel.helpers' import { KAT_COLORS } from './packingListPanel.constants' describe('packingListPanel.helpers', () => { @@ -219,4 +219,26 @@ describe('packingListPanel.helpers', () => { expect(unassignedTotalWeight(undefined, [])).toBe(0) }) }) + describe('sortItemsByName', () => { + const names = (items: { name: string }[]) => items.map(i => i.name) + + it('orders by name, ignoring case and accents the way the language does', () => { + const items = [{ name: 'shirt' }, { name: 'Éponge' }, { name: 'adapter' }, { name: 'Zahnbürste' }, { name: 'Bag' }] + expect(names(sortItemsByName(items, 'en'))).toEqual(['adapter', 'Bag', 'Éponge', 'shirt', 'Zahnbürste']) + }) + + it('reads numbers as numbers', () => { + expect(names(sortItemsByName([{ name: 'Shirt 10' }, { name: 'Shirt 2' }], 'en'))).toEqual(['Shirt 2', 'Shirt 10']) + }) + + it('keeps the placeholder of an empty list at the bottom', () => { + expect(names(sortItemsByName([{ name: '...' }, { name: 'Zip bag' }, { name: 'Adapter' }], 'en'))).toEqual(['Adapter', 'Zip bag', '...']) + }) + + it('leaves the array it was given in its manual order', () => { + const items = [{ name: 'b' }, { name: 'a' }] + sortItemsByName(items, 'en') + expect(names(items)).toEqual(['b', 'a']) + }) + }) }) diff --git a/client/src/components/Packing/packingListPanel.helpers.ts b/client/src/components/Packing/packingListPanel.helpers.ts index aafa9b501..09884335f 100644 --- a/client/src/components/Packing/packingListPanel.helpers.ts +++ b/client/src/components/Packing/packingListPanel.helpers.ts @@ -1,4 +1,4 @@ -import { KAT_COLORS } from './packingListPanel.constants' +import { KAT_COLORS, PACKING_PLACEHOLDER_NAME } from './packingListPanel.constants' // Stable color assignment: category name → index via simple hash export function katColor(kat: string, allCategories?: string[]): string { @@ -180,3 +180,19 @@ export const parseImportLines = (text: string): ParsedImportItem[] => { return { ...splitQuantity(parts[0]), category: undefined, weight_grams: undefined, bag: undefined, checked: false } }).filter(i => i.name) } + +/** + * One list's items in name order, for the A-Z view. Compared the way the reader's + * language sorts (accents next to their letter, "Shirt 2" before "Shirt 10"), and + * the '...' stand-in of an empty list stays at the bottom where it always sits. + * Returns a new array; the stored manual order is left alone. + */ +export function sortItemsByName(items: T[], locale?: string): T[] { + const collator = new Intl.Collator(locale, { sensitivity: 'base', numeric: true }) + return [...items].sort((a, b) => { + const pa = a.name === PACKING_PLACEHOLDER_NAME + const pb = b.name === PACKING_PLACEHOLDER_NAME + if (pa !== pb) return pa ? 1 : -1 + return collator.compare(a.name.trim(), b.name.trim()) + }) +} diff --git a/client/src/components/Packing/usePackingListPanel.ts b/client/src/components/Packing/usePackingListPanel.ts index 0d57ed692..a3efe4509 100644 --- a/client/src/components/Packing/usePackingListPanel.ts +++ b/client/src/components/Packing/usePackingListPanel.ts @@ -11,7 +11,11 @@ import { useNetworkMode } from '../../hooks/useNetworkMode' import { useBagTotalsPing } from './useBagTotalsPing' import type { PackingItem, PackingBag } from '../../types' import { BAG_COLORS, PACKING_PLACEHOLDER_NAME } from './packingListPanel.constants' -import { parseImportLines } from './packingListPanel.helpers' +import { parseImportLines, sortItemsByName } from './packingListPanel.helpers' + +const PACKING_SORT_KEY = 'trek:packing-sort' + +export type PackingSort = 'manual' | 'name' export interface TripMember { id: number @@ -50,6 +54,15 @@ export interface PackingListPanelProps { */ export function usePackingList({ tripId, items, openImportSignal = 0, addCategorySignal = 0, saveTemplateSignal = 0, inlineHeader = true, view: viewProp, onViewChange }: PackingListPanelProps) { const [filter, setFilter] = useState('alle') // 'alle' | 'offen' | 'erledigt' + // A-Z only changes what is shown; the manual order stays stored underneath and + // comes back when the switch is turned off. Remembered per browser. + const [sort, setSortState] = useState(() => { + try { return localStorage.getItem(PACKING_SORT_KEY) === 'name' ? 'name' : 'manual' } catch { return 'manual' } + }) + const setSort = (next: PackingSort) => { + setSortState(next) + try { localStorage.setItem(PACKING_SORT_KEY, next) } catch { /* storage unavailable: the choice lasts until reload */ } + } // Three-tier sharing (#858): 'common' = the group pool (where existing items // live — non-breaking), 'personal' = my own list (private + shared-to-me). const [ownView, setOwnView] = useState<'common' | 'personal'>('common') @@ -65,7 +78,7 @@ export function usePackingList({ tripId, items, openImportSignal = 0, addCategor const isAdmin = useAuthStore((s) => s.user?.role === 'admin') const currentUserId = useAuthStore((s) => s.user?.id) const toast = useToast() - const { t } = useTranslation() + const { t, locale } = useTranslation() // Trip members & category assignees const [tripMembers, setTripMembers] = useState([]) @@ -120,8 +133,11 @@ export function usePackingList({ tripId, items, openImportSignal = 0, addCategor if (!groups[kat]) groups[kat] = [] groups[kat].push(item) } + if (sort === 'name') { + for (const kat of Object.keys(groups)) groups[kat] = sortItemsByName(groups[kat], locale) + } return groups - }, [viewItems, filter, t]) + }, [viewItems, filter, sort, locale, t]) const abgehakt = viewItems.filter(i => i.checked).length const fortschritt = viewItems.length > 0 ? Math.round((abgehakt / viewItems.length) * 100) : 0 @@ -399,7 +415,7 @@ export function usePackingList({ tripId, items, openImportSignal = 0, addCategor view, setView, currentUserId, handleSetSharing, handleCloneItem, handleJoinItem, handleLeaveItem, tripId, items, inlineHeader, t, canEdit, isAdmin, font, reorderPackingItems, - filter, setFilter, addingCategory, setAddingCategory, newCatName, setNewCatName, + filter, setFilter, sort, setSort, addingCategory, setAddingCategory, newCatName, setNewCatName, tripMembers, categoryAssignees, handleSetAssignees, allCategories, gruppiert, abgehakt, fortschritt, handleAddItemToCategory, handleAddNewCategory, handleRenameCategory, handleDeleteCategory, handleDeleteItem, handleClearChecked, bagTrackingEnabled, bags, unassignedWeightGrams, serverWeightsFresh, newBagName, setNewBagName, showAddBag, setShowAddBag, showBagModal, setShowBagModal, diff --git a/shared/src/i18n/ar/packing.ts b/shared/src/i18n/ar/packing.ts index b4ab3dd77..39d310387 100644 --- a/shared/src/i18n/ar/packing.ts +++ b/shared/src/i18n/ar/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'الكل', 'packing.filterOpen': 'مفتوح', 'packing.filterDone': 'تم', + 'packing.sortBy': 'ترتيب حسب', + 'packing.sortByName': 'أ إلى ي', 'packing.emptyTitle': 'قائمة التجهيز فارغة', 'packing.emptyFiltered': 'لا توجد عناصر مطابقة لهذا الفلتر', 'packing.menuRename': 'إعادة تسمية', diff --git a/shared/src/i18n/az/packing.ts b/shared/src/i18n/az/packing.ts index f79be650b..bda9dfcb3 100644 --- a/shared/src/i18n/az/packing.ts +++ b/shared/src/i18n/az/packing.ts @@ -46,6 +46,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Hamısı', 'packing.filterOpen': 'Hazır deyil', 'packing.filterDone': 'Hazırdır', + 'packing.sortBy': 'Sıralama', + 'packing.sortByName': 'A-dan Z-yə', 'packing.emptyTitle': 'Baqaj siyahısı boşdur', 'packing.emptyFiltered': diff --git a/shared/src/i18n/br/packing.ts b/shared/src/i18n/br/packing.ts index c9ae4a9ae..e3eae12a2 100644 --- a/shared/src/i18n/br/packing.ts +++ b/shared/src/i18n/br/packing.ts @@ -42,6 +42,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Todos', 'packing.filterOpen': 'Abertos', 'packing.filterDone': 'Prontos', + 'packing.sortBy': 'Ordenar por', + 'packing.sortByName': 'A a Z', 'packing.emptyTitle': 'A lista de mala está vazia', 'packing.emptyFiltered': 'Nenhum item corresponde ao filtro', 'packing.menuRename': 'Renomear', diff --git a/shared/src/i18n/ca/packing.ts b/shared/src/i18n/ca/packing.ts index 1786e4823..4ec8def6b 100644 --- a/shared/src/i18n/ca/packing.ts +++ b/shared/src/i18n/ca/packing.ts @@ -31,6 +31,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Tot', 'packing.filterOpen': 'Pendents', 'packing.filterDone': 'Fet', + 'packing.sortBy': 'Ordena per', + 'packing.sortByName': 'A a Z', 'packing.emptyTitle': "La llista d'equipatge és buida", 'packing.emptyFiltered': 'Cap element coincideix amb aquest filtre', 'packing.menuRename': 'Canvia el nom', diff --git a/shared/src/i18n/cs/packing.ts b/shared/src/i18n/cs/packing.ts index 89806c108..300688422 100644 --- a/shared/src/i18n/cs/packing.ts +++ b/shared/src/i18n/cs/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Vše', 'packing.filterOpen': 'K zabalení', 'packing.filterDone': 'Hotovo', + 'packing.sortBy': 'Seřadit podle', + 'packing.sortByName': 'A až Z', 'packing.emptyTitle': 'Seznam věcí je prázdný', 'packing.emptyFiltered': 'Žádné položky neodpovídají filtru', 'packing.menuRename': 'Přejmenovat', diff --git a/shared/src/i18n/de/packing.ts b/shared/src/i18n/de/packing.ts index c5fca57c6..9dece6d25 100644 --- a/shared/src/i18n/de/packing.ts +++ b/shared/src/i18n/de/packing.ts @@ -41,6 +41,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Alle', 'packing.filterOpen': 'Offen', 'packing.filterDone': 'Erledigt', + 'packing.sortBy': 'Sortieren nach', + 'packing.sortByName': 'A bis Z', 'packing.emptyTitle': 'Packliste ist leer', 'packing.emptyFiltered': 'Keine Gegenstände in diesem Filter', 'packing.menuRename': 'Umbenennen', diff --git a/shared/src/i18n/en/packing.ts b/shared/src/i18n/en/packing.ts index 8034a98ef..b8cf91929 100644 --- a/shared/src/i18n/en/packing.ts +++ b/shared/src/i18n/en/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'All', 'packing.filterOpen': 'Open', 'packing.filterDone': 'Done', + 'packing.sortBy': 'Sort by', + 'packing.sortByName': 'A to Z', 'packing.emptyTitle': 'Packing list is empty', 'packing.emptyFiltered': 'No items match this filter', 'packing.menuRename': 'Rename', diff --git a/shared/src/i18n/es/packing.ts b/shared/src/i18n/es/packing.ts index 7c840e91c..233ecd2e6 100644 --- a/shared/src/i18n/es/packing.ts +++ b/shared/src/i18n/es/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Todo', 'packing.filterOpen': 'Pendientes', 'packing.filterDone': 'Hecho', + 'packing.sortBy': 'Ordenar por', + 'packing.sortByName': 'A a Z', 'packing.emptyTitle': 'La lista de equipaje está vacía', 'packing.emptyFiltered': 'Ningún elemento coincide con este filtro', 'packing.menuRename': 'Renombrar', diff --git a/shared/src/i18n/et/packing.ts b/shared/src/i18n/et/packing.ts index 51ff2518a..06bda1955 100644 --- a/shared/src/i18n/et/packing.ts +++ b/shared/src/i18n/et/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Kõik', 'packing.filterOpen': 'Pakkimata', 'packing.filterDone': 'Pakitud', + 'packing.sortBy': 'Sordi', + 'packing.sortByName': 'A kuni Ü', 'packing.emptyTitle': 'Pakkimisnimekiri on tühi', 'packing.emptyFiltered': 'Ükski ese ei vasta sellele filtrile', 'packing.menuRename': 'Nimeta ümber', diff --git a/shared/src/i18n/fr/packing.ts b/shared/src/i18n/fr/packing.ts index acc75931c..c1e6d6ddb 100644 --- a/shared/src/i18n/fr/packing.ts +++ b/shared/src/i18n/fr/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Tous', 'packing.filterOpen': 'À faire', 'packing.filterDone': 'Fait', + 'packing.sortBy': 'Trier par', + 'packing.sortByName': 'A à Z', 'packing.emptyTitle': 'La liste de bagages est vide', 'packing.emptyFiltered': 'Aucun article ne correspond à ce filtre', 'packing.menuRename': 'Renommer', diff --git a/shared/src/i18n/gr/packing.ts b/shared/src/i18n/gr/packing.ts index ad21823da..b489e37cd 100644 --- a/shared/src/i18n/gr/packing.ts +++ b/shared/src/i18n/gr/packing.ts @@ -41,6 +41,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Όλα', 'packing.filterOpen': 'Ανοιχτά', 'packing.filterDone': 'Ολοκληρωμένα', + 'packing.sortBy': 'Ταξινόμηση κατά', + 'packing.sortByName': 'Α έως Ω', 'packing.emptyTitle': 'Η λίστα αποσκευών είναι κενή', 'packing.emptyFiltered': 'Κανένα αντικείμενο δεν ταιριάζει με αυτό το φίλτρο', 'packing.menuRename': 'Μετονομασία', diff --git a/shared/src/i18n/hu/packing.ts b/shared/src/i18n/hu/packing.ts index 8e0905b0a..19f539c6c 100644 --- a/shared/src/i18n/hu/packing.ts +++ b/shared/src/i18n/hu/packing.ts @@ -41,6 +41,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Összes', 'packing.filterOpen': 'Nyitott', 'packing.filterDone': 'Kész', + 'packing.sortBy': 'Rendezés', + 'packing.sortByName': 'A-tól Z-ig', 'packing.emptyTitle': 'A csomagolási lista üres', 'packing.emptyFiltered': 'Nincs elem ebben a szűrőben', 'packing.menuRename': 'Átnevezés', diff --git a/shared/src/i18n/id/packing.ts b/shared/src/i18n/id/packing.ts index 8e274e2e4..ee2398772 100644 --- a/shared/src/i18n/id/packing.ts +++ b/shared/src/i18n/id/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Semua', 'packing.filterOpen': 'Belum', 'packing.filterDone': 'Selesai', + 'packing.sortBy': 'Urutkan', + 'packing.sortByName': 'A ke Z', 'packing.emptyTitle': 'Daftar bawaan kosong', 'packing.emptyFiltered': 'Tidak ada item yang cocok dengan filter ini', 'packing.menuRename': 'Ganti Nama', diff --git a/shared/src/i18n/it/packing.ts b/shared/src/i18n/it/packing.ts index d46faad3a..c519df77c 100644 --- a/shared/src/i18n/it/packing.ts +++ b/shared/src/i18n/it/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Tutti', 'packing.filterOpen': 'Da fare', 'packing.filterDone': 'Fatto', + 'packing.sortBy': 'Ordina per', + 'packing.sortByName': 'A-Z', 'packing.emptyTitle': 'La lista valigia è vuota', 'packing.emptyFiltered': 'Nessun elemento corrisponde a questo filtro', 'packing.menuRename': 'Rinomina', diff --git a/shared/src/i18n/ja/packing.ts b/shared/src/i18n/ja/packing.ts index 86dfb38e6..a83df28de 100644 --- a/shared/src/i18n/ja/packing.ts +++ b/shared/src/i18n/ja/packing.ts @@ -39,6 +39,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'すべて', 'packing.filterOpen': '未完了', 'packing.filterDone': '完了', + 'packing.sortBy': '並べ替え', + 'packing.sortByName': '名前順', 'packing.emptyTitle': '持ち物リストは空です', 'packing.emptyFiltered': 'このフィルターに一致する項目はありません', 'packing.menuRename': '名前を変更', diff --git a/shared/src/i18n/ko/packing.ts b/shared/src/i18n/ko/packing.ts index 14bcd9d17..ef7097e9d 100644 --- a/shared/src/i18n/ko/packing.ts +++ b/shared/src/i18n/ko/packing.ts @@ -39,6 +39,8 @@ const packing: TranslationStrings = { 'packing.filterAll': '전체', 'packing.filterOpen': '미완료', 'packing.filterDone': '완료', + 'packing.sortBy': '정렬', + 'packing.sortByName': '가나다순', 'packing.emptyTitle': '짐 목록이 비어 있습니다', 'packing.emptyFiltered': '이 필터와 일치하는 항목이 없습니다', 'packing.menuRename': '이름 변경', diff --git a/shared/src/i18n/nl/packing.ts b/shared/src/i18n/nl/packing.ts index e0415a3f8..b4bfd6366 100644 --- a/shared/src/i18n/nl/packing.ts +++ b/shared/src/i18n/nl/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Alle', 'packing.filterOpen': 'Openstaand', 'packing.filterDone': 'Klaar', + 'packing.sortBy': 'Sorteren op', + 'packing.sortByName': 'A tot Z', 'packing.emptyTitle': 'Inpaklijst is leeg', 'packing.emptyFiltered': 'Geen items gevonden voor dit filter', 'packing.menuRename': 'Hernoemen', diff --git a/shared/src/i18n/pl/packing.ts b/shared/src/i18n/pl/packing.ts index ea888f84c..89246f657 100644 --- a/shared/src/i18n/pl/packing.ts +++ b/shared/src/i18n/pl/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Wszystkie', 'packing.filterOpen': 'Do spakowania', 'packing.filterDone': 'Spakowane', + 'packing.sortBy': 'Sortuj według', + 'packing.sortByName': 'Od A do Z', 'packing.emptyTitle': 'Lista pakowania jest pusta', 'packing.emptyFiltered': 'Brak przedmiotów pasujących do filtra', 'packing.menuRename': 'Zmień nazwę', diff --git a/shared/src/i18n/ru/packing.ts b/shared/src/i18n/ru/packing.ts index 65514f7e7..8992a402c 100644 --- a/shared/src/i18n/ru/packing.ts +++ b/shared/src/i18n/ru/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Все', 'packing.filterOpen': 'Не собрано', 'packing.filterDone': 'Собрано', + 'packing.sortBy': 'Сортировка', + 'packing.sortByName': 'От А до Я', 'packing.emptyTitle': 'Список вещей пуст', 'packing.emptyFiltered': 'Нет вещей, соответствующих фильтру', 'packing.menuRename': 'Переименовать', diff --git a/shared/src/i18n/sk/packing.ts b/shared/src/i18n/sk/packing.ts index 6f213362e..a6ed83819 100644 --- a/shared/src/i18n/sk/packing.ts +++ b/shared/src/i18n/sk/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Všetko', 'packing.filterOpen': 'Na zabalenie', 'packing.filterDone': 'Hotovo', + 'packing.sortBy': 'Zoradiť podľa', + 'packing.sortByName': 'A až Z', 'packing.emptyTitle': 'Zoznam vecí je prázdny', 'packing.emptyFiltered': 'Žiadne položky nezodpovedajú tomuto filtru', 'packing.menuRename': 'Premenovať', diff --git a/shared/src/i18n/sv/packing.ts b/shared/src/i18n/sv/packing.ts index ce28034d3..f414ccbab 100644 --- a/shared/src/i18n/sv/packing.ts +++ b/shared/src/i18n/sv/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Alla', 'packing.filterOpen': 'Öppna', 'packing.filterDone': 'Klar', + 'packing.sortBy': 'Sortera efter', + 'packing.sortByName': 'A till Ö', 'packing.emptyTitle': 'Packlistan är tom', 'packing.emptyFiltered': 'Inga föremål matchar detta filter', 'packing.menuRename': 'Döp om', diff --git a/shared/src/i18n/th/packing.ts b/shared/src/i18n/th/packing.ts index 3a7c17b46..559616b50 100644 --- a/shared/src/i18n/th/packing.ts +++ b/shared/src/i18n/th/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': "ทั้งหมด", 'packing.filterOpen': "ยังไม่ได้จัด", 'packing.filterDone': "เสร็จแล้ว", + 'packing.sortBy': 'เรียงตาม', + 'packing.sortByName': 'ก ถึง ฮ', 'packing.emptyTitle': "รายการจัดกระเป๋าว่างเปล่า", 'packing.emptyFiltered': "ไม่มีรายการที่ตรงกับตัวกรองนี้", 'packing.menuRename': "เปลี่ยนชื่อ", diff --git a/shared/src/i18n/tr/packing.ts b/shared/src/i18n/tr/packing.ts index 9cd010cae..baafc52d2 100644 --- a/shared/src/i18n/tr/packing.ts +++ b/shared/src/i18n/tr/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Tüm', 'packing.filterOpen': 'Açık', 'packing.filterDone': 'Tamamlamak', + 'packing.sortBy': 'Sırala', + 'packing.sortByName': "A'dan Z'ye", 'packing.emptyTitle': 'Paket listesi boş', 'packing.emptyFiltered': 'Bu filtreye uyan öğe yok', 'packing.menuRename': 'Yeniden adlandır', diff --git a/shared/src/i18n/uk/packing.ts b/shared/src/i18n/uk/packing.ts index a3ae6ed92..a81e208aa 100644 --- a/shared/src/i18n/uk/packing.ts +++ b/shared/src/i18n/uk/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Усі', 'packing.filterOpen': 'Не зібрано', 'packing.filterDone': 'Зібрано', + 'packing.sortBy': 'Сортування', + 'packing.sortByName': 'Від А до Я', 'packing.emptyTitle': 'Список речей порожній', 'packing.emptyFiltered': 'Немає речей, що відповідають фільтру', 'packing.menuRename': 'Перейменувати', diff --git a/shared/src/i18n/vi/packing.ts b/shared/src/i18n/vi/packing.ts index bae428d27..d3062960f 100644 --- a/shared/src/i18n/vi/packing.ts +++ b/shared/src/i18n/vi/packing.ts @@ -40,6 +40,8 @@ const packing: TranslationStrings = { 'packing.filterAll': 'Tất cả', 'packing.filterOpen': 'Mở', 'packing.filterDone': 'Xong', + 'packing.sortBy': 'Sắp xếp theo', + 'packing.sortByName': 'A đến Z', 'packing.emptyTitle': 'Danh sách đóng gói trống', 'packing.emptyFiltered': 'Không có mục nào phù hợp với bộ lọc này', 'packing.menuRename': 'Đổi tên', diff --git a/shared/src/i18n/zh-TW/packing.ts b/shared/src/i18n/zh-TW/packing.ts index c938e0d34..0ac291f74 100644 --- a/shared/src/i18n/zh-TW/packing.ts +++ b/shared/src/i18n/zh-TW/packing.ts @@ -39,6 +39,8 @@ const packing: TranslationStrings = { 'packing.filterAll': '全部', 'packing.filterOpen': '未完成', 'packing.filterDone': '已完成', + 'packing.sortBy': '排序方式', + 'packing.sortByName': '依名稱', 'packing.emptyTitle': '行李清單為空', 'packing.emptyFiltered': '沒有匹配的物品', 'packing.menuRename': '重新命名', diff --git a/shared/src/i18n/zh/packing.ts b/shared/src/i18n/zh/packing.ts index b2311dfbe..6df5327ba 100644 --- a/shared/src/i18n/zh/packing.ts +++ b/shared/src/i18n/zh/packing.ts @@ -39,6 +39,8 @@ const packing: TranslationStrings = { 'packing.filterAll': '全部', 'packing.filterOpen': '未完成', 'packing.filterDone': '已完成', + 'packing.sortBy': '排序方式', + 'packing.sortByName': '按名称', 'packing.emptyTitle': '行李清单为空', 'packing.emptyFiltered': '没有匹配的物品', 'packing.menuRename': '重命名',