forked from
smokesignal.events/smokesignal
i18n+filtering fork - fluent-templates v2
1openapi: 3.0.3
2info:
3 title: smokesignal API
4 description: |
5 Event and RSVP management system with comprehensive internationalization support.
6
7 ## I18n Features
8
9 smokesignal provides full internationalization support with automatic language detection
10 and locale-aware responses. All endpoints support multiple languages through:
11
12 - **Accept-Language headers**: Standard HTTP language negotiation
13 - **URL parameters**: `?lang=fr-ca` for explicit language selection
14 - **Locale-aware caching**: Optimized performance with language-specific cache keys
15 - **Translated content**: All user-facing content available in supported locales
16
17 ## Supported Locales
18
19 - `en-US`: English (United States) - Default
20 - `fr-CA`: French (Canada) with gender-aware content
21
22 ## Language Detection Priority
23
24 1. URL `lang` parameter
25 2. Accept-Language header
26 3. Session preference
27 4. Default locale (en-US)
28
29 version: 1.0.0
30 contact:
31 name: smokesignal Support
32 url: https://github.com/yourusername/smokesignal
33 license:
34 name: MIT
35 url: https://opensource.org/licenses/MIT
36
37servers:
38 - url: https://api.smokesignal.example.com
39 description: Production server
40 - url: http://localhost:3000
41 description: Development server
42
43paths:
44 /events:
45 get:
46 summary: Filter and search events
47 description: |
48 Retrieve events based on filter criteria with full internationalization support.
49
50 Facets and event metadata are automatically translated based on the user's
51 language preference. Cache keys include locale information for optimal performance.
52
53 ## I18n Behavior
54
55 - Event status and format facets are translated
56 - Date range facets use locale-appropriate formatting
57 - Facet counts include proper pluralization
58 - Error messages are localized
59
60 parameters:
61 - name: Accept-Language
62 in: header
63 description: |
64 Language preference using standard HTTP Accept-Language header.
65
66 Examples:
67 - `en-US,en;q=0.9` - English preferred
68 - `fr-CA,fr;q=0.9,en;q=0.8` - French Canadian preferred, French secondary, English fallback
69 - `fr-CA` - French Canadian only
70
71 schema:
72 type: string
73 example: "fr-CA,fr;q=0.9,en;q=0.8"
74
75 - name: lang
76 in: query
77 description: |
78 Explicit language override. Takes priority over Accept-Language header.
79
80 Supported values:
81 - `en-us`: English (United States)
82 - `fr-ca`: French (Canada)
83
84 schema:
85 type: string
86 enum: [en-us, fr-ca]
87 example: "fr-ca"
88
89 - name: q
90 in: query
91 description: Search term for event title and description
92 schema:
93 type: string
94 example: "music festival"
95
96 - name: start_date
97 in: query
98 description: Filter events starting after this date (ISO 8601)
99 schema:
100 type: string
101 format: date
102 example: "2025-06-01"
103
104 - name: end_date
105 in: query
106 description: Filter events ending before this date (ISO 8601)
107 schema:
108 type: string
109 format: date
110 example: "2025-12-31"
111
112 - name: lat
113 in: query
114 description: Latitude for location-based filtering
115 schema:
116 type: number
117 format: float
118 example: 45.5017
119
120 - name: lng
121 in: query
122 description: Longitude for location-based filtering
123 schema:
124 type: number
125 format: float
126 example: -73.5673
127
128 - name: radius
129 in: query
130 description: Search radius in kilometers (requires lat/lng)
131 schema:
132 type: number
133 format: float
134 minimum: 0
135 maximum: 1000
136 example: 25
137
138 - name: modes
139 in: query
140 description: Filter by event format/mode
141 schema:
142 type: array
143 items:
144 type: string
145 enum: [in_person, virtual, hybrid]
146 example: ["in_person", "hybrid"]
147
148 - name: statuses
149 in: query
150 description: Filter by event status
151 schema:
152 type: array
153 items:
154 type: string
155 enum: [active, draft, cancelled]
156 example: ["active"]
157
158 - name: sort
159 in: query
160 description: Sort order for results
161 schema:
162 type: string
163 enum: [start_time, created_at, updated_at, relevance]
164 default: start_time
165 example: "start_time"
166
167 - name: limit
168 in: query
169 description: Maximum number of events to return
170 schema:
171 type: integer
172 minimum: 1
173 maximum: 100
174 default: 20
175 example: 20
176
177 - name: offset
178 in: query
179 description: Number of events to skip (for pagination)
180 schema:
181 type: integer
182 minimum: 0
183 default: 0
184 example: 0
185
186 responses:
187 '200':
188 description: Successful response with filtered events and facets
189 headers:
190 Content-Language:
191 description: Language of the returned content
192 schema:
193 type: string
194 example: "fr-CA"
195 X-Cache-Key:
196 description: Cache key used (includes locale)
197 schema:
198 type: string
199 example: "filter:abc123:fr-ca"
200
201 content:
202 application/json:
203 schema:
204 $ref: '#/components/schemas/FilterResults'
205 examples:
206 english_results:
207 summary: English response
208 value:
209 events:
210 - id: "evt_123"
211 title: "Summer Music Festival"
212 description: "Annual outdoor music festival"
213 start_date: "2025-07-15T19:00:00Z"
214 mode: "in_person"
215 status: "active"
216 facets:
217 modes:
218 - value: "in_person"
219 count: 25
220 i18n_key: "event-mode-in-person"
221 display_name: "In Person"
222 statuses:
223 - value: "active"
224 count: 25
225 i18n_key: "event-status-active"
226 display_name: "Active"
227 total_count: 25
228
229 french_results:
230 summary: French Canadian response
231 value:
232 events:
233 - id: "evt_123"
234 title: "Summer Music Festival"
235 description: "Annual outdoor music festival"
236 start_date: "2025-07-15T19:00:00Z"
237 mode: "in_person"
238 status: "active"
239 facets:
240 modes:
241 - value: "in_person"
242 count: 25
243 i18n_key: "event-mode-in-person"
244 display_name: "En personne"
245 statuses:
246 - value: "active"
247 count: 25
248 i18n_key: "event-status-active"
249 display_name: "Actif"
250 total_count: 25
251
252 text/html:
253 schema:
254 type: string
255 description: Rendered HTML template with translated content
256 examples:
257 htmx_fragment:
258 summary: HTMX partial response
259 value: |
260 <div id="event-results">
261 <h2>25 événements trouvés</h2>
262 <!-- Translated content -->
263 </div>
264
265 '400':
266 description: Bad request - Invalid parameters
267 content:
268 application/json:
269 schema:
270 $ref: '#/components/schemas/Error'
271 examples:
272 invalid_locale:
273 summary: Invalid locale parameter
274 value:
275 error: "invalid_locale"
276 message: "Unsupported locale 'es-ES'. Supported locales: en-us, fr-ca"
277 details:
278 supported_locales: ["en-us", "fr-ca"]
279
280 '500':
281 description: Internal server error
282 content:
283 application/json:
284 schema:
285 $ref: '#/components/schemas/Error'
286
287 /events/{id}:
288 get:
289 summary: Get event details
290 description: |
291 Retrieve detailed information for a specific event with localized content.
292
293 ## I18n Features
294
295 - Event metadata translated based on user language
296 - Date/time formatting according to locale conventions
297 - RSVP status and form labels localized
298
299 parameters:
300 - name: id
301 in: path
302 required: true
303 description: Event ID
304 schema:
305 type: string
306 example: "evt_123"
307
308 - name: Accept-Language
309 in: header
310 description: Language preference
311 schema:
312 type: string
313 example: "fr-CA,fr;q=0.9,en;q=0.8"
314
315 - name: lang
316 in: query
317 description: Explicit language override
318 schema:
319 type: string
320 enum: [en-us, fr-ca]
321
322 responses:
323 '200':
324 description: Event details
325 content:
326 application/json:
327 schema:
328 $ref: '#/components/schemas/Event'
329 text/html:
330 schema:
331 type: string
332 description: Rendered event detail page
333
334 '404':
335 description: Event not found
336 content:
337 application/json:
338 schema:
339 $ref: '#/components/schemas/Error'
340
341 /facets:
342 get:
343 summary: Get available facets for filtering
344 description: |
345 Retrieve facet counts for the current filter context with translated display names.
346
347 This endpoint is optimized for autocomplete and filter UI updates. Facets include
348 pre-calculated display names in the user's preferred language.
349
350 parameters:
351 - name: Accept-Language
352 in: header
353 description: Language preference for facet translations
354 schema:
355 type: string
356 example: "fr-CA"
357
358 - name: context
359 in: query
360 description: Current filter context to calculate facets against
361 schema:
362 type: string
363 example: "search=music&location=montreal"
364
365 responses:
366 '200':
367 description: Available facets with counts and translations
368 content:
369 application/json:
370 schema:
371 $ref: '#/components/schemas/EventFacets'
372
373 /health/translations:
374 get:
375 summary: Health check for translation system
376 description: |
377 Verify that translation system is working correctly for all supported locales.
378
379 Returns status of translation loading, cache connectivity, and sample translations.
380
381 responses:
382 '200':
383 description: Translation system healthy
384 content:
385 application/json:
386 schema:
387 type: object
388 properties:
389 status:
390 type: string
391 example: "healthy"
392 locales:
393 type: array
394 items:
395 type: object
396 properties:
397 locale:
398 type: string
399 loaded:
400 type: boolean
401 translation_count:
402 type: integer
403 example:
404 - locale: "en-us"
405 loaded: true
406 translation_count: 245
407 - locale: "fr-ca"
408 loaded: true
409 translation_count: 243
410 cache:
411 type: object
412 properties:
413 connected:
414 type: boolean
415 hit_rate:
416 type: number
417
418components:
419 schemas:
420 FilterResults:
421 type: object
422 properties:
423 events:
424 type: array
425 items:
426 $ref: '#/components/schemas/Event'
427 facets:
428 $ref: '#/components/schemas/EventFacets'
429 total_count:
430 type: integer
431 description: Total number of events matching criteria
432
433 Event:
434 type: object
435 properties:
436 id:
437 type: string
438 description: Unique event identifier
439 title:
440 type: string
441 description: Event title
442 description:
443 type: string
444 description: Event description
445 start_date:
446 type: string
447 format: date-time
448 description: Event start date and time (ISO 8601)
449 end_date:
450 type: string
451 format: date-time
452 description: Event end date and time (ISO 8601)
453 mode:
454 type: string
455 enum: [in_person, virtual, hybrid]
456 description: Event format/mode
457 status:
458 type: string
459 enum: [active, draft, cancelled]
460 description: Event status
461 location:
462 $ref: '#/components/schemas/Location'
463 created_at:
464 type: string
465 format: date-time
466 updated_at:
467 type: string
468 format: date-time
469
470 EventFacets:
471 type: object
472 description: Available facets for filtering with translated display names
473 properties:
474 modes:
475 type: array
476 items:
477 $ref: '#/components/schemas/FacetValue'
478 description: Event format facets
479 statuses:
480 type: array
481 items:
482 $ref: '#/components/schemas/FacetValue'
483 description: Event status facets
484 date_ranges:
485 type: array
486 items:
487 $ref: '#/components/schemas/FacetValue'
488 description: Date range facets (Today, This Week, etc.)
489 creators:
490 type: array
491 items:
492 $ref: '#/components/schemas/FacetValue'
493 description: Event creator facets
494 total_count:
495 type: integer
496 description: Total events matching current criteria
497
498 FacetValue:
499 type: object
500 description: A single facet value with count and i18n support
501 properties:
502 value:
503 type: string
504 description: The actual filter value (e.g., "in_person")
505 example: "in_person"
506 count:
507 type: integer
508 description: Number of events matching this facet
509 example: 15
510 i18n_key:
511 type: string
512 description: Translation key for the display name
513 example: "event-mode-in-person"
514 display_name:
515 type: string
516 description: Pre-calculated display name in user's locale
517 example: "En personne"
518
519 Location:
520 type: object
521 properties:
522 latitude:
523 type: number
524 format: float
525 longitude:
526 type: number
527 format: float
528 address:
529 type: string
530 city:
531 type: string
532 country:
533 type: string
534
535 Error:
536 type: object
537 properties:
538 error:
539 type: string
540 description: Error code
541 message:
542 type: string
543 description: Human-readable error message (localized)
544 details:
545 type: object
546 description: Additional error context
547 required:
548 - error
549 - message
550
551 securitySchemes:
552 BearerAuth:
553 type: http
554 scheme: bearer
555 description: JWT token authentication
556
557security:
558 - BearerAuth: []
559
560tags:
561 - name: Events
562 description: Event management and filtering
563 - name: I18n
564 description: Internationalization and localization
565 - name: Health
566 description: System health and status checks