@rmdes/indiekit-endpoint-blogroll 1.0.17 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +241 -0
- package/locales/de.json +133 -0
- package/locales/es-419.json +133 -0
- package/locales/es.json +133 -0
- package/locales/fr.json +133 -0
- package/locales/hi.json +133 -0
- package/locales/id.json +133 -0
- package/locales/it.json +133 -0
- package/locales/nl.json +133 -0
- package/locales/pl.json +133 -0
- package/locales/pt-BR.json +133 -0
- package/locales/pt.json +133 -0
- package/locales/sr.json +133 -0
- package/locales/sv.json +133 -0
- package/locales/zh-Hans-CN.json +133 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Blogroll Endpoint for Indiekit
|
|
2
|
+
|
|
3
|
+
An Indiekit plugin that provides a comprehensive blogroll management system with feed aggregation, admin UI, and public API.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multiple Source Types:** Import blogs from OPML files/URLs, Microsub subscriptions, or add manually
|
|
8
|
+
- **Background Feed Fetching:** Automatically syncs blogs and caches recent items
|
|
9
|
+
- **Microsub Integration:** Mirror your Microsub subscriptions as a blogroll (zero duplication)
|
|
10
|
+
- **Admin UI:** Manage sources, blogs, and view recent activity
|
|
11
|
+
- **Public JSON API:** Read-only endpoints for frontend integration
|
|
12
|
+
- **OPML Export:** Export your blogroll as OPML (all or by category)
|
|
13
|
+
- **Feed Discovery:** Auto-discover feeds from website URLs
|
|
14
|
+
- **Item Retention:** Automatic cleanup of old items (encourages fresh content discovery)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @rmdes/indiekit-endpoint-blogroll
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
Add to your `indiekit.config.js`:
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import BlogrollEndpoint from "@rmdes/indiekit-endpoint-blogroll";
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
plugins: [
|
|
31
|
+
new BlogrollEndpoint({
|
|
32
|
+
mountPath: "/blogrollapi", // Admin UI and API base path
|
|
33
|
+
syncInterval: 3600000, // 1 hour (in milliseconds)
|
|
34
|
+
maxItemsPerBlog: 50, // Items to fetch per blog
|
|
35
|
+
maxItemAge: 7, // Days - older items auto-deleted
|
|
36
|
+
fetchTimeout: 15000 // 15 seconds per feed fetch
|
|
37
|
+
})
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Requirements
|
|
43
|
+
|
|
44
|
+
- **Indiekit:** `>=1.0.0-beta.25`
|
|
45
|
+
- **MongoDB:** Required for data storage
|
|
46
|
+
- **Optional:** `@rmdes/indiekit-endpoint-microsub` for Microsub integration
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
### Admin UI
|
|
51
|
+
|
|
52
|
+
Navigate to `/blogrollapi` in your Indiekit instance to access:
|
|
53
|
+
|
|
54
|
+
- **Dashboard:** View sync status, blog counts, recent activity
|
|
55
|
+
- **Sources:** Manage OPML and Microsub sources
|
|
56
|
+
- **Blogs:** Add/edit/delete individual blogs, refresh feeds
|
|
57
|
+
- **Manual Sync:** Trigger immediate sync or clear and resync
|
|
58
|
+
|
|
59
|
+
### Source Types
|
|
60
|
+
|
|
61
|
+
1. **OPML URL:** Point to a public OPML file (e.g., your feed reader's export)
|
|
62
|
+
2. **OPML File:** Paste OPML XML directly into the form
|
|
63
|
+
3. **Microsub:** Import subscriptions from your Microsub channels
|
|
64
|
+
4. **Manual:** Add individual blog feeds one at a time
|
|
65
|
+
|
|
66
|
+
### Public API
|
|
67
|
+
|
|
68
|
+
All API endpoints return JSON (except OPML export which returns XML).
|
|
69
|
+
|
|
70
|
+
**List Blogs**
|
|
71
|
+
```
|
|
72
|
+
GET /blogrollapi/api/blogs?category=Tech&limit=100&offset=0
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Get Blog with Recent Items**
|
|
76
|
+
```
|
|
77
|
+
GET /blogrollapi/api/blogs/:id
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**List Items Across All Blogs**
|
|
81
|
+
```
|
|
82
|
+
GET /blogrollapi/api/items?blog=<id>&category=Tech&limit=50&offset=0
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**List Categories**
|
|
86
|
+
```
|
|
87
|
+
GET /blogrollapi/api/categories
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Sync Status**
|
|
91
|
+
```
|
|
92
|
+
GET /blogrollapi/api/status
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Export OPML**
|
|
96
|
+
```
|
|
97
|
+
GET /blogrollapi/api/opml (all blogs)
|
|
98
|
+
GET /blogrollapi/api/opml/:category (specific category)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Example Response
|
|
102
|
+
|
|
103
|
+
**GET /blogrollapi/api/blogs**
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"items": [
|
|
107
|
+
{
|
|
108
|
+
"id": "507f1f77bcf86cd799439011",
|
|
109
|
+
"title": "Example Blog",
|
|
110
|
+
"description": "A great blog about tech",
|
|
111
|
+
"feedUrl": "https://example.com/feed",
|
|
112
|
+
"siteUrl": "https://example.com",
|
|
113
|
+
"feedType": "rss",
|
|
114
|
+
"category": "Tech",
|
|
115
|
+
"tags": ["programming", "web"],
|
|
116
|
+
"photo": "https://example.com/icon.png",
|
|
117
|
+
"status": "active",
|
|
118
|
+
"itemCount": 25,
|
|
119
|
+
"pinned": false,
|
|
120
|
+
"lastFetchAt": "2026-02-13T10:30:00.000Z"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"total": 42,
|
|
124
|
+
"hasMore": true
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**GET /blogrollapi/api/items**
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"items": [
|
|
132
|
+
{
|
|
133
|
+
"id": "507f1f77bcf86cd799439011",
|
|
134
|
+
"url": "https://example.com/post/hello",
|
|
135
|
+
"title": "Hello World",
|
|
136
|
+
"summary": "My first blog post...",
|
|
137
|
+
"published": "2026-02-13T10:00:00.000Z",
|
|
138
|
+
"isFuture": false,
|
|
139
|
+
"author": { "name": "Jane Doe" },
|
|
140
|
+
"photo": ["https://example.com/image.jpg"],
|
|
141
|
+
"categories": ["announcement"],
|
|
142
|
+
"blog": {
|
|
143
|
+
"id": "507f1f77bcf86cd799439011",
|
|
144
|
+
"title": "Example Blog",
|
|
145
|
+
"siteUrl": "https://example.com",
|
|
146
|
+
"category": "Tech",
|
|
147
|
+
"photo": "https://example.com/icon.png"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"hasMore": false
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Microsub Integration
|
|
156
|
+
|
|
157
|
+
If you have `@rmdes/indiekit-endpoint-microsub` installed, the blogroll can mirror your subscriptions:
|
|
158
|
+
|
|
159
|
+
1. Create a Microsub source in the admin UI
|
|
160
|
+
2. Select specific channels or sync all channels
|
|
161
|
+
3. Add a category prefix (optional) to distinguish Microsub blogs
|
|
162
|
+
4. Blogs and items are referenced, not duplicated
|
|
163
|
+
|
|
164
|
+
**Benefits:**
|
|
165
|
+
- Zero data duplication - items are served directly from Microsub
|
|
166
|
+
- Automatic orphan cleanup when feeds are unsubscribed
|
|
167
|
+
- Webhook support for real-time updates
|
|
168
|
+
|
|
169
|
+
## Background Sync
|
|
170
|
+
|
|
171
|
+
The plugin automatically syncs in the background:
|
|
172
|
+
|
|
173
|
+
1. **Initial Sync:** Runs 15 seconds after server startup
|
|
174
|
+
2. **Periodic Sync:** Runs every `syncInterval` milliseconds (default 1 hour)
|
|
175
|
+
3. **What it Does:**
|
|
176
|
+
- Syncs enabled sources (OPML/Microsub)
|
|
177
|
+
- Fetches new items from active blogs
|
|
178
|
+
- Deletes items older than `maxItemAge` days
|
|
179
|
+
- Updates sync statistics
|
|
180
|
+
|
|
181
|
+
**Manual Sync:**
|
|
182
|
+
- Trigger from the dashboard
|
|
183
|
+
- Use `POST /blogrollapi/sync` (protected endpoint)
|
|
184
|
+
- Use `POST /blogrollapi/clear-resync` to clear and resync all
|
|
185
|
+
|
|
186
|
+
## Feed Discovery
|
|
187
|
+
|
|
188
|
+
The plugin includes auto-discovery for finding feeds from website URLs:
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
// In the admin UI, when adding a blog, paste a website URL
|
|
192
|
+
// The plugin will:
|
|
193
|
+
// 1. Check <link rel="alternate"> tags in HTML
|
|
194
|
+
// 2. Try common feed paths (/feed, /rss, /atom.xml, etc.)
|
|
195
|
+
// 3. Suggest discovered feeds
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Item Retention
|
|
199
|
+
|
|
200
|
+
By default, items older than 7 days are automatically deleted during sync. This encourages discovery of fresh content rather than archiving everything.
|
|
201
|
+
|
|
202
|
+
**To Change Retention:**
|
|
203
|
+
```javascript
|
|
204
|
+
new BlogrollEndpoint({
|
|
205
|
+
maxItemAge: 30 // Keep items for 30 days instead
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Blog Status
|
|
210
|
+
|
|
211
|
+
- **active:** Blog is working, fetching items normally
|
|
212
|
+
- **error:** Last fetch failed (see `lastError` for details)
|
|
213
|
+
- **deleted:** Soft-deleted, won't be recreated by sync
|
|
214
|
+
|
|
215
|
+
## Navigation
|
|
216
|
+
|
|
217
|
+
The plugin adds itself to Indiekit's navigation:
|
|
218
|
+
|
|
219
|
+
- **Menu Item:** "Blogroll" (requires database)
|
|
220
|
+
- **Shortcut:** Bookmark icon in admin dashboard
|
|
221
|
+
|
|
222
|
+
## Security
|
|
223
|
+
|
|
224
|
+
- **Protected Routes:** Admin UI and management endpoints require authentication
|
|
225
|
+
- **Public Routes:** Read-only API endpoints are publicly accessible
|
|
226
|
+
- **XSS Prevention:** Feed content is sanitized with `sanitize-html`
|
|
227
|
+
- **Feed Discovery:** Protected to prevent abuse (requires authentication)
|
|
228
|
+
|
|
229
|
+
## Supported Feed Formats
|
|
230
|
+
|
|
231
|
+
- RSS 2.0
|
|
232
|
+
- Atom 1.0
|
|
233
|
+
- JSON Feed 1.0
|
|
234
|
+
|
|
235
|
+
## Contributing
|
|
236
|
+
|
|
237
|
+
Report issues at: https://github.com/rmdes/indiekit-endpoint-blogroll/issues
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT
|
package/locales/de.json
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"blogroll": {
|
|
3
|
+
"title": "Blogroll",
|
|
4
|
+
"description": "Verwalten Sie Ihre Blogroll-Quellen und Blogs",
|
|
5
|
+
"enabled": "Aktiviert",
|
|
6
|
+
"disabled": "Deaktiviert",
|
|
7
|
+
"edit": "Bearbeiten",
|
|
8
|
+
"sync": "Synchronisieren",
|
|
9
|
+
"refresh": "Aktualisieren",
|
|
10
|
+
"cancel": "Abbrechen",
|
|
11
|
+
"never": "Nie",
|
|
12
|
+
|
|
13
|
+
"stats": {
|
|
14
|
+
"title": "Übersicht",
|
|
15
|
+
"sources": "Quellen",
|
|
16
|
+
"blogs": "Blogs",
|
|
17
|
+
"items": "Einträge",
|
|
18
|
+
"errors": "Fehler",
|
|
19
|
+
"lastSync": "Letzte Synchronisation"
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
"actions": {
|
|
23
|
+
"title": "Aktionen",
|
|
24
|
+
"syncNow": "Jetzt synchronisieren",
|
|
25
|
+
"clearResync": "Löschen & Neu synchronisieren",
|
|
26
|
+
"clearConfirm": "Dadurch werden alle zwischengespeicherten Einträge gelöscht und alles neu abgerufen. Fortfahren?"
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
"errors": {
|
|
30
|
+
"title": "Blogs mit Fehlern",
|
|
31
|
+
"seeAll": "Alle %{count} Blogs mit Fehlern anzeigen"
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
"sources": {
|
|
35
|
+
"title": "OPML-Synchronisation",
|
|
36
|
+
"manage": "OPML-Synchronisation",
|
|
37
|
+
"add": "OPML-Quelle hinzufügen",
|
|
38
|
+
"new": "Neue OPML-Quelle",
|
|
39
|
+
"edit": "OPML-Quelle bearbeiten",
|
|
40
|
+
"create": "Erstellen",
|
|
41
|
+
"save": "Speichern",
|
|
42
|
+
"empty": "Keine OPML-Quellen konfiguriert. Verwenden Sie diese Funktion, um Blogs aus FreshRSS oder anderen Feed-Readern zu importieren.",
|
|
43
|
+
"recent": "OPML-Quellen",
|
|
44
|
+
"interval": "Alle %{minutes} Min.",
|
|
45
|
+
"lastSync": "Zuletzt synchronisiert",
|
|
46
|
+
"deleteConfirm": "Diese OPML-Quelle löschen? Importierte Blogs bleiben erhalten.",
|
|
47
|
+
"created": "OPML-Quelle erfolgreich erstellt.",
|
|
48
|
+
"created_synced": "OPML-Quelle erfolgreich erstellt und synchronisiert.",
|
|
49
|
+
"created_sync_failed": "OPML-Quelle erstellt, aber Synchronisation fehlgeschlagen: %{error}",
|
|
50
|
+
"updated": "OPML-Quelle erfolgreich aktualisiert.",
|
|
51
|
+
"deleted": "OPML-Quelle erfolgreich gelöscht.",
|
|
52
|
+
"synced": "Erfolgreich synchronisiert. Hinzugefügt: %{added}, Aktualisiert: %{updated}",
|
|
53
|
+
"form": {
|
|
54
|
+
"name": "Name",
|
|
55
|
+
"type": "Import-Typ",
|
|
56
|
+
"typeHint": "URL synchronisiert regelmäßig, Datei ist ein einmaliger Import",
|
|
57
|
+
"url": "OPML-URL",
|
|
58
|
+
"urlHint": "URL zu Ihrer OPML-Datei (z.B. FreshRSS-Export-URL)",
|
|
59
|
+
"opmlContent": "OPML-Inhalt",
|
|
60
|
+
"opmlContentHint": "Fügen Sie hier den vollständigen OPML-XML-Inhalt ein",
|
|
61
|
+
"syncInterval": "Synchronisationsintervall",
|
|
62
|
+
"enabled": "Automatische Synchronisation aktivieren"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
"blogs": {
|
|
67
|
+
"title": "Blogs",
|
|
68
|
+
"manage": "Blogs verwalten",
|
|
69
|
+
"add": "Blog hinzufügen",
|
|
70
|
+
"new": "Neuer Blog",
|
|
71
|
+
"edit": "Blog bearbeiten",
|
|
72
|
+
"create": "Blog hinzufügen",
|
|
73
|
+
"save": "Blog speichern",
|
|
74
|
+
"empty": "Noch keine Blogs. Fügen Sie einen hinzu oder importieren Sie aus einer OPML-Quelle.",
|
|
75
|
+
"recent": "Aktuelle Blogs",
|
|
76
|
+
"pinned": "Angeheftet",
|
|
77
|
+
"hidden": "Versteckt",
|
|
78
|
+
"noItems": "Noch keine Einträge abgerufen.",
|
|
79
|
+
"recentItems": "Aktuelle Einträge",
|
|
80
|
+
"allCategories": "Alle Kategorien",
|
|
81
|
+
"allStatuses": "Alle Status",
|
|
82
|
+
"statusActive": "Aktiv",
|
|
83
|
+
"statusError": "Fehler",
|
|
84
|
+
"statusPending": "Ausstehend",
|
|
85
|
+
"clearFilters": "Filter löschen",
|
|
86
|
+
"deleteConfirm": "Diesen Blog und alle zwischengespeicherten Einträge löschen?",
|
|
87
|
+
"created": "Blog erfolgreich hinzugefügt.",
|
|
88
|
+
"created_synced": "Blog hinzugefügt und synchronisiert. %{items} Einträge abgerufen.",
|
|
89
|
+
"created_sync_failed": "Blog hinzugefügt, aber erster Abruf fehlgeschlagen: %{error}",
|
|
90
|
+
"updated": "Blog erfolgreich aktualisiert.",
|
|
91
|
+
"deleted": "Blog erfolgreich gelöscht.",
|
|
92
|
+
"refreshed": "Blog aktualisiert. %{items} neue Einträge hinzugefügt.",
|
|
93
|
+
"form": {
|
|
94
|
+
"discoverUrl": "Website-URL",
|
|
95
|
+
"discover": "Feed entdecken",
|
|
96
|
+
"discoverHint": "Geben Sie eine Website-URL ein, um automatisch RSS/Atom-Feeds zu finden",
|
|
97
|
+
"discoverNoUrl": "Bitte geben Sie eine Website-URL ein",
|
|
98
|
+
"discovering": "Suche läuft...",
|
|
99
|
+
"discoveringHint": "Suche nach RSS/Atom-Feeds...",
|
|
100
|
+
"discoverFailed": "Feeds konnten nicht gefunden werden",
|
|
101
|
+
"discoverNoFeeds": "Keine Feeds auf dieser Website gefunden",
|
|
102
|
+
"discoverFoundOne": "Feed gefunden:",
|
|
103
|
+
"discoverFoundMultiple": "Mehrere Feeds gefunden. Klicken Sie auf einen, um ihn auszuwählen:",
|
|
104
|
+
"discoverSelected": "Ausgewählter Feed:",
|
|
105
|
+
"feedUrl": "Feed-URL",
|
|
106
|
+
"feedUrlHint": "RSS-, Atom- oder JSON-Feed-URL",
|
|
107
|
+
"title": "Titel",
|
|
108
|
+
"titlePlaceholder": "Automatisch aus Feed erkannt",
|
|
109
|
+
"titleHint": "Leer lassen, um den Feed-Titel zu verwenden",
|
|
110
|
+
"siteUrl": "Website-URL",
|
|
111
|
+
"siteUrlHint": "Link zur Startseite des Blogs (optional)",
|
|
112
|
+
"category": "Kategorie",
|
|
113
|
+
"categoryHint": "Gruppieren Sie Blogs nach Kategorie zum Filtern und OPML-Export",
|
|
114
|
+
"tags": "Schlagwörter",
|
|
115
|
+
"tagsHint": "Kommagetrennte Schlagwörter für zusätzliche Organisation",
|
|
116
|
+
"notes": "Notizen",
|
|
117
|
+
"notesPlaceholder": "Warum Sie diesem Blog folgen...",
|
|
118
|
+
"notesHint": "Persönliche Notizen (nicht öffentlich sichtbar)",
|
|
119
|
+
"pinned": "Diesen Blog anheften (oben in Listen anzeigen)",
|
|
120
|
+
"hidden": "Vor öffentlicher API verbergen (nur für Sie sichtbar)"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
"api": {
|
|
125
|
+
"title": "API-Endpunkte",
|
|
126
|
+
"blogs": "Alle Blogs mit Metadaten auflisten",
|
|
127
|
+
"items": "Aktuelle Einträge von allen Blogs auflisten",
|
|
128
|
+
"categories": "Alle Kategorien auflisten",
|
|
129
|
+
"opml": "Als OPML exportieren",
|
|
130
|
+
"status": "Synchronisationsstatus und Statistiken"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"blogroll": {
|
|
3
|
+
"title": "Blogroll",
|
|
4
|
+
"description": "Administra tus fuentes de blogroll y blogs",
|
|
5
|
+
"enabled": "Habilitado",
|
|
6
|
+
"disabled": "Deshabilitado",
|
|
7
|
+
"edit": "Editar",
|
|
8
|
+
"sync": "Sincronizar",
|
|
9
|
+
"refresh": "Actualizar",
|
|
10
|
+
"cancel": "Cancelar",
|
|
11
|
+
"never": "Nunca",
|
|
12
|
+
|
|
13
|
+
"stats": {
|
|
14
|
+
"title": "Resumen",
|
|
15
|
+
"sources": "Fuentes",
|
|
16
|
+
"blogs": "Blogs",
|
|
17
|
+
"items": "Entradas",
|
|
18
|
+
"errors": "Errores",
|
|
19
|
+
"lastSync": "Última sincronización"
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
"actions": {
|
|
23
|
+
"title": "Acciones",
|
|
24
|
+
"syncNow": "Sincronizar todo ahora",
|
|
25
|
+
"clearResync": "Limpiar y resincronizar",
|
|
26
|
+
"clearConfirm": "Esto eliminará todas las entradas almacenadas en caché y volverá a descargar todo. ¿Continuar?"
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
"errors": {
|
|
30
|
+
"title": "Blogs con errores",
|
|
31
|
+
"seeAll": "Ver los %{count} blogs con errores"
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
"sources": {
|
|
35
|
+
"title": "Sincronización OPML",
|
|
36
|
+
"manage": "Sincronización OPML",
|
|
37
|
+
"add": "Agregar fuente OPML",
|
|
38
|
+
"new": "Nueva fuente OPML",
|
|
39
|
+
"edit": "Editar fuente OPML",
|
|
40
|
+
"create": "Crear",
|
|
41
|
+
"save": "Guardar",
|
|
42
|
+
"empty": "No hay fuentes OPML configuradas. Usa esto para importar blogs de forma masiva desde FreshRSS u otros lectores de feeds.",
|
|
43
|
+
"recent": "Fuentes OPML",
|
|
44
|
+
"interval": "Cada %{minutes} min",
|
|
45
|
+
"lastSync": "Última sincronización",
|
|
46
|
+
"deleteConfirm": "¿Eliminar esta fuente OPML? Los blogs importados se conservarán.",
|
|
47
|
+
"created": "Fuente OPML creada exitosamente.",
|
|
48
|
+
"created_synced": "Fuente OPML creada y sincronizada exitosamente.",
|
|
49
|
+
"created_sync_failed": "Fuente OPML creada, pero la sincronización falló: %{error}",
|
|
50
|
+
"updated": "Fuente OPML actualizada exitosamente.",
|
|
51
|
+
"deleted": "Fuente OPML eliminada exitosamente.",
|
|
52
|
+
"synced": "Sincronización exitosa. Agregados: %{added}, Actualizados: %{updated}",
|
|
53
|
+
"form": {
|
|
54
|
+
"name": "Nombre",
|
|
55
|
+
"type": "Tipo de importación",
|
|
56
|
+
"typeHint": "La URL sincroniza periódicamente, el archivo es una importación única",
|
|
57
|
+
"url": "URL OPML",
|
|
58
|
+
"urlHint": "URL de tu archivo OPML (ej., URL de exportación de FreshRSS)",
|
|
59
|
+
"opmlContent": "Contenido OPML",
|
|
60
|
+
"opmlContentHint": "Pega aquí el contenido XML OPML completo",
|
|
61
|
+
"syncInterval": "Intervalo de sincronización",
|
|
62
|
+
"enabled": "Habilitar sincronización automática"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
"blogs": {
|
|
67
|
+
"title": "Blogs",
|
|
68
|
+
"manage": "Administrar blogs",
|
|
69
|
+
"add": "Agregar blog",
|
|
70
|
+
"new": "Nuevo blog",
|
|
71
|
+
"edit": "Editar blog",
|
|
72
|
+
"create": "Agregar blog",
|
|
73
|
+
"save": "Guardar blog",
|
|
74
|
+
"empty": "Todavía no hay blogs. Agrega uno o importa desde una fuente OPML.",
|
|
75
|
+
"recent": "Blogs recientes",
|
|
76
|
+
"pinned": "Fijado",
|
|
77
|
+
"hidden": "Oculto",
|
|
78
|
+
"noItems": "Aún no se descargaron entradas.",
|
|
79
|
+
"recentItems": "Entradas recientes",
|
|
80
|
+
"allCategories": "Todas las categorías",
|
|
81
|
+
"allStatuses": "Todos los estados",
|
|
82
|
+
"statusActive": "Activo",
|
|
83
|
+
"statusError": "Error",
|
|
84
|
+
"statusPending": "Pendiente",
|
|
85
|
+
"clearFilters": "Limpiar filtros",
|
|
86
|
+
"deleteConfirm": "¿Eliminar este blog y todas sus entradas almacenadas?",
|
|
87
|
+
"created": "Blog agregado exitosamente.",
|
|
88
|
+
"created_synced": "Blog agregado y sincronizado. Se descargaron %{items} entradas.",
|
|
89
|
+
"created_sync_failed": "Blog agregado, pero la descarga inicial falló: %{error}",
|
|
90
|
+
"updated": "Blog actualizado exitosamente.",
|
|
91
|
+
"deleted": "Blog eliminado exitosamente.",
|
|
92
|
+
"refreshed": "Blog actualizado. Se agregaron %{items} entradas nuevas.",
|
|
93
|
+
"form": {
|
|
94
|
+
"discoverUrl": "URL del sitio web",
|
|
95
|
+
"discover": "Descubrir feed",
|
|
96
|
+
"discoverHint": "Ingresa una URL de sitio web para descubrir automáticamente su feed RSS/Atom",
|
|
97
|
+
"discoverNoUrl": "Por favor ingresa una URL de sitio web",
|
|
98
|
+
"discovering": "Descubriendo...",
|
|
99
|
+
"discoveringHint": "Buscando feeds RSS/Atom...",
|
|
100
|
+
"discoverFailed": "No se pudieron descubrir feeds",
|
|
101
|
+
"discoverNoFeeds": "No se encontraron feeds en este sitio web",
|
|
102
|
+
"discoverFoundOne": "Feed encontrado:",
|
|
103
|
+
"discoverFoundMultiple": "Se encontraron varios feeds. Hace clic en uno para seleccionarlo:",
|
|
104
|
+
"discoverSelected": "Feed seleccionado:",
|
|
105
|
+
"feedUrl": "URL del feed",
|
|
106
|
+
"feedUrlHint": "URL de RSS, Atom o JSON Feed",
|
|
107
|
+
"title": "Título",
|
|
108
|
+
"titlePlaceholder": "Detectado automáticamente del feed",
|
|
109
|
+
"titleHint": "Dejar en blanco para usar el título del feed",
|
|
110
|
+
"siteUrl": "URL del sitio",
|
|
111
|
+
"siteUrlHint": "Enlace a la página principal del blog (opcional)",
|
|
112
|
+
"category": "Categoría",
|
|
113
|
+
"categoryHint": "Agrupa blogs por categoría para filtrar y exportar a OPML",
|
|
114
|
+
"tags": "Etiquetas",
|
|
115
|
+
"tagsHint": "Etiquetas separadas por comas para organización adicional",
|
|
116
|
+
"notes": "Notas",
|
|
117
|
+
"notesPlaceholder": "Por qué sigues este blog...",
|
|
118
|
+
"notesHint": "Notas personales (no se muestran públicamente)",
|
|
119
|
+
"pinned": "Fijar este blog (mostrar al inicio de las listas)",
|
|
120
|
+
"hidden": "Ocultar de la API pública (visible solo para vos)"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
"api": {
|
|
125
|
+
"title": "Endpoints de la API",
|
|
126
|
+
"blogs": "Listar todos los blogs con metadatos",
|
|
127
|
+
"items": "Listar entradas recientes de todos los blogs",
|
|
128
|
+
"categories": "Listar todas las categorías",
|
|
129
|
+
"opml": "Exportar como OPML",
|
|
130
|
+
"status": "Estado de sincronización y estadísticas"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
package/locales/es.json
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"blogroll": {
|
|
3
|
+
"title": "Blogroll",
|
|
4
|
+
"description": "Gestiona tus fuentes de blogroll y blogs",
|
|
5
|
+
"enabled": "Activado",
|
|
6
|
+
"disabled": "Desactivado",
|
|
7
|
+
"edit": "Editar",
|
|
8
|
+
"sync": "Sincronizar",
|
|
9
|
+
"refresh": "Actualizar",
|
|
10
|
+
"cancel": "Cancelar",
|
|
11
|
+
"never": "Nunca",
|
|
12
|
+
|
|
13
|
+
"stats": {
|
|
14
|
+
"title": "Resumen",
|
|
15
|
+
"sources": "Fuentes",
|
|
16
|
+
"blogs": "Blogs",
|
|
17
|
+
"items": "Entradas",
|
|
18
|
+
"errors": "Errores",
|
|
19
|
+
"lastSync": "Última sincronización"
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
"actions": {
|
|
23
|
+
"title": "Acciones",
|
|
24
|
+
"syncNow": "Sincronizar todo ahora",
|
|
25
|
+
"clearResync": "Borrar y resincronizar",
|
|
26
|
+
"clearConfirm": "Esto eliminará todas las entradas almacenadas en caché y volverá a obtenerlo todo. ¿Continuar?"
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
"errors": {
|
|
30
|
+
"title": "Blogs con errores",
|
|
31
|
+
"seeAll": "Ver todos los %{count} blogs con errores"
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
"sources": {
|
|
35
|
+
"title": "Sincronización OPML",
|
|
36
|
+
"manage": "Sincronización OPML",
|
|
37
|
+
"add": "Añadir fuente OPML",
|
|
38
|
+
"new": "Nueva fuente OPML",
|
|
39
|
+
"edit": "Editar fuente OPML",
|
|
40
|
+
"create": "Crear",
|
|
41
|
+
"save": "Guardar",
|
|
42
|
+
"empty": "No hay fuentes OPML configuradas. Utiliza esto para importar blogs en bloque desde FreshRSS u otros lectores de feeds.",
|
|
43
|
+
"recent": "Fuentes OPML",
|
|
44
|
+
"interval": "Cada %{minutes} min",
|
|
45
|
+
"lastSync": "Última sincronización",
|
|
46
|
+
"deleteConfirm": "¿Eliminar esta fuente OPML? Los blogs importados se conservarán.",
|
|
47
|
+
"created": "Fuente OPML creada correctamente.",
|
|
48
|
+
"created_synced": "Fuente OPML creada y sincronizada correctamente.",
|
|
49
|
+
"created_sync_failed": "Fuente OPML creada, pero la sincronización falló: %{error}",
|
|
50
|
+
"updated": "Fuente OPML actualizada correctamente.",
|
|
51
|
+
"deleted": "Fuente OPML eliminada correctamente.",
|
|
52
|
+
"synced": "Sincronización exitosa. Añadidos: %{added}, Actualizados: %{updated}",
|
|
53
|
+
"form": {
|
|
54
|
+
"name": "Nombre",
|
|
55
|
+
"type": "Tipo de importación",
|
|
56
|
+
"typeHint": "La URL sincroniza periódicamente, el archivo es una importación única",
|
|
57
|
+
"url": "URL OPML",
|
|
58
|
+
"urlHint": "URL de tu archivo OPML (p. ej., URL de exportación de FreshRSS)",
|
|
59
|
+
"opmlContent": "Contenido OPML",
|
|
60
|
+
"opmlContentHint": "Pega aquí el contenido XML OPML completo",
|
|
61
|
+
"syncInterval": "Intervalo de sincronización",
|
|
62
|
+
"enabled": "Activar sincronización automática"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
"blogs": {
|
|
67
|
+
"title": "Blogs",
|
|
68
|
+
"manage": "Gestionar blogs",
|
|
69
|
+
"add": "Añadir blog",
|
|
70
|
+
"new": "Nuevo blog",
|
|
71
|
+
"edit": "Editar blog",
|
|
72
|
+
"create": "Añadir blog",
|
|
73
|
+
"save": "Guardar blog",
|
|
74
|
+
"empty": "Todavía no hay blogs. Añade uno o impórtalo desde una fuente OPML.",
|
|
75
|
+
"recent": "Blogs recientes",
|
|
76
|
+
"pinned": "Fijado",
|
|
77
|
+
"hidden": "Oculto",
|
|
78
|
+
"noItems": "Aún no se han obtenido entradas.",
|
|
79
|
+
"recentItems": "Entradas recientes",
|
|
80
|
+
"allCategories": "Todas las categorías",
|
|
81
|
+
"allStatuses": "Todos los estados",
|
|
82
|
+
"statusActive": "Activo",
|
|
83
|
+
"statusError": "Error",
|
|
84
|
+
"statusPending": "Pendiente",
|
|
85
|
+
"clearFilters": "Limpiar filtros",
|
|
86
|
+
"deleteConfirm": "¿Eliminar este blog y todas sus entradas almacenadas?",
|
|
87
|
+
"created": "Blog añadido correctamente.",
|
|
88
|
+
"created_synced": "Blog añadido y sincronizado. Se obtuvieron %{items} entradas.",
|
|
89
|
+
"created_sync_failed": "Blog añadido, pero la obtención inicial falló: %{error}",
|
|
90
|
+
"updated": "Blog actualizado correctamente.",
|
|
91
|
+
"deleted": "Blog eliminado correctamente.",
|
|
92
|
+
"refreshed": "Blog actualizado. Se añadieron %{items} entradas nuevas.",
|
|
93
|
+
"form": {
|
|
94
|
+
"discoverUrl": "URL del sitio web",
|
|
95
|
+
"discover": "Descubrir feed",
|
|
96
|
+
"discoverHint": "Introduce una URL de sitio web para descubrir automáticamente su feed RSS/Atom",
|
|
97
|
+
"discoverNoUrl": "Por favor, introduce una URL de sitio web",
|
|
98
|
+
"discovering": "Descubriendo...",
|
|
99
|
+
"discoveringHint": "Buscando feeds RSS/Atom...",
|
|
100
|
+
"discoverFailed": "No se pudieron descubrir feeds",
|
|
101
|
+
"discoverNoFeeds": "No se encontraron feeds en este sitio web",
|
|
102
|
+
"discoverFoundOne": "Feed encontrado:",
|
|
103
|
+
"discoverFoundMultiple": "Se encontraron varios feeds. Haz clic en uno para seleccionarlo:",
|
|
104
|
+
"discoverSelected": "Feed seleccionado:",
|
|
105
|
+
"feedUrl": "URL del feed",
|
|
106
|
+
"feedUrlHint": "URL de RSS, Atom o JSON Feed",
|
|
107
|
+
"title": "Título",
|
|
108
|
+
"titlePlaceholder": "Detectado automáticamente del feed",
|
|
109
|
+
"titleHint": "Dejar en blanco para usar el título del feed",
|
|
110
|
+
"siteUrl": "URL del sitio",
|
|
111
|
+
"siteUrlHint": "Enlace a la página principal del blog (opcional)",
|
|
112
|
+
"category": "Categoría",
|
|
113
|
+
"categoryHint": "Agrupa blogs por categoría para filtrar y exportar a OPML",
|
|
114
|
+
"tags": "Etiquetas",
|
|
115
|
+
"tagsHint": "Etiquetas separadas por comas para organización adicional",
|
|
116
|
+
"notes": "Notas",
|
|
117
|
+
"notesPlaceholder": "Por qué sigues este blog...",
|
|
118
|
+
"notesHint": "Notas personales (no se muestran públicamente)",
|
|
119
|
+
"pinned": "Fijar este blog (mostrar en la parte superior de las listas)",
|
|
120
|
+
"hidden": "Ocultar de la API pública (visible solo para ti)"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
"api": {
|
|
125
|
+
"title": "Puntos de acceso de la API",
|
|
126
|
+
"blogs": "Listar todos los blogs con metadatos",
|
|
127
|
+
"items": "Listar entradas recientes de todos los blogs",
|
|
128
|
+
"categories": "Listar todas las categorías",
|
|
129
|
+
"opml": "Exportar como OPML",
|
|
130
|
+
"status": "Estado de sincronización y estadísticas"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|