feat(collections): import a file into a list that already exists

The import dialog always made a new list. It now asks where the places go:
a new list, as before and still the default, or a list that is already there.
The picker offers the lists the person may edit, which is their own plus a
shared one where they are an editor or an admin, and starts on the list they
have open.

Adding to a list only ever adds. A place the list already holds is left
exactly as it is, with its status, notes, rating and labels, and counted as
already there in what the import reports; it is recognised the way a single
save recognises one, by provider id, then name, then position. The list keeps
its own name, colour, icon and description whatever the file says, a label
the file brings is created only when the list has none of that name, and new
places are appended after the ones already there so a manual order survives.

The route is POST /api/addons/collections/:id/import, 200 because it adds to
a list rather than making one, and both imports now write their places through
the same helper.
This commit is contained in:
Maurice
2026-09-19 23:12:25 +02:00
parent 7cfec6452d
commit d803efd39d
36 changed files with 978 additions and 81 deletions
@@ -172,8 +172,8 @@ export type CollectionFile = z.infer<typeof collectionFileSchema>;
/**
* The import request: the file itself, plus the one thing the importer may
* decide rather than the file. A list always arrives as a NEW list, so there
* is no target id here and no way for a file to write into an existing one.
* decide rather than the file. This one always makes a NEW list, so it carries
* no target id; the list to add to is named in the URL of the route below.
*/
export const collectionImportRequestSchema = z.object({
file: collectionFileSchema,
@@ -182,12 +182,29 @@ export const collectionImportRequestSchema = z.object({
});
export type CollectionImportRequest = z.infer<typeof collectionImportRequestSchema>;
/**
* The same file read into a list that already exists.
*
* Only the file: what the list is called, how it looks and what it says stay
* the list's own. Nothing in the request can overwrite a place either, so the
* worst a file can do to a list somebody else shares is add to it.
*/
export const collectionImportIntoRequestSchema = z.object({
file: collectionFileSchema,
});
export type CollectionImportIntoRequest = z.infer<typeof collectionImportIntoRequestSchema>;
export interface CollectionImportResult {
/** The list as created, so the client can select it without a refetch. */
/** The list as created or added to, so the client can select it without a refetch. */
collection: unknown;
imported: number;
/** Places the file carried that the contract refused. */
skipped: number;
/**
* Places the list already had, left exactly as they were. Only an import
* into an existing list can report any: a new list starts empty.
*/
duplicates?: number;
}
/*
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'استيراد قائمة',
'collections.file.choose': 'اختر ملف قائمة',
'collections.file.confirm': 'استيراد',
'collections.file.targetNew': 'قائمة جديدة',
'collections.file.targetNewHint': 'الملف كقائمة مستقلة',
'collections.file.targetExisting': 'الإضافة إلى قائمة',
'collections.file.targetExistingHint': 'إلى قائمة لديك بالفعل',
'collections.file.searchLists': 'البحث في القوائم',
'collections.file.intoHint': 'الأماكن الموجودة في القائمة تبقى كما هي، وكذلك اسمها ولونها. وتُضاف التسميات القادمة من الملف.',
'collections.file.confirmInto': 'إضافة إلى القائمة',
'collections.file.doneInto': 'تمت إضافة {count} مكانًا إلى {name}',
'collections.file.doneIntoDuplicates': 'تمت إضافة {count} إلى {name}، و{duplicates} كانت موجودة بالفعل',
'collections.file.doneIntoNothing': 'كل الأماكن في الملف موجودة بالفعل في {name}',
'collections.file.change': 'تغيير',
'collections.file.labelCount': '{count} تسمية',
'collections.file.hint': 'تصل الأماكن كقائمة جديدة خاصة بك. أما التقييمات والأعضاء والصور المرفوعة فلا تأتي معها.',
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Importar lista',
'collections.file.choose': 'Escolher um arquivo de lista',
'collections.file.confirm': 'Importar',
'collections.file.targetNew': 'Nova lista',
'collections.file.targetNewHint': 'O arquivo como lista própria',
'collections.file.targetExisting': 'Adicionar a uma lista',
'collections.file.targetExistingHint': 'A uma que você já tem',
'collections.file.searchLists': 'Buscar listas',
'collections.file.intoHint': 'Os lugares que a lista já tem continuam como estão, assim como o nome e a cor. As etiquetas do arquivo são adicionadas.',
'collections.file.confirmInto': 'Adicionar à lista',
'collections.file.doneInto': '{count} lugares adicionados a {name}',
'collections.file.doneIntoDuplicates': '{count} adicionados a {name}, {duplicates} já estavam lá',
'collections.file.doneIntoNothing': 'Todos os lugares do arquivo já estão em {name}',
'collections.file.change': 'Trocar',
'collections.file.labelCount': '{count} etiquetas',
'collections.file.hint':
+10
View File
@@ -142,6 +142,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Importa una llista',
'collections.file.choose': 'Tria un fitxer de llista',
'collections.file.confirm': 'Importa',
'collections.file.targetNew': 'Llista nova',
'collections.file.targetNewHint': 'El fitxer com a llista pròpia',
'collections.file.targetExisting': 'Afegeix a una llista',
'collections.file.targetExistingHint': 'A una que ja tens',
'collections.file.searchLists': 'Cerca llistes',
'collections.file.intoHint': 'Els llocs que la llista ja té es queden com estan, igual que el nom i el color. Les etiquetes del fitxer s\'hi afegeixen.',
'collections.file.confirmInto': 'Afegeix a la llista',
'collections.file.doneInto': '{count} llocs afegits a {name}',
'collections.file.doneIntoDuplicates': '{count} afegits a {name}, {duplicates} ja hi eren',
'collections.file.doneIntoNothing': 'Tots els llocs del fitxer ja són a {name}',
'collections.file.change': 'Canvia',
'collections.file.labelCount': '{count} etiquetes',
'collections.file.hint':
+10
View File
@@ -150,6 +150,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Import seznamu',
'collections.file.choose': 'Vyberte soubor se seznamem',
'collections.file.confirm': 'Importovat',
'collections.file.targetNew': 'Nový seznam',
'collections.file.targetNewHint': 'Soubor jako samostatný seznam',
'collections.file.targetExisting': 'Přidat do seznamu',
'collections.file.targetExistingHint': 'Do seznamu, který už máte',
'collections.file.searchLists': 'Hledat seznamy',
'collections.file.intoHint': 'Místa, která seznam už má, zůstanou beze změny, stejně jako jeho název a barva. Štítky ze souboru se přidají.',
'collections.file.confirmInto': 'Přidat do seznamu',
'collections.file.doneInto': '{count} míst přidáno do {name}',
'collections.file.doneIntoDuplicates': '{count} přidáno do {name}, {duplicates} už tam bylo',
'collections.file.doneIntoNothing': 'Všechna místa ze souboru už v {name} jsou',
'collections.file.change': 'Změnit',
'collections.file.labelCount': 'Štítky: {count}',
'collections.file.hint':
+10
View File
@@ -152,6 +152,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Liste importieren',
'collections.file.choose': 'Listendatei auswählen',
'collections.file.confirm': 'Importieren',
'collections.file.targetNew': 'Neue Liste',
'collections.file.targetNewHint': 'Die Datei als eigene Liste',
'collections.file.targetExisting': 'Zu einer Liste hinzufügen',
'collections.file.targetExistingHint': 'Zu einer, die es schon gibt',
'collections.file.searchLists': 'Listen durchsuchen',
'collections.file.intoHint': 'Orte, die die Liste schon hat, bleiben unverändert, ebenso ihr Name und ihre Farbe. Labels aus der Datei kommen dazu.',
'collections.file.confirmInto': 'Hinzufügen',
'collections.file.doneInto': '{count} Orte zu {name} hinzugefügt',
'collections.file.doneIntoDuplicates': '{count} zu {name} hinzugefügt, {duplicates} waren schon drin',
'collections.file.doneIntoNothing': 'Alle Orte der Datei sind schon in {name}',
'collections.file.change': 'Ändern',
'collections.file.labelCount': '{count} Labels',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Import a list',
'collections.file.choose': 'Choose a list file',
'collections.file.confirm': 'Import',
'collections.file.targetNew': 'New list',
'collections.file.targetNewHint': 'The file as a list of its own',
'collections.file.targetExisting': 'Add to a list',
'collections.file.targetExistingHint': 'Into one you already have',
'collections.file.searchLists': 'Search lists',
'collections.file.intoHint': 'Places the list already has stay as they are, and so do its name and colour. Labels the file brings are added.',
'collections.file.confirmInto': 'Add to list',
'collections.file.doneInto': '{count} places added to {name}',
'collections.file.doneIntoDuplicates': '{count} added to {name}, {duplicates} were already there',
'collections.file.doneIntoNothing': 'Every place in the file is already in {name}',
'collections.file.change': 'Change',
'collections.file.labelCount': '{count} labels',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Importar una lista',
'collections.file.choose': 'Elegir un archivo de lista',
'collections.file.confirm': 'Importar',
'collections.file.targetNew': 'Nueva lista',
'collections.file.targetNewHint': 'El archivo como lista propia',
'collections.file.targetExisting': 'Añadir a una lista',
'collections.file.targetExistingHint': 'A una que ya tienes',
'collections.file.searchLists': 'Buscar listas',
'collections.file.intoHint': 'Los lugares que la lista ya tiene se quedan como están, igual que su nombre y su color. Las etiquetas del archivo se añaden.',
'collections.file.confirmInto': 'Añadir a la lista',
'collections.file.doneInto': '{count} lugares añadidos a {name}',
'collections.file.doneIntoDuplicates': '{count} añadidos a {name}, {duplicates} ya estaban',
'collections.file.doneIntoNothing': 'Todos los lugares del archivo ya están en {name}',
'collections.file.change': 'Cambiar',
'collections.file.labelCount': '{count} etiquetas',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Importer une liste',
'collections.file.choose': 'Choisir un fichier de liste',
'collections.file.confirm': 'Importer',
'collections.file.targetNew': 'Nouvelle liste',
'collections.file.targetNewHint': 'Le fichier comme liste à part',
'collections.file.targetExisting': 'Ajouter à une liste',
'collections.file.targetExistingHint': 'À une liste que vous avez déjà',
'collections.file.searchLists': 'Rechercher une liste',
'collections.file.intoHint': 'Les lieux déjà dans la liste restent tels quels, comme son nom et sa couleur. Les étiquettes du fichier sont ajoutées.',
'collections.file.confirmInto': 'Ajouter à la liste',
'collections.file.doneInto': '{count} lieux ajoutés à {name}',
'collections.file.doneIntoDuplicates': '{count} ajoutés à {name}, {duplicates} y étaient déjà',
'collections.file.doneIntoNothing': 'Tous les lieux du fichier sont déjà dans {name}',
'collections.file.change': 'Changer',
'collections.file.labelCount': '{count} étiquettes',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Εισαγωγή λίστας',
'collections.file.choose': 'Επιλέξτε αρχείο λίστας',
'collections.file.confirm': 'Εισαγωγή',
'collections.file.targetNew': 'Νέα λίστα',
'collections.file.targetNewHint': 'Το αρχείο ως ξεχωριστή λίστα',
'collections.file.targetExisting': 'Προσθήκη σε λίστα',
'collections.file.targetExistingHint': 'Σε μία που έχετε ήδη',
'collections.file.searchLists': 'Αναζήτηση λιστών',
'collections.file.intoHint': 'Τα μέρη που έχει ήδη η λίστα μένουν όπως είναι, όπως και το όνομα και το χρώμα της. Οι ετικέτες του αρχείου προστίθενται.',
'collections.file.confirmInto': 'Προσθήκη στη λίστα',
'collections.file.doneInto': '{count} μέρη προστέθηκαν στη λίστα {name}',
'collections.file.doneIntoDuplicates': '{count} προστέθηκαν στη λίστα {name}, {duplicates} υπήρχαν ήδη',
'collections.file.doneIntoNothing': 'Όλα τα μέρη του αρχείου είναι ήδη στη λίστα {name}',
'collections.file.change': 'Αλλαγή',
'collections.file.labelCount': '{count} ετικέτες',
'collections.file.hint':
+10
View File
@@ -152,6 +152,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Lista importálása',
'collections.file.choose': 'Válassz listafájlt',
'collections.file.confirm': 'Importálás',
'collections.file.targetNew': 'Új lista',
'collections.file.targetNewHint': 'A fájl külön listaként',
'collections.file.targetExisting': 'Hozzáadás listához',
'collections.file.targetExistingHint': 'Egy meglévő listához',
'collections.file.searchLists': 'Listák keresése',
'collections.file.intoHint': 'A listában már meglévő helyek változatlanok maradnak, ahogy a neve és a színe is. A fájl címkéi bekerülnek.',
'collections.file.confirmInto': 'Hozzáadás a listához',
'collections.file.doneInto': '{count} hely hozzáadva ehhez: {name}',
'collections.file.doneIntoDuplicates': '{count} hozzáadva ehhez: {name}, {duplicates} már benne volt',
'collections.file.doneIntoNothing': 'A fájl minden helye már benne van ebben: {name}',
'collections.file.change': 'Csere',
'collections.file.labelCount': '{count} címke',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Impor daftar',
'collections.file.choose': 'Pilih berkas daftar',
'collections.file.confirm': 'Impor',
'collections.file.targetNew': 'Daftar baru',
'collections.file.targetNewHint': 'Berkas sebagai daftar tersendiri',
'collections.file.targetExisting': 'Tambahkan ke daftar',
'collections.file.targetExistingHint': 'Ke daftar yang sudah ada',
'collections.file.searchLists': 'Cari daftar',
'collections.file.intoHint': 'Tempat yang sudah ada di daftar tetap seperti semula, begitu juga nama dan warnanya. Label dari berkas akan ditambahkan.',
'collections.file.confirmInto': 'Tambahkan ke daftar',
'collections.file.doneInto': '{count} tempat ditambahkan ke {name}',
'collections.file.doneIntoDuplicates': '{count} ditambahkan ke {name}, {duplicates} sudah ada',
'collections.file.doneIntoNothing': 'Semua tempat dalam berkas sudah ada di {name}',
'collections.file.change': 'Ganti',
'collections.file.labelCount': '{count} label',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Importa un elenco',
'collections.file.choose': 'Scegli un file di elenco',
'collections.file.confirm': 'Importa',
'collections.file.targetNew': 'Nuova lista',
'collections.file.targetNewHint': 'Il file come lista a sé',
'collections.file.targetExisting': 'Aggiungi a una lista',
'collections.file.targetExistingHint': 'A una che hai già',
'collections.file.searchLists': 'Cerca liste',
'collections.file.intoHint': 'I luoghi già presenti nella lista restano come sono, così come il suo nome e il suo colore. Le etichette del file vengono aggiunte.',
'collections.file.confirmInto': 'Aggiungi alla lista',
'collections.file.doneInto': '{count} luoghi aggiunti a {name}',
'collections.file.doneIntoDuplicates': '{count} aggiunti a {name}, {duplicates} erano già presenti',
'collections.file.doneIntoNothing': 'Tutti i luoghi del file sono già in {name}',
'collections.file.change': 'Cambia',
'collections.file.labelCount': '{count} etichette',
'collections.file.hint':
+10
View File
@@ -150,6 +150,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'リストのインポート',
'collections.file.choose': 'リストファイルを選択',
'collections.file.confirm': 'インポート',
'collections.file.targetNew': '新しいリスト',
'collections.file.targetNewHint': 'ファイルを独立したリストに',
'collections.file.targetExisting': 'リストに追加',
'collections.file.targetExistingHint': 'すでにあるリストへ',
'collections.file.searchLists': 'リストを検索',
'collections.file.intoHint': 'リストにすでにある場所はそのまま残り、名前と色も変わりません。ファイルのラベルは追加されます。',
'collections.file.confirmInto': 'リストに追加',
'collections.file.doneInto': '{count} 件の場所を {name} に追加しました',
'collections.file.doneIntoDuplicates': '{count} 件を {name} に追加しました。{duplicates} 件はすでにありました',
'collections.file.doneIntoNothing': 'ファイルの場所はすべてすでに {name} にあります',
'collections.file.change': '変更',
'collections.file.labelCount': 'ラベル {count} 件',
'collections.file.hint':
+10
View File
@@ -150,6 +150,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': '목록 가져오기',
'collections.file.choose': '목록 파일 선택',
'collections.file.confirm': '가져오기',
'collections.file.targetNew': '새 리스트',
'collections.file.targetNewHint': '파일을 별도 리스트로',
'collections.file.targetExisting': '리스트에 추가',
'collections.file.targetExistingHint': '이미 있는 리스트에',
'collections.file.searchLists': '리스트 검색',
'collections.file.intoHint': '리스트에 이미 있는 장소는 그대로 유지되고, 이름과 색도 그대로입니다. 파일의 라벨은 추가됩니다.',
'collections.file.confirmInto': '리스트에 추가',
'collections.file.doneInto': '{count}개 장소를 {name}에 추가했습니다',
'collections.file.doneIntoDuplicates': '{count}개를 {name}에 추가했고, {duplicates}개는 이미 있었습니다',
'collections.file.doneIntoNothing': '파일의 모든 장소가 이미 {name}에 있습니다',
'collections.file.change': '변경',
'collections.file.labelCount': '라벨 {count}개',
'collections.file.hint': '장소는 내 새 목록으로 들어옵니다. 평가, 멤버, 업로드한 사진은 함께 오지 않습니다.',
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Lijst importeren',
'collections.file.choose': 'Kies een lijstbestand',
'collections.file.confirm': 'Importeren',
'collections.file.targetNew': 'Nieuwe lijst',
'collections.file.targetNewHint': 'Het bestand als eigen lijst',
'collections.file.targetExisting': 'Aan een lijst toevoegen',
'collections.file.targetExistingHint': 'Aan een lijst die je al hebt',
'collections.file.searchLists': 'Lijsten zoeken',
'collections.file.intoHint': 'Plekken die de lijst al heeft blijven zoals ze zijn, net als de naam en de kleur. Labels uit het bestand komen erbij.',
'collections.file.confirmInto': 'Aan lijst toevoegen',
'collections.file.doneInto': '{count} plekken toegevoegd aan {name}',
'collections.file.doneIntoDuplicates': '{count} toegevoegd aan {name}, {duplicates} stonden er al in',
'collections.file.doneIntoNothing': 'Alle plekken uit het bestand staan al in {name}',
'collections.file.change': 'Wijzigen',
'collections.file.labelCount': '{count} labels',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Importuj listę',
'collections.file.choose': 'Wybierz plik listy',
'collections.file.confirm': 'Importuj',
'collections.file.targetNew': 'Nowa lista',
'collections.file.targetNewHint': 'Plik jako osobna lista',
'collections.file.targetExisting': 'Dodaj do listy',
'collections.file.targetExistingHint': 'Do listy, którą już masz',
'collections.file.searchLists': 'Szukaj list',
'collections.file.intoHint': 'Miejsca, które lista już ma, zostają bez zmian, tak samo jej nazwa i kolor. Etykiety z pliku zostaną dodane.',
'collections.file.confirmInto': 'Dodaj do listy',
'collections.file.doneInto': 'Dodano {count} miejsc do {name}',
'collections.file.doneIntoDuplicates': 'Dodano {count} do {name}, {duplicates} już tam było',
'collections.file.doneIntoNothing': 'Wszystkie miejsca z pliku są już w {name}',
'collections.file.change': 'Zmień',
'collections.file.labelCount': 'Etykiety: {count}',
'collections.file.hint':
+10
View File
@@ -150,6 +150,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Импорт списка',
'collections.file.choose': 'Выберите файл списка',
'collections.file.confirm': 'Импортировать',
'collections.file.targetNew': 'Новый список',
'collections.file.targetNewHint': 'Файл как отдельный список',
'collections.file.targetExisting': 'Добавить в список',
'collections.file.targetExistingHint': 'В список, который уже есть',
'collections.file.searchLists': 'Поиск списков',
'collections.file.intoHint': 'Места, которые уже есть в списке, остаются без изменений, как и его название и цвет. Метки из файла добавляются.',
'collections.file.confirmInto': 'Добавить в список',
'collections.file.doneInto': '{count} мест добавлено в {name}',
'collections.file.doneIntoDuplicates': '{count} добавлено в {name}, {duplicates} уже были там',
'collections.file.doneIntoNothing': 'Все места из файла уже есть в {name}',
'collections.file.change': 'Изменить',
'collections.file.labelCount': 'Меток: {count}',
'collections.file.hint':
+10
View File
@@ -150,6 +150,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Importera lista',
'collections.file.choose': 'Välj en listfil',
'collections.file.confirm': 'Importera',
'collections.file.targetNew': 'Ny lista',
'collections.file.targetNewHint': 'Filen som en egen lista',
'collections.file.targetExisting': 'Lägg till i en lista',
'collections.file.targetExistingHint': 'I en du redan har',
'collections.file.searchLists': 'Sök listor',
'collections.file.intoHint': 'Platser som listan redan har lämnas som de är, liksom namn och färg. Etiketter från filen läggs till.',
'collections.file.confirmInto': 'Lägg till i listan',
'collections.file.doneInto': '{count} platser tillagda i {name}',
'collections.file.doneIntoDuplicates': '{count} tillagda i {name}, {duplicates} fanns redan',
'collections.file.doneIntoNothing': 'Alla platser i filen finns redan i {name}',
'collections.file.change': 'Byt',
'collections.file.labelCount': '{count} etiketter',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Liste içe aktar',
'collections.file.choose': 'Bir liste dosyası seç',
'collections.file.confirm': 'İçe aktar',
'collections.file.targetNew': 'Yeni liste',
'collections.file.targetNewHint': 'Dosya kendi listesi olarak',
'collections.file.targetExisting': 'Bir listeye ekle',
'collections.file.targetExistingHint': 'Zaten sahip olduğun bir listeye',
'collections.file.searchLists': 'Listelerde ara',
'collections.file.intoHint': 'Listede zaten bulunan yerler olduğu gibi kalır, adı ve rengi de öyle. Dosyadaki etiketler eklenir.',
'collections.file.confirmInto': 'Listeye ekle',
'collections.file.doneInto': '{name} listesine {count} yer eklendi',
'collections.file.doneIntoDuplicates': '{name} listesine {count} eklendi, {duplicates} tanesi zaten vardı',
'collections.file.doneIntoNothing': 'Dosyadaki tüm yerler zaten {name} listesinde',
'collections.file.change': 'Değiştir',
'collections.file.labelCount': '{count} etiket',
'collections.file.hint':
+10
View File
@@ -150,6 +150,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Імпорт списку',
'collections.file.choose': 'Виберіть файл списку',
'collections.file.confirm': 'Імпортувати',
'collections.file.targetNew': 'Новий список',
'collections.file.targetNewHint': 'Файл як окремий список',
'collections.file.targetExisting': 'Додати до списку',
'collections.file.targetExistingHint': 'До списку, який уже є',
'collections.file.searchLists': 'Пошук списків',
'collections.file.intoHint': 'Місця, які вже є у списку, лишаються без змін, як і його назва та колір. Мітки з файлу додаються.',
'collections.file.confirmInto': 'Додати до списку',
'collections.file.doneInto': '{count} місць додано до {name}',
'collections.file.doneIntoDuplicates': '{count} додано до {name}, {duplicates} уже були там',
'collections.file.doneIntoNothing': 'Усі місця з файлу вже є у {name}',
'collections.file.change': 'Змінити',
'collections.file.labelCount': 'Міток: {count}',
'collections.file.hint':
+10
View File
@@ -151,6 +151,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': 'Nhập danh sách',
'collections.file.choose': 'Chọn tệp danh sách',
'collections.file.confirm': 'Nhập',
'collections.file.targetNew': 'Danh sách mới',
'collections.file.targetNewHint': 'Tệp thành một danh sách riêng',
'collections.file.targetExisting': 'Thêm vào một danh sách',
'collections.file.targetExistingHint': 'Vào danh sách bạn đã có',
'collections.file.searchLists': 'Tìm danh sách',
'collections.file.intoHint': 'Những địa điểm danh sách đã có vẫn giữ nguyên, tên và màu cũng vậy. Nhãn từ tệp sẽ được thêm vào.',
'collections.file.confirmInto': 'Thêm vào danh sách',
'collections.file.doneInto': 'Đã thêm {count} địa điểm vào {name}',
'collections.file.doneIntoDuplicates': 'Đã thêm {count} vào {name}, {duplicates} đã có sẵn',
'collections.file.doneIntoNothing': 'Mọi địa điểm trong tệp đều đã có trong {name}',
'collections.file.change': 'Đổi',
'collections.file.labelCount': '{count} nhãn',
'collections.file.hint':
+10
View File
@@ -150,6 +150,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': '匯入清單',
'collections.file.choose': '選擇清單檔案',
'collections.file.confirm': '匯入',
'collections.file.targetNew': '新增清單',
'collections.file.targetNewHint': '把檔案當成獨立清單',
'collections.file.targetExisting': '加入清單',
'collections.file.targetExistingHint': '加入已有的清單',
'collections.file.searchLists': '搜尋清單',
'collections.file.intoHint': '清單中已有的地點維持原樣,名稱與顏色也不變。檔案帶來的標籤會加入。',
'collections.file.confirmInto': '加入清單',
'collections.file.doneInto': '已將 {count} 個地點加入 {name}',
'collections.file.doneIntoDuplicates': '已將 {count} 個加入 {name},{duplicates} 個原本就在其中',
'collections.file.doneIntoNothing': '檔案中的地點都已在 {name} 中',
'collections.file.change': '更換',
'collections.file.labelCount': '{count} 個標籤',
'collections.file.hint': '這些地點會成為你自己的新清單。評分、成員與上傳的照片不會一併匯入。',
+10
View File
@@ -150,6 +150,16 @@ const collection: TranslationStrings = {
'collections.file.importTitle': '导入列表',
'collections.file.choose': '选择列表文件',
'collections.file.confirm': '导入',
'collections.file.targetNew': '新建列表',
'collections.file.targetNewHint': '把文件作为单独的列表',
'collections.file.targetExisting': '添加到列表',
'collections.file.targetExistingHint': '添加到已有的列表',
'collections.file.searchLists': '搜索列表',
'collections.file.intoHint': '列表中已有的地点保持不变,名称和颜色也不变。文件中的标签会被添加。',
'collections.file.confirmInto': '添加到列表',
'collections.file.doneInto': '已将 {count} 个地点添加到 {name}',
'collections.file.doneIntoDuplicates': '已将 {count} 个添加到 {name},{duplicates} 个原本就在其中',
'collections.file.doneIntoNothing': '文件中的地点都已在 {name} 中',
'collections.file.change': '更换',
'collections.file.labelCount': '{count} 个标签',
'collections.file.hint': '这些地点会成为你自己的新列表。评分、成员和上传的照片不会一起导入。',