odac 0.9.0 → 1.0.0

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 (208) hide show
  1. package/.github/workflows/auto-pr-description.yml +0 -2
  2. package/.github/workflows/codeql.yml +46 -0
  3. package/.github/workflows/release.yml +13 -6
  4. package/.github/workflows/test-coverage.yml +10 -9
  5. package/.releaserc.js +9 -6
  6. package/CHANGELOG.md +62 -150
  7. package/CODE_OF_CONDUCT.md +1 -1
  8. package/CONTRIBUTING.md +8 -8
  9. package/LICENSE +21 -661
  10. package/README.md +12 -12
  11. package/SECURITY.md +4 -4
  12. package/bin/odac.js +101 -0
  13. package/{framework/web/candy.js → client/odac.js} +310 -44
  14. package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
  15. package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
  16. package/docs/backend/01-overview/03-development-server.md +11 -11
  17. package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
  18. package/docs/backend/03-config/00-configuration-overview.md +6 -6
  19. package/docs/backend/03-config/01-database-connection.md +1 -1
  20. package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
  21. package/docs/backend/03-config/04-environment-variables.md +20 -20
  22. package/docs/backend/03-config/05-early-hints.md +4 -4
  23. package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
  24. package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
  25. package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
  26. package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
  27. package/docs/backend/04-routing/05-advanced-routing.md +3 -3
  28. package/docs/backend/04-routing/06-error-pages.md +17 -17
  29. package/docs/backend/04-routing/07-cron-jobs.md +13 -13
  30. package/docs/backend/04-routing/08-middleware.md +214 -0
  31. package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
  32. package/docs/backend/04-routing/09-websocket-examples.md +381 -0
  33. package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
  34. package/docs/backend/04-routing/09-websocket.md +298 -0
  35. package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
  36. package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
  37. package/docs/backend/05-controllers/03-controller-classes.md +19 -19
  38. package/docs/backend/05-forms/01-custom-forms.md +114 -114
  39. package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
  40. package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
  41. package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
  42. package/docs/backend/07-views/01-the-view-directory.md +1 -1
  43. package/docs/backend/07-views/02-rendering-a-view.md +22 -22
  44. package/docs/backend/07-views/03-template-syntax.md +52 -52
  45. package/docs/backend/07-views/03-variables.md +84 -84
  46. package/docs/backend/07-views/04-request-data.md +57 -57
  47. package/docs/backend/07-views/05-conditionals.md +78 -78
  48. package/docs/backend/07-views/06-loops.md +114 -114
  49. package/docs/backend/07-views/07-translations.md +66 -66
  50. package/docs/backend/07-views/08-backend-javascript.md +103 -103
  51. package/docs/backend/07-views/09-comments.md +71 -71
  52. package/docs/backend/08-database/01-database-connection.md +8 -8
  53. package/docs/backend/08-database/02-using-mysql.md +49 -49
  54. package/docs/backend/09-validation/01-the-validator-service.md +38 -38
  55. package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
  56. package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
  57. package/docs/backend/10-authentication/03-register.md +12 -12
  58. package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
  59. package/docs/backend/10-authentication/05-session-management.md +10 -10
  60. package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
  61. package/docs/backend/11-mail/01-the-mail-service.md +5 -5
  62. package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
  63. package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
  64. package/docs/frontend/01-overview/01-introduction.md +30 -30
  65. package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
  66. package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
  67. package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
  68. package/docs/frontend/03-forms/01-form-handling.md +32 -32
  69. package/docs/frontend/04-api-requests/01-get-post.md +33 -33
  70. package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
  71. package/docs/frontend/06-websocket/00-overview.md +76 -0
  72. package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
  73. package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
  74. package/docs/index.json +49 -11
  75. package/eslint.config.mjs +6 -6
  76. package/{framework/index.js → index.js} +1 -1
  77. package/package.json +14 -39
  78. package/{framework/src → src}/Auth.js +59 -59
  79. package/{framework/src → src}/Config.js +3 -3
  80. package/{framework/src → src}/Lang.js +7 -7
  81. package/{framework/src → src}/Mail.js +5 -5
  82. package/{framework/src → src}/Mysql.js +42 -42
  83. package/src/Odac.js +112 -0
  84. package/{framework/src → src}/Request.js +38 -36
  85. package/{framework/src → src}/Route/Internal.js +116 -116
  86. package/src/Route/Middleware.js +75 -0
  87. package/src/Route.js +621 -0
  88. package/src/Server.js +22 -0
  89. package/{framework/src → src}/Stream.js +11 -3
  90. package/{framework/src → src}/Validator.js +21 -21
  91. package/{framework/src → src}/Var.js +5 -5
  92. package/{framework/src → src}/View/EarlyHints.js +1 -1
  93. package/{framework/src → src}/View/Form.js +69 -69
  94. package/{framework/src → src}/View.js +78 -81
  95. package/src/WebSocket.js +403 -0
  96. package/template/config.json +5 -0
  97. package/{web → template}/controller/page/about.js +6 -6
  98. package/{web → template}/controller/page/index.js +9 -9
  99. package/{web → template}/package.json +4 -5
  100. package/{web → template}/public/assets/css/style.css +4 -4
  101. package/{web → template}/public/assets/js/app.js +6 -6
  102. package/{web → template}/route/www.js +6 -6
  103. package/{web → template}/skeleton/main.html +1 -1
  104. package/{web → template}/view/content/about.html +5 -5
  105. package/{web → template}/view/content/home.html +12 -12
  106. package/template/view/footer/main.html +11 -0
  107. package/{web → template}/view/head/main.html +1 -1
  108. package/{web → template}/view/header/main.html +2 -2
  109. package/test/core/Candy.test.js +58 -58
  110. package/test/core/Commands.test.js +7 -7
  111. package/test/core/Config.test.js +82 -85
  112. package/test/core/Lang.test.js +2 -2
  113. package/test/core/Process.test.js +6 -6
  114. package/test/framework/Route.test.js +56 -37
  115. package/test/framework/View/EarlyHints.test.js +2 -2
  116. package/test/framework/WebSocket.test.js +100 -0
  117. package/test/framework/middleware.test.js +85 -0
  118. package/test/server/Api.test.js +31 -31
  119. package/test/server/DNS.test.js +11 -11
  120. package/test/server/Hub.test.js +497 -0
  121. package/test/server/Mail.account.test_.js +3 -3
  122. package/test/server/Mail.init.test_.js +10 -10
  123. package/test/server/Mail.test_.js +20 -20
  124. package/test/server/SSL.test_.js +54 -54
  125. package/test/server/Server.test.js +39 -39
  126. package/test/server/Service.test_.js +7 -7
  127. package/test/server/Subdomain.test.js +7 -7
  128. package/test/server/Web/Firewall.test.js +87 -87
  129. package/test/server/Web/Proxy.test.js +397 -0
  130. package/test/server/{Web.test_.js → Web.test.js} +137 -205
  131. package/test/server/__mocks__/fs.js +2 -2
  132. package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
  133. package/test/server/__mocks__/index.js +6 -6
  134. package/test/server/__mocks__/testFactories.js +1 -1
  135. package/test/server/__mocks__/testHelpers.js +7 -7
  136. package/.husky/pre-commit +0 -2
  137. package/.kiro/steering/code-style.md +0 -56
  138. package/.kiro/steering/product.md +0 -20
  139. package/.kiro/steering/structure.md +0 -77
  140. package/.kiro/steering/tech.md +0 -87
  141. package/AGENTS.md +0 -84
  142. package/bin/candy +0 -10
  143. package/bin/candypack +0 -10
  144. package/cli/index.js +0 -3
  145. package/cli/src/Cli.js +0 -348
  146. package/cli/src/Connector.js +0 -93
  147. package/cli/src/Monitor.js +0 -416
  148. package/core/Candy.js +0 -87
  149. package/core/Commands.js +0 -239
  150. package/core/Config.js +0 -1094
  151. package/core/Lang.js +0 -52
  152. package/core/Log.js +0 -43
  153. package/core/Process.js +0 -26
  154. package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
  155. package/docs/server/01-installation/01-quick-install.md +0 -19
  156. package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
  157. package/docs/server/02-get-started/01-core-concepts.md +0 -7
  158. package/docs/server/02-get-started/02-basic-commands.md +0 -57
  159. package/docs/server/02-get-started/03-cli-reference.md +0 -276
  160. package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
  161. package/docs/server/03-service/01-start-a-new-service.md +0 -57
  162. package/docs/server/03-service/02-delete-a-service.md +0 -48
  163. package/docs/server/04-web/01-create-a-website.md +0 -36
  164. package/docs/server/04-web/02-list-websites.md +0 -9
  165. package/docs/server/04-web/03-delete-a-website.md +0 -29
  166. package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
  167. package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
  168. package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
  169. package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
  170. package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
  171. package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
  172. package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
  173. package/docs/server/07-mail/04-change-account-password.md +0 -23
  174. package/framework/src/Candy.js +0 -81
  175. package/framework/src/Route.js +0 -455
  176. package/framework/src/Server.js +0 -15
  177. package/locale/de-DE.json +0 -80
  178. package/locale/en-US.json +0 -79
  179. package/locale/es-ES.json +0 -80
  180. package/locale/fr-FR.json +0 -80
  181. package/locale/pt-BR.json +0 -80
  182. package/locale/ru-RU.json +0 -80
  183. package/locale/tr-TR.json +0 -85
  184. package/locale/zh-CN.json +0 -80
  185. package/server/index.js +0 -5
  186. package/server/src/Api.js +0 -88
  187. package/server/src/DNS.js +0 -940
  188. package/server/src/Hub.js +0 -535
  189. package/server/src/Mail.js +0 -571
  190. package/server/src/SSL.js +0 -180
  191. package/server/src/Server.js +0 -27
  192. package/server/src/Service.js +0 -248
  193. package/server/src/Subdomain.js +0 -64
  194. package/server/src/Web/Firewall.js +0 -170
  195. package/server/src/Web/Proxy.js +0 -134
  196. package/server/src/Web.js +0 -451
  197. package/server/src/mail/imap.js +0 -1091
  198. package/server/src/mail/server.js +0 -32
  199. package/server/src/mail/smtp.js +0 -786
  200. package/test/server/Client.test.js +0 -338
  201. package/test/server/__mocks__/http-proxy.js +0 -105
  202. package/watchdog/index.js +0 -3
  203. package/watchdog/src/Watchdog.js +0 -156
  204. package/web/config.json +0 -5
  205. package/web/view/footer/main.html +0 -11
  206. /package/{framework/src → src}/Env.js +0 -0
  207. /package/{framework/src → src}/Route/Cron.js +0 -0
  208. /package/{framework/src → src}/Token.js +0 -0
@@ -1,16 +1,16 @@
1
1
  ## 🌍 Translations (i18n)
2
2
 
3
- CandyPack provides built-in internationalization (i18n) support, allowing you to create multi-language applications easily.
3
+ Odac provides built-in internationalization (i18n) support, allowing you to create multi-language applications easily.
4
4
 
5
5
  ### Basic Translation
6
6
 
7
7
  ```html
8
- <candy translate>Welcome</candy>
9
- <candy translate>Hello World</candy>
10
- <candy translate>Login</candy>
8
+ <odac translate>Welcome</odac>
9
+ <odac translate>Hello World</odac>
10
+ <odac translate>Login</odac>
11
11
  ```
12
12
 
13
- The text inside the tag is used as the translation key. CandyPack looks up this key in your locale files.
13
+ The text inside the tag is used as the translation key. Odac looks up this key in your locale files.
14
14
 
15
15
  ### Translation Files
16
16
 
@@ -45,15 +45,15 @@ locale/
45
45
 
46
46
  ### Translations with Placeholders
47
47
 
48
- Use nested `<candy>` tags to insert dynamic values:
48
+ Use nested `<odac>` tags to insert dynamic values:
49
49
 
50
50
  ```html
51
- <candy translate>Hello <candy var="user.name" /></candy>
51
+ <odac translate>Hello <odac var="user.name" /></odac>
52
52
  ```
53
53
 
54
54
  **How it works:**
55
55
  1. The content becomes: `Hello %s1`
56
- 2. CandyPack looks up this key in the locale file
56
+ 2. Odac looks up this key in the locale file
57
57
  3. `%s1` is replaced with the actual value
58
58
 
59
59
  **Locale file:**
@@ -67,9 +67,9 @@ Use nested `<candy>` tags to insert dynamic values:
67
67
  ### Multiple Placeholders
68
68
 
69
69
  ```html
70
- <candy translate>
71
- <candy var="user.firstName" /> <candy var="user.lastName" />
72
- </candy>
70
+ <odac translate>
71
+ <odac var="user.firstName" /> <odac var="user.lastName" />
72
+ </odac>
73
73
  ```
74
74
 
75
75
  This creates the key `%s1 %s2` and replaces both placeholders.
@@ -85,7 +85,7 @@ This creates the key `%s1 %s2` and replaces both placeholders.
85
85
  ### String Literals in Translations
86
86
 
87
87
  ```html
88
- <candy translate>Hello <candy>John</candy>, how are you?</candy>
88
+ <odac translate>Hello <odac>John</odac>, how are you?</odac>
89
89
  ```
90
90
 
91
91
  **Locale file:**
@@ -102,11 +102,11 @@ By default, translations are HTML-escaped for security. Use `raw` attribute when
102
102
 
103
103
  ```html
104
104
  <!-- Normal translation (HTML will be encoded) -->
105
- <candy translate>Click <a href="/help">here</a> for help</candy>
105
+ <odac translate>Click <a href="/help">here</a> for help</odac>
106
106
  <!-- Output: Click &lt;a href="/help"&gt;here&lt;/a&gt; for help -->
107
107
 
108
108
  <!-- Raw translation (HTML preserved) -->
109
- <candy translate raw>Click <a href="/help">here</a> for help</candy>
109
+ <odac translate raw>Click <a href="/help">here</a> for help</odac>
110
110
  <!-- Output: Click <a href="/help">here</a> for help -->
111
111
  ```
112
112
 
@@ -121,9 +121,9 @@ By default, translations are HTML-escaped for security. Use `raw` attribute when
121
121
  ### Raw Translations with Placeholders
122
122
 
123
123
  ```html
124
- <candy translate raw>
125
- Welcome <strong><candy var="user.name" /></strong>!
126
- </candy>
124
+ <odac translate raw>
125
+ Welcome <strong><odac var="user.name" /></strong>!
126
+ </odac>
127
127
  ```
128
128
 
129
129
  **Locale file:**
@@ -140,10 +140,10 @@ By default, translations are HTML-escaped for security. Use `raw` attribute when
140
140
 
141
141
  ```html
142
142
  <nav>
143
- <a href="/"><candy translate>Home</candy></a>
144
- <a href="/products"><candy translate>Products</candy></a>
145
- <a href="/about"><candy translate>About Us</candy></a>
146
- <a href="/contact"><candy translate>Contact</candy></a>
143
+ <a href="/"><odac translate>Home</odac></a>
144
+ <a href="/products"><odac translate>Products</odac></a>
145
+ <a href="/about"><odac translate>About Us</odac></a>
146
+ <a href="/contact"><odac translate>Contact</odac></a>
147
147
  </nav>
148
148
  ```
149
149
 
@@ -152,10 +152,10 @@ By default, translations are HTML-escaped for security. Use `raw` attribute when
152
152
  ```html
153
153
  <div class="welcome">
154
154
  <h1>
155
- <candy translate>Welcome back, <candy var="user.name" />!</candy>
155
+ <odac translate>Welcome back, <odac var="user.name" />!</odac>
156
156
  </h1>
157
157
  <p>
158
- <candy translate>You have <candy var="notifications.length" /> new notifications</candy>
158
+ <odac translate>You have <odac var="notifications.length" /> new notifications</odac>
159
159
  </p>
160
160
  </div>
161
161
  ```
@@ -175,21 +175,21 @@ By default, translations are HTML-escaped for security. Use `raw` attribute when
175
175
  ```html
176
176
  <form>
177
177
  <div class="form-group">
178
- <label><candy translate>Email Address</candy></label>
179
- <input type="email" name="email" placeholder="<candy translate>Enter your email</candy>">
178
+ <label><odac translate>Email Address</odac></label>
179
+ <input type="email" name="email" placeholder="<odac translate>Enter your email</odac>">
180
180
  </div>
181
181
 
182
182
  <div class="form-group">
183
- <label><candy translate>Password</candy></label>
184
- <input type="password" name="password" placeholder="<candy translate>Enter your password</candy>">
183
+ <label><odac translate>Password</odac></label>
184
+ <input type="password" name="password" placeholder="<odac translate>Enter your password</odac>">
185
185
  </div>
186
186
 
187
187
  <button type="submit">
188
- <candy translate>Login</candy>
188
+ <odac translate>Login</odac>
189
189
  </button>
190
190
 
191
191
  <a href="/forgot-password">
192
- <candy translate>Forgot your password?</candy>
192
+ <odac translate>Forgot your password?</odac>
193
193
  </a>
194
194
  </form>
195
195
  ```
@@ -198,24 +198,24 @@ By default, translations are HTML-escaped for security. Use `raw` attribute when
198
198
 
199
199
  ```html
200
200
  <div class="product">
201
- <h2><candy var="product.name" /></h2>
201
+ <h2><odac var="product.name" /></h2>
202
202
 
203
203
  <p class="price">
204
- <candy translate>Price: $<candy var="product.price" /></candy>
204
+ <odac translate>Price: $<odac var="product.price" /></odac>
205
205
  </p>
206
206
 
207
- <candy:if condition="product.stock > 0">
207
+ <odac:if condition="product.stock > 0">
208
208
  <p class="stock">
209
- <candy translate><candy var="product.stock" /> units in stock</candy>
209
+ <odac translate><odac var="product.stock" /> units in stock</odac>
210
210
  </p>
211
- <candy:else>
211
+ <odac:else>
212
212
  <p class="out-of-stock">
213
- <candy translate>Out of stock</candy>
213
+ <odac translate>Out of stock</odac>
214
214
  </p>
215
- </candy:if>
215
+ </odac:if>
216
216
 
217
217
  <button>
218
- <candy translate>Add to Cart</candy>
218
+ <odac translate>Add to Cart</odac>
219
219
  </button>
220
220
  </div>
221
221
  ```
@@ -237,28 +237,28 @@ By default, translations are HTML-escaped for security. Use `raw` attribute when
237
237
  #### Error Messages
238
238
 
239
239
  ```html
240
- <candy:if condition="errors">
240
+ <odac:if condition="errors">
241
241
  <div class="error-box">
242
- <candy:if condition="errors.email">
243
- <p><candy translate>Invalid email address</candy></p>
244
- </candy:if>
242
+ <odac:if condition="errors.email">
243
+ <p><odac translate>Invalid email address</odac></p>
244
+ </odac:if>
245
245
 
246
- <candy:if condition="errors.password">
247
- <p><candy translate>Password must be at least 8 characters</candy></p>
248
- </candy:if>
246
+ <odac:if condition="errors.password">
247
+ <p><odac translate>Password must be at least 8 characters</odac></p>
248
+ </odac:if>
249
249
  </div>
250
- </candy:if>
250
+ </odac:if>
251
251
  ```
252
252
 
253
253
  #### Rich Text with HTML
254
254
 
255
255
  ```html
256
256
  <div class="notice">
257
- <candy translate raw>
257
+ <odac translate raw>
258
258
  By clicking "Register", you agree to our
259
259
  <a href="/terms">Terms of Service</a> and
260
260
  <a href="/privacy">Privacy Policy</a>.
261
- </candy>
261
+ </odac>
262
262
  </div>
263
263
  ```
264
264
 
@@ -276,19 +276,19 @@ The language is typically set based on user preference or browser settings. You
276
276
 
277
277
  ```javascript
278
278
  // Controller
279
- module.exports = async function(Candy) {
279
+ module.exports = async function(Odac) {
280
280
  // Set language from user preference
281
- const userLang = Candy.Auth.check()
282
- ? Candy.Auth.user().language
281
+ const userLang = Odac.Auth.check()
282
+ ? Odac.Auth.user().language
283
283
  : 'en'
284
284
 
285
- Candy.Lang.setLanguage(userLang)
285
+ Odac.Lang.setLanguage(userLang)
286
286
 
287
287
  // Or from query parameter
288
- const lang = Candy.Request.get('lang') || 'en'
289
- Candy.Lang.setLanguage(lang)
288
+ const lang = Odac.Request.get('lang') || 'en'
289
+ Odac.Lang.setLanguage(lang)
290
290
 
291
- Candy.View.skeleton('main').set('content', 'home')
291
+ Odac.View.skeleton('main').set('content', 'home')
292
292
  }
293
293
  ```
294
294
 
@@ -297,11 +297,11 @@ module.exports = async function(Candy) {
297
297
  You can also use translations in your controllers:
298
298
 
299
299
  ```javascript
300
- module.exports = async function(Candy) {
301
- const message = Candy.__('Welcome back, %s!', user.name)
300
+ module.exports = async function(Odac) {
301
+ const message = Odac.__('Welcome back, %s!', user.name)
302
302
 
303
- Candy.set('message', message)
304
- Candy.View.skeleton('main').set('content', 'dashboard')
303
+ Odac.set('message', message)
304
+ Odac.View.skeleton('main').set('content', 'dashboard')
305
305
  }
306
306
  ```
307
307
 
@@ -338,21 +338,21 @@ module.exports = async function(Candy) {
338
338
  #### Pluralization
339
339
 
340
340
  ```html
341
- <candy:if condition="count === 1">
342
- <candy translate><candy var="count" /> item</candy>
343
- <candy:else>
344
- <candy translate><candy var="count" /> items</candy>
345
- </candy:if>
341
+ <odac:if condition="count === 1">
342
+ <odac translate><odac var="count" /> item</odac>
343
+ <odac:else>
344
+ <odac translate><odac var="count" /> items</odac>
345
+ </odac:if>
346
346
  ```
347
347
 
348
348
  #### Date Formatting
349
349
 
350
350
  ```javascript
351
351
  // Controller
352
- const formattedDate = new Date(date).toLocaleDateString(Candy.Lang.current())
353
- Candy.set('date', formattedDate)
352
+ const formattedDate = new Date(date).toLocaleDateString(Odac.Lang.current())
353
+ Odac.set('date', formattedDate)
354
354
  ```
355
355
 
356
356
  ```html
357
- <p><candy translate>Last updated: <candy var="date" /></candy></p>
357
+ <p><odac translate>Last updated: <odac var="date" /></odac></p>
358
358
  ```