miki-template 2.0.1 → 2.2.2

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.
Files changed (71) hide show
  1. package/.github/workflows/ci.yml +13 -37
  2. package/.github/workflows/docs.yml +105 -0
  3. package/.github/workflows/npm-publish-github-packages.yml +36 -0
  4. package/README.md +69 -14
  5. package/assets/logo.png +0 -0
  6. package/benchmarks/ejs-results.json +4 -4
  7. package/benchmarks/handlebars-results.json +6 -6
  8. package/benchmarks/miki-results.json +4 -4
  9. package/benchmarks/pug-results.json +4 -4
  10. package/benchmarks/stress.mjs +1 -1
  11. package/docs/api/async-render.md +85 -0
  12. package/docs/api/cache.md +87 -0
  13. package/docs/api/compile.md +128 -0
  14. package/docs/api/context-processors.md +77 -0
  15. package/docs/api/filters.md +217 -0
  16. package/docs/api/finder.md +94 -0
  17. package/docs/api/helpers.md +53 -0
  18. package/docs/api/i18n.md +157 -0
  19. package/docs/api/index.md +54 -0
  20. package/docs/api/libraries.md +207 -0
  21. package/docs/api/render-partial.md +81 -0
  22. package/docs/api/render.md +92 -0
  23. package/docs/api/security.md +145 -0
  24. package/docs/api/setup-express.md +76 -0
  25. package/docs/api/tags.md +134 -0
  26. package/docs/assets/banner.png +0 -0
  27. package/docs/assets/logo.png +0 -0
  28. package/docs/guide/advanced-usage.md +397 -0
  29. package/docs/guide/async-rendering.md +308 -0
  30. package/docs/guide/context-processors.md +257 -0
  31. package/docs/guide/custom-filters.md +311 -0
  32. package/docs/guide/custom-tags.md +271 -0
  33. package/docs/guide/filters.md +642 -0
  34. package/docs/guide/getting-started.md +102 -0
  35. package/docs/guide/installation.md +95 -0
  36. package/docs/guide/partial-templates.md +367 -0
  37. package/docs/guide/quick-start.md +222 -0
  38. package/docs/guide/security.md +345 -0
  39. package/docs/guide/tags.md +783 -0
  40. package/docs/guide/template-discovery.md +170 -0
  41. package/docs/guide/template-inheritance.md +273 -0
  42. package/docs/guide/what-is-miki-template.md +28 -0
  43. package/docs/guide/why-miki-template.md +75 -0
  44. package/docs/index.md +104 -0
  45. package/docs/integrations/elysia.md +78 -0
  46. package/docs/integrations/express.md +219 -0
  47. package/docs/integrations/fastify.md +77 -0
  48. package/docs/integrations/hono.md +78 -0
  49. package/docs/integrations/index.md +68 -0
  50. package/docs/integrations/koa.md +88 -0
  51. package/docs/integrations/nestjs.md +78 -0
  52. package/docs/integrations/tsed.md +81 -0
  53. package/docs/javascripts/extra.js +174 -0
  54. package/docs/performance.md +37 -0
  55. package/docs/stylesheets/extra.css +819 -0
  56. package/mkdocs.yml +217 -0
  57. package/overrides/main.html +26 -0
  58. package/overrides/partials/footer.html +9 -0
  59. package/package.json +4 -2
  60. package/requirements-docs.txt +1 -0
  61. package/docs/README.md +0 -18
  62. package/docs/advanced_usage.md +0 -71
  63. package/docs/api.md +0 -122
  64. package/docs/filters.md +0 -708
  65. package/docs/installation.md +0 -106
  66. package/docs/integrations.md +0 -214
  67. package/docs/overview.md +0 -79
  68. package/docs/partialdef.md +0 -70
  69. package/docs/security.md +0 -27
  70. package/docs/tags.md +0 -673
  71. package/docs/usage.md +0 -646
package/docs/filters.md DELETED
@@ -1,708 +0,0 @@
1
- # Filters Reference
2
-
3
- `miki-template` includes a comprehensive set of built-in filters matching Django's filter library. Filters are applied to variables using the pipe `|` character, and can be chained: `{{ value|filter1|filter2:"arg" }}`.
4
-
5
- ---
6
-
7
- ## Filter Chaining
8
-
9
- Filters can be chained — the output of each filter becomes the input of the next:
10
-
11
- ```html
12
- {{ name|lower|capfirst }}
13
- <!-- "miki" → "miki" → "Miki" -->
14
-
15
- {{ user.bio|striptags|truncatewords:20 }}
16
- <!-- Strip HTML tags, then truncate to 20 words -->
17
- ```
18
-
19
- ---
20
-
21
- ## Text Filters
22
-
23
- ### `upper`
24
- Converts a string to UPPERCASE.
25
- ```html
26
- {{ "hello"|upper }} → "HELLO"
27
- {{ name|upper }} → "JOHN"
28
- ```
29
-
30
- ### `lower`
31
- Converts a string to lowercase.
32
- ```html
33
- {{ "HELLO"|lower }} → "hello"
34
- ```
35
-
36
- ### `title`
37
- Converts to Title Case (first letter of each word capitalized).
38
- ```html
39
- {{ "hello world"|title }} → "Hello World"
40
- ```
41
-
42
- ### `capfirst`
43
- Capitalizes only the first character.
44
- ```html
45
- {{ "hello"|capfirst }} → "Hello"
46
- {{ "h"|capfirst }} → "H"
47
- ```
48
-
49
- ### `slugify`
50
- Converts to a URL-safe slug by lowercasing, removing accents, and replacing spaces with hyphens.
51
- ```html
52
- {{ "Hello World!"|slugify }} → "hello-world"
53
- {{ "Café con Leche"|slugify }} → "cafe-con-leche"
54
- {{ " Multiple Spaces "|slugify }} → "multiple-spaces"
55
- ```
56
-
57
- ### `wordcount`
58
- Returns the number of words (whitespace-separated tokens).
59
- ```html
60
- {{ "one two three"|wordcount }} → 3
61
- {{ " "|wordcount }} → 0
62
- ```
63
-
64
- ### `truncatewords:N`
65
- Truncates the string to approximately N words, appending `...`.
66
- ```html
67
- {{ "one two three four five"|truncatewords:3 }} → "one two three ..."
68
- ```
69
-
70
- ### `truncatechars:N`
71
- Truncates to N characters (including the `...` suffix if truncation occurs).
72
- ```html
73
- {{ "Hello World"|truncatechars:8 }} → "Hello..."
74
- {{ "Hi"|truncatechars:5 }} → "Hi" (no truncation needed)
75
- ```
76
-
77
- ### `truncatechars_html:N`
78
- Like `truncatechars` but respects HTML tags — tags are preserved in full and only visible text counts toward the limit.
79
- ```html
80
- {{ "<p>Hello world</p>"|truncatechars_html:10 }} → "<p>Hello worl...</p>"
81
- ```
82
-
83
- ### `linebreaks`
84
- Converts newlines into paragraphs (`<p>`) and standalone line breaks into `<br>`.
85
- ```html
86
- {{ "Line one\n\nLine two\nLine three"|linebreaks }}
87
- <!-- Output: <p>Line one</p><p>Line two<br>Line three</p> -->
88
- ```
89
-
90
- ### `linebreaksbr`
91
- Converts all newlines to `<br>` tags. Does **not** wrap in `<p>` tags.
92
- ```html
93
- {{ "Line one\nLine two"|linebreaksbr }}
94
- <!-- Output: Line one<br>Line two -->
95
- ```
96
-
97
- ### `urlize`
98
- Automatically converts URLs in text into clickable `<a>` links.
99
- ```html
100
- {{ "visit https://example.com for more"|urlize }}
101
- <!-- Output: visit <a href="https://example.com">https://example.com</a> for more -->
102
- ```
103
-
104
- ### `cut:value`
105
- Removes all occurrences of the specified value from the string.
106
- ```html
107
- {{ "Hello World"|cut:" " }} → "HelloWorld"
108
- {{ "a|b|c"|cut:"|" }} → "abc"
109
- ```
110
-
111
- ### `addslashes`
112
- Adds backslashes before single quotes, double quotes, and backslashes.
113
- ```html
114
- {{ 'He said "Hello"'|addslashes }} → 'He said \"Hello\"'
115
- ```
116
-
117
- ### `removetags:tag1,tag2,...`
118
- Removes the named HTML tags (and their contents).
119
- ```html
120
- {{ "<p>Hello</p><b>World</b>"|removetags:"p,b" }} → "HelloWorld"
121
- ```
122
-
123
- ### `reverse`
124
- Reverses a string or array.
125
- ```html
126
- {{ "hello"|reverse }} → "olleh"
127
- {{ items|reverse }} → [3, 2, 1]
128
- ```
129
-
130
- ### `split:separator`
131
- Splits a string into an array. Default separator is a single space.
132
- ```html
133
- {{ "a,b,c"|split:"," }} → ["a", "b", "c"]
134
- {{ "hello world"|split }} → ["hello", "world"]
135
- ```
136
-
137
- ### `replace:old,new`
138
- Replaces occurrences of `old` with `new` in the string.
139
- ```html
140
- {{ "hello world"|replace:"world,Earth" }} → "hello Earth"
141
- ```
142
-
143
- ### `length_is:N`
144
- Returns `true` if the value's length equals N, otherwise `false`.
145
- ```html
146
- {{ "hello"|length_is:5 }} → true
147
- {{ items|length_is:3 }} → true/false
148
- ```
149
-
150
- ---
151
-
152
- ## HTML / Security Filters
153
-
154
- ### `safe`
155
- Marks the value as **HTML-safe**, bypassing auto-escaping. Use with caution — never pass unsanitized user input through `|safe`.
156
- ```html
157
- {{ "<b>Bold</b>"|safe }} → <b>Bold</b> (NOT &lt;b&gt;Bold&lt;/b&gt;)
158
- ```
159
-
160
- ### `escape`
161
- Explicitly escapes HTML entities. Useful when `autoescape` is `off`.
162
- ```html
163
- {% autoescape off %}
164
- {{ user_input|escape }} → &lt;script&gt;alert()&lt;/script&gt;
165
- {% endautoescape %}
166
- ```
167
-
168
- ---
169
-
170
- ## URL / Encoding Filters
171
-
172
- ### `urlencode`
173
- URL-encodes the string. By default, uses query-string encoding (spaces → `+`).
174
- ```html
175
- {{ "Hello World"|urlencode }} → "Hello+World"
176
- {{ "a/b c"|urlencode }} → "a%2Fb+c"
177
- ```
178
-
179
- ### `escapeuri`
180
- Percent-encodes all special characters in a URI.
181
- ```html
182
- {{ "https://example.com?q=hello world"|escapeuri }}
183
- → "https%3A%2F%2Fexample.com%3Fq%3Dhello%20world"
184
- ```
185
-
186
- ### `base64_encode`
187
- Encodes a string to Base64.
188
- ```html
189
- {{ "hello"|base64_encode }} → "aGVsbG8="
190
- ```
191
-
192
- ### `base64_decode`
193
- Decodes a Base64 string. Returns the original value if decoding fails or produces invalid UTF-8.
194
- ```html
195
- {{ "aGVsbG8="|base64_decode }} → "hello"
196
- ```
197
-
198
- ---
199
-
200
- ## String Formatting Filters
201
-
202
- ### `stringformat:"fmt"`
203
- Formats the value using Python-style format strings (`%s`, `%d`, etc.).
204
- ```html
205
- {{ 42|stringformat:"d" }} → "42"
206
- {{ 3.14159|stringformat:".2f" }} → "3.14"
207
- {{ "x"|stringformat:"s" }} → "x"
208
- ```
209
-
210
- ### `json`
211
- Safely serializes a value to JSON, marked safe for use inside `<script>` blocks.
212
- ```html
213
- {{ data|json }}
214
- <!-- Output: {"users":[{"name":"Alice"}]} (not HTML-escaped) -->
215
- ```
216
-
217
- ---
218
-
219
- ## List / Sequence Filters
220
-
221
- ### `length`
222
- Returns the length of an array, object, string, or any object with a `.length` property.
223
- ```html
224
- {{ items|length }} → 5 (for arrays)
225
- {{ "hello"|length }} → 5
226
- {{ object|length }} → number of keys
227
- {{ undefined|length }} → 0
228
- ```
229
-
230
- ### `join:separator`
231
- Joins an array with the specified separator.
232
- ```html
233
- {{ tags|join:", " }} → "js, python, rust"
234
- {{ items|join:" + " }} → "a + b + c"
235
- ```
236
-
237
- ### `slice:"start:end"`
238
- Slices an array or string like Python (`[start:end]`). Supports negative indices.
239
- ```html
240
- {{ items|slice:"1:3" }} → items[1], items[2]
241
- {{ items|slice:":2" }} → first 2 items
242
- {{ items|slice:"1:" }} → items from index 1 onwards
243
- {{ "hello"|slice:"1:4" }} → "ell"
244
- ```
245
-
246
- ### `sort`
247
- Sorts an array in ascending order. Strings use locale-aware comparison.
248
- ```html
249
- {{ [3, 1, 2]|sort }} → [1, 2, 3]
250
- ```
251
-
252
- ### `unique`
253
- Removes duplicate values from an array.
254
- ```html
255
- {{ [1, 2, 2, 3]|unique }} → [1, 2, 3]
256
- ```
257
-
258
- ### `random`
259
- Returns a random element from an array.
260
- ```html
261
- {{ ["a", "b", "c"]|random }} → "b" (random)
262
- ```
263
-
264
- ### `dictsort:"key"`
265
- Sorts an array of objects by the specified attribute (ascending).
266
- ```html
267
- {% for item in items|dictsort:"name" %}
268
- {{ item.name }}
269
- {% endfor %}
270
- ```
271
-
272
- ### `dictsortreversed:"key"`
273
- Sorts an array of objects by the specified attribute (descending).
274
- ```html
275
- {% for item in items|dictsortreversed:"price" %}
276
- {{ item.name }} - ${{ item.price }}
277
- {% endfor %}
278
- ```
279
-
280
- ---
281
-
282
- ## Default / Fallback Filters
283
-
284
- ### `default:fallback`
285
- Uses the fallback value if the original value is falsy (`null`, `undefined`, or empty string `""`).
286
- ```html
287
- {{ user.name|default:"Anonymous" }} → "Anonymous" if name is missing
288
- {{ ""|default:"empty" }} → "empty"
289
- {{ 0|default:"zero" }} → "zero"
290
- ```
291
-
292
- ### `default_if_none:fallback`
293
- Uses the fallback value only if the original value is `null` or `undefined` (not empty string).
294
- ```html
295
- {{ value|default_if_none:"N/A" }} → "N/A" if value === null or value === undefined
296
- {{ ""|default_if_none:"N/A" }} → "" (empty string is not none)
297
- ```
298
-
299
- ### `firstof`
300
- Returns the first truthy value from the arguments.
301
- ```html
302
- {{ ""|firstof:user.name:guest:default }} → user.name or "guest" or "default"
303
- ```
304
-
305
- ---
306
-
307
- ## Date / Time Filters
308
-
309
- All date filters accept `Date` objects, ISO strings, or timestamps.
310
-
311
- ### `date:"format"`
312
- Formats a date using Django-style format codes:
313
- | Code | Meaning | Example |
314
- |------|---------|---------|
315
- | `d` | Day with leading zero | `01–31` |
316
- | `j` | Day without leading zero | `1–31` |
317
- | `m` | Month with leading zero | `01–12` |
318
- | `n` | Month without leading zero | `1–12` |
319
- | `Y` | Full year | `2026` |
320
- | `y` | 2-digit year | `26` |
321
- | `H` | 24-hour with leading zero | `00–23` |
322
- | `i` | Minutes | `00–59` |
323
- | `s` | Seconds | `00–59` |
324
- | `F` | Full month name | `January` |
325
- | `M` | Short day/month name | `Jan` |
326
-
327
- ```html
328
- {{ post.published|date:"Y-m-d" }} → "2026-08-31"
329
- {{ post.published|date:"F j, Y" }} → "August 31, 2026"
330
- {{ post.published|date:"H:i" }} → "14:30"
331
- ```
332
-
333
- ### `time:"format"`
334
- Same as `date` but only outputs time portion.
335
-
336
- ### `strftime:"format"`
337
- Uses `date-fns` format patterns (PPpp, yyyy-MM-dd, etc.) for full locale support.
338
- ```html
339
- {{ now|strftime:"PPpp" }} → "Aug 31, 2026 at 2:30 PM"
340
- {{ now|strftime:"yyyy-MM-dd" }} → "2026-08-31"
341
- ```
342
-
343
- ### `date_format:"format"`
344
- Alias for `strftime` with additional custom patterns.
345
-
346
- ### `timesince`
347
- Returns a human-readable "time ago" string (e.g., "4 minutes", "2 hours", "3 days").
348
- ```html
349
- {{ post.created|timesince }} → "2 hours"
350
- {{ post.created|timesince:other_date }} → "3 days" (relative to other_date)
351
- ```
352
-
353
- ### `timeuntil`
354
- Returns a human-readable "time until" string.
355
- ```html
356
- {{ event.date|timeuntil }} → "5 days"
357
- ```
358
-
359
- ### `time_diff:date`
360
- Returns the absolute time difference between two dates as a human-readable string.
361
- ```html
362
- {{ event.date|time_diff }} → "3 days"
363
- {{ event.date|time_diff:now }} → difference from now
364
- ```
365
-
366
- ### `ago`
367
- Returns a human-readable relative time string like "2 days ago", "1 hour ago", etc.
368
- ```html
369
- {{ comment.created|ago }} → "2 days ago"
370
- {{ comment.created|ago }} → "just now" (if less than 1 minute ago)
371
- ```
372
-
373
- ### `until`
374
- Returns a human-readable string representing time until the given date.
375
- ```html
376
- {{ event.date|until }} → "3 days"
377
- {{ event.date|until }} → "now" (if less than 1 minute away)
378
- ```
379
-
380
- ---
381
-
382
- ## Numeric Filters
383
-
384
- ### `add:N`
385
- Adds N to the value. Also works for string concatenation and array concatenation.
386
- ```html
387
- {{ count|add:5 }} → count + 5
388
- {{ items|add:other }} → concatenated array or string
389
- ```
390
-
391
- ### `sub:N`
392
- Subtracts N from the value.
393
- ```html
394
- {{ 10|sub:3 }} → 7
395
- ```
396
-
397
- ### `mult:N`
398
- Multiplies the value by N.
399
- ```html
400
- {{ 4|mult:5 }} → 20
401
- ```
402
-
403
- ### `square`
404
- Returns the square of the value.
405
- ```html
406
- {{ 6|square }} → 36
407
- ```
408
-
409
- ### `sqrt`
410
- Returns the square root of the value. Returns 0 for negative numbers.
411
- ```html
412
- {{ 9|sqrt }} → 3
413
- {{ -1|sqrt }} → 0
414
- ```
415
-
416
- ### `mod:N`
417
- Returns the modulo (remainder) of the value divided by N. Returns 0 if N is 0.
418
- ```html
419
- {{ 10|mod:3 }} → 1
420
- {{ 10|mod:0 }} → 0
421
- ```
422
-
423
- ### `divisibleby:N`
424
- Returns `true` if the value is divisible by N.
425
- ```html
426
- {{ 10|divisibleby:5 }} → true
427
- {{ 7|divisibleby:2 }} → false
428
- ```
429
-
430
- ### `floatformat:N`
431
- Formats a number to N decimal places. Django default is 1 decimal.
432
-
433
- | arg | behavior |
434
- |-----|----------|
435
- | (none) | 1 decimal (`3.4`) |
436
- | `0` | 0 decimals (`3`) |
437
- | `1` | 1 decimal (`3.4`) |
438
- | `2` | 2 decimals (`3.40`) |
439
- | `-1` | all decimals, trimmed |
440
-
441
- ```html
442
- {{ 3.14159|floatformat }} → "3.1"
443
- {{ 3.14159|floatformat:2 }} → "3.14"
444
- {{ 3.000|floatformat:0 }} → "3"
445
- ```
446
-
447
- ### `abs`
448
- Returns the absolute value of a number.
449
- ```html
450
- {{ -5|abs }} → 5
451
- {{ 5|abs }} → 5
452
- ```
453
-
454
- ### `round:N`
455
- Rounds to N decimal places (default: 0 decimals).
456
- ```html
457
- {{ 3.14159|round:2 }} → 3.14
458
- {{ 3.5|round }} → 4
459
- {{ 3.4|round }} → 3
460
- ```
461
-
462
- ### `floor`
463
- Rounds down to the nearest integer.
464
- ```html
465
- {{ 3.7|floor }} → 3
466
- {{ -3.7|floor }} → -4
467
- ```
468
-
469
- ### `ceil`
470
- Rounds up to the nearest integer.
471
- ```html
472
- {{ 3.2|ceil }} → 4
473
- {{ -3.2|ceil }} → -3
474
- ```
475
-
476
- ### `min:N` / `min:array`
477
- Returns the minimum of the value and N, or the minimum element in an array.
478
- ```html
479
- {{ 5|min:2 }} → 2
480
- {{ [5, 2, 8]|min }} → 2
481
- ```
482
-
483
- ### `max:N` / `max:array`
484
- Returns the maximum of the value and N, or the maximum element in an array.
485
- ```html
486
- {{ 5|max:2 }} → 5
487
- {{ [5, 2, 8]|max }} → 8
488
- ```
489
-
490
- ### `sum`
491
- Returns the sum of all elements in an array.
492
- ```html
493
- {{ [1, 2, 3, 4]|sum }} → 10
494
- ```
495
-
496
- ### `average`
497
- Returns the arithmetic mean of an array. Returns 0 for empty arrays.
498
- ```html
499
- {{ [1, 2, 3, 4]|average }} → 2.5
500
- ```
501
-
502
- ---
503
-
504
- ## Miscellaneous Filters
505
-
506
- ### `yesno:"yes,no,maybe"`
507
- Maps truthy / falsy / null values to custom strings.
508
- ```html
509
- {{ flag|yesno:"yes,no,maybe" }} → "yes" if true, "no" if false, "maybe" if null
510
- {{ active|yesno:"Active,Inactive" }} → "Active" or "Inactive"
511
- ```
512
-
513
- ### `pluralize:"s,plural"`
514
- Returns the singular or plural suffix based on the value. Supports custom suffixes.
515
- ```html
516
- {{ items|length }} {{ items|pluralize }} item{{ items|pluralize }}
517
- <!-- 1 item | 5 items -->
518
-
519
- {{ count|pluralize:"y,ies" }} → "1 candy" | "2 candies"
520
- ```
521
-
522
- ### `filesizeformat`
523
- Formats a byte count as a human-readable file size.
524
- ```html
525
- {{ 1024|filesizeformat }} → "1.0 KB"
526
- {{ 1048576|filesizeformat }} → "1.0 MB"
527
- {{ 0|filesizeformat }} → "0 bytes"
528
- {{ 1536|filesizeformat }} → "1.5 KB"
529
- ```
530
-
531
- ---
532
-
533
- ## Data Formatting Filters
534
-
535
- ### `currency:symbol`
536
- Formats a number as currency with thousands separators and 2 decimal places. Default symbol is `$`.
537
- ```html
538
- {{ 1234.5|currency }} → "$1,234.50"
539
- {{ 1234.5|currency:"€" }} → "€1,234.50"
540
- ```
541
-
542
- ### `phone_number`
543
- Formats a 10-digit US phone number as `(123) 456-7890`. Handles 11-digit numbers with leading `1` as `+1 (123) 456-7890`.
544
- ```html
545
- {{ "1234567890"|phone_number }} → "(123) 456-7890"
546
- {{ "11234567890"|phone_number }} → "+1 (123) 456-7890"
547
- ```
548
-
549
- ### `email`
550
- Wraps an email address in a `mailto:` link.
551
- ```html
552
- {{ "user@example.com"|email }} → "mailto:user@example.com"
553
- ```
554
-
555
- ### `url`
556
- Ensures a URL has a protocol prefix. Prepends `https://` if missing.
557
- ```html
558
- {{ "example.com"|url }} → "https://example.com"
559
- {{ "https://example.com"|url }} → "https://example.com"
560
- ```
561
-
562
- ### `mask:char`
563
- Masks all but the last 4 characters of a string. Default mask character is `*`.
564
- ```html
565
- {{ "1234567890"|mask }} → "******7890"
566
- {{ "1234567890"|mask:"#" }} → "######7890"
567
- ```
568
-
569
- ### `whatsapp_link:message`
570
- Generates a WhatsApp link (`https://wa.me/NUMBER`) with an optional pre-filled message.
571
- ```html
572
- {{ "1234567890"|whatsapp_link }} → "https://wa.me/1234567890"
573
- {{ "1234567890"|whatsapp_link:"Hello" }} → "https://wa.me/1234567890?text=Hello"
574
- ```
575
-
576
- ### `credit_card`
577
- Formats a credit card number with dashes every 4 digits.
578
- ```html
579
- {{ "4111111111111111"|credit_card }} → "4111-1111-1111-1111"
580
- ```
581
-
582
- ### `ssn`
583
- Formats a 9-digit Social Security Number as `XXX-XX-XXXX`.
584
- ```html
585
- {{ "123456789"|ssn }} → "123-45-6789"
586
- ```
587
-
588
- ### `ip_address`
589
- Formats a 10 or 12 digit string as a dotted IP address.
590
- ```html
591
- {{ "192168011001"|ip_address }} → "192.168.11.001"
592
- ```
593
-
594
- ### `uuid`
595
- Generates a random UUID v4 string.
596
- ```html
597
- {{ ""|uuid }} → "9787a126-cb81-4825-b63b-73345a51a1c1"
598
- ```
599
-
600
- ---
601
-
602
- ## Humanize Filters (Built-in Library)
603
-
604
- These filters are part of the `humanize` library, activated by default or via `{% load humanize %}`.
605
-
606
- ### `intcomma`
607
- Adds commas to thousands places.
608
- ```html
609
- {{ 1234567|intcomma }} → "1,234,567"
610
- ```
611
-
612
- ### `intword`
613
- Converts large numbers to human-friendly strings.
614
- ```html
615
- {{ 1234567|intword }} → "1.2 million"
616
- {{ 1000|intword }} → "1.0 thousand"
617
- ```
618
-
619
- ### `apnumber`
620
- Converts numbers to their word equivalent (0–19).
621
- ```html
622
- {{ 3|apnumber }} → "three"
623
- ```
624
-
625
- ### `ordinal`
626
- Returns the ordinal suffix for a number.
627
- ```html
628
- {{ 1|ordinal }} → "1st"
629
- {{ 2|ordinal }} → "2nd"
630
- {{ 11|ordinal }} → "11th"
631
- ```
632
-
633
- ### `naturalday`
634
- Returns "today", "yesterday", "tomorrow", or the date string for other dates.
635
- ```html
636
- {{ today|naturalday }} → "today"
637
- {{ yesterday|naturalday }} → "yesterday"
638
- ```
639
-
640
- ---
641
-
642
- ## i18n Filters
643
-
644
- ### `trans:"fallback"`
645
- Translate a string using the i18n registry. Falls back to the original value if no translation is found.
646
-
647
- ```html
648
- {{ "Hello, World!"|trans }}
649
- {{ greeting|trans:"Hello, %s!" }}
650
- ```
651
-
652
- ---
653
-
654
- ## Regroup Filter
655
-
656
- ### `regroup:"key"`
657
- Group an array of objects by a common attribute. Returns an array of `{ grouper, list }` objects.
658
-
659
- ```html
660
- {% for group in items|regroup:"category" %}
661
- <h3>{{ group.grouper }}</h3>
662
- {% for item in group.list %}
663
- <p>{{ item.name }}</p>
664
- {% endfor %}
665
- {% endfor %}
666
- ```
667
-
668
- ---
669
-
670
- ## Custom Filters
671
-
672
- Register custom filters with `registerFilter`:
673
-
674
- ```javascript
675
- const { registerFilter } = require('miki-template');
676
-
677
- // Simple filter
678
- registerFilter('reverse', (val) => String(val).split('').reverse().join(''));
679
-
680
- // Filter with argument
681
- registerFilter('truncate', (val, length) => {
682
- const str = String(val);
683
- if (str.length <= length) return str;
684
- return str.slice(0, length) + '...';
685
- });
686
-
687
- // Chaining works automatically:
688
- // {{ name|reverse|truncate:5 }}
689
- ```
690
-
691
- ---
692
-
693
- ## Filter Argument Types
694
-
695
- Filters accept the following argument types:
696
-
697
- | Syntax | Type | Example |
698
- |--------|------|---------|
699
- | Unquoted | Variable lookup | `{{ value|filter:count }}` |
700
- | Double-quoted | String literal | `{{ value|filter:"hello" }}` |
701
- | Single-quoted | String literal | `{{ value|filter:'world' }}` |
702
- | Number | Integer literal | `{{ value|truncatewords:10 }}` |
703
-
704
- ```html
705
- {{ user.name|default:"Guest" }} <!-- String default -->
706
- {{ items|slice:"1:3" }} <!-- Slice notation -->
707
- {{ price|floatformat:2 }} <!-- Decimal places -->
708
- ```