i18n+filtering fork - fluent-templates v2
at main 566 lines 17 kB view raw
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