odac 0.9.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.
- package/.editorconfig +21 -0
- package/.github/workflows/auto-pr-description.yml +49 -0
- package/.github/workflows/release.yml +32 -0
- package/.github/workflows/test-coverage.yml +58 -0
- package/.husky/pre-commit +2 -0
- package/.kiro/steering/code-style.md +56 -0
- package/.kiro/steering/product.md +20 -0
- package/.kiro/steering/structure.md +77 -0
- package/.kiro/steering/tech.md +87 -0
- package/.prettierrc +10 -0
- package/.releaserc.js +134 -0
- package/AGENTS.md +84 -0
- package/CHANGELOG.md +181 -0
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +63 -0
- package/LICENSE +661 -0
- package/README.md +57 -0
- package/SECURITY.md +26 -0
- package/bin/candy +10 -0
- package/bin/candypack +10 -0
- package/cli/index.js +3 -0
- package/cli/src/Cli.js +348 -0
- package/cli/src/Connector.js +93 -0
- package/cli/src/Monitor.js +416 -0
- package/core/Candy.js +87 -0
- package/core/Commands.js +239 -0
- package/core/Config.js +1094 -0
- package/core/Lang.js +52 -0
- package/core/Log.js +43 -0
- package/core/Process.js +26 -0
- package/docs/backend/01-overview/01-whats-in-the-candy-box.md +9 -0
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +9 -0
- package/docs/backend/01-overview/03-development-server.md +79 -0
- package/docs/backend/02-structure/01-typical-project-layout.md +39 -0
- package/docs/backend/03-config/00-configuration-overview.md +214 -0
- package/docs/backend/03-config/01-database-connection.md +60 -0
- package/docs/backend/03-config/02-static-route-mapping-optional.md +20 -0
- package/docs/backend/03-config/03-request-timeout.md +11 -0
- package/docs/backend/03-config/04-environment-variables.md +227 -0
- package/docs/backend/03-config/05-early-hints.md +352 -0
- package/docs/backend/04-routing/01-basic-page-routes.md +28 -0
- package/docs/backend/04-routing/02-controller-less-view-routes.md +43 -0
- package/docs/backend/04-routing/03-api-and-data-routes.md +20 -0
- package/docs/backend/04-routing/04-authentication-aware-routes.md +48 -0
- package/docs/backend/04-routing/05-advanced-routing.md +14 -0
- package/docs/backend/04-routing/06-error-pages.md +101 -0
- package/docs/backend/04-routing/07-cron-jobs.md +149 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +17 -0
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +20 -0
- package/docs/backend/05-controllers/03-controller-classes.md +93 -0
- package/docs/backend/05-forms/01-custom-forms.md +395 -0
- package/docs/backend/05-forms/02-automatic-database-insert.md +297 -0
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +96 -0
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +40 -0
- package/docs/backend/07-views/01-the-view-directory.md +73 -0
- package/docs/backend/07-views/02-rendering-a-view.md +179 -0
- package/docs/backend/07-views/03-template-syntax.md +181 -0
- package/docs/backend/07-views/03-variables.md +328 -0
- package/docs/backend/07-views/04-request-data.md +231 -0
- package/docs/backend/07-views/05-conditionals.md +290 -0
- package/docs/backend/07-views/06-loops.md +353 -0
- package/docs/backend/07-views/07-translations.md +358 -0
- package/docs/backend/07-views/08-backend-javascript.md +398 -0
- package/docs/backend/07-views/09-comments.md +297 -0
- package/docs/backend/08-database/01-database-connection.md +99 -0
- package/docs/backend/08-database/02-using-mysql.md +322 -0
- package/docs/backend/09-validation/01-the-validator-service.md +424 -0
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +53 -0
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +55 -0
- package/docs/backend/10-authentication/03-register.md +134 -0
- package/docs/backend/10-authentication/04-candy-register-forms.md +676 -0
- package/docs/backend/10-authentication/05-session-management.md +159 -0
- package/docs/backend/10-authentication/06-candy-login-forms.md +596 -0
- package/docs/backend/11-mail/01-the-mail-service.md +42 -0
- package/docs/backend/12-streaming/01-streaming-overview.md +300 -0
- package/docs/backend/13-utilities/01-candy-var.md +504 -0
- package/docs/frontend/01-overview/01-introduction.md +146 -0
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +608 -0
- package/docs/frontend/02-ajax-navigation/02-configuration.md +370 -0
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +519 -0
- package/docs/frontend/03-forms/01-form-handling.md +420 -0
- package/docs/frontend/04-api-requests/01-get-post.md +443 -0
- package/docs/frontend/05-streaming/01-client-streaming.md +163 -0
- package/docs/index.json +452 -0
- package/docs/server/01-installation/01-quick-install.md +19 -0
- package/docs/server/01-installation/02-manual-installation-via-npm.md +9 -0
- package/docs/server/02-get-started/01-core-concepts.md +7 -0
- package/docs/server/02-get-started/02-basic-commands.md +57 -0
- package/docs/server/02-get-started/03-cli-reference.md +276 -0
- package/docs/server/02-get-started/04-cli-quick-reference.md +102 -0
- package/docs/server/03-service/01-start-a-new-service.md +57 -0
- package/docs/server/03-service/02-delete-a-service.md +48 -0
- package/docs/server/04-web/01-create-a-website.md +36 -0
- package/docs/server/04-web/02-list-websites.md +9 -0
- package/docs/server/04-web/03-delete-a-website.md +29 -0
- package/docs/server/05-subdomain/01-create-a-subdomain.md +32 -0
- package/docs/server/05-subdomain/02-list-subdomains.md +33 -0
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +41 -0
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +34 -0
- package/docs/server/07-mail/01-create-a-mail-account.md +23 -0
- package/docs/server/07-mail/02-delete-a-mail-account.md +20 -0
- package/docs/server/07-mail/03-list-mail-accounts.md +20 -0
- package/docs/server/07-mail/04-change-account-password.md +23 -0
- package/eslint.config.mjs +120 -0
- package/framework/index.js +4 -0
- package/framework/src/Auth.js +309 -0
- package/framework/src/Candy.js +81 -0
- package/framework/src/Config.js +79 -0
- package/framework/src/Env.js +60 -0
- package/framework/src/Lang.js +57 -0
- package/framework/src/Mail.js +83 -0
- package/framework/src/Mysql.js +575 -0
- package/framework/src/Request.js +301 -0
- package/framework/src/Route/Cron.js +128 -0
- package/framework/src/Route/Internal.js +439 -0
- package/framework/src/Route.js +455 -0
- package/framework/src/Server.js +15 -0
- package/framework/src/Stream.js +163 -0
- package/framework/src/Token.js +37 -0
- package/framework/src/Validator.js +271 -0
- package/framework/src/Var.js +211 -0
- package/framework/src/View/EarlyHints.js +190 -0
- package/framework/src/View/Form.js +600 -0
- package/framework/src/View.js +513 -0
- package/framework/web/candy.js +838 -0
- package/jest.config.js +22 -0
- package/locale/de-DE.json +80 -0
- package/locale/en-US.json +79 -0
- package/locale/es-ES.json +80 -0
- package/locale/fr-FR.json +80 -0
- package/locale/pt-BR.json +80 -0
- package/locale/ru-RU.json +80 -0
- package/locale/tr-TR.json +85 -0
- package/locale/zh-CN.json +80 -0
- package/package.json +86 -0
- package/server/index.js +5 -0
- package/server/src/Api.js +88 -0
- package/server/src/DNS.js +940 -0
- package/server/src/Hub.js +535 -0
- package/server/src/Mail.js +571 -0
- package/server/src/SSL.js +180 -0
- package/server/src/Server.js +27 -0
- package/server/src/Service.js +248 -0
- package/server/src/Subdomain.js +64 -0
- package/server/src/Web/Firewall.js +170 -0
- package/server/src/Web/Proxy.js +134 -0
- package/server/src/Web.js +451 -0
- package/server/src/mail/imap.js +1091 -0
- package/server/src/mail/server.js +32 -0
- package/server/src/mail/smtp.js +786 -0
- package/test/cli/Cli.test.js +36 -0
- package/test/core/Candy.test.js +234 -0
- package/test/core/Commands.test.js +538 -0
- package/test/core/Config.test.js +1435 -0
- package/test/core/Lang.test.js +250 -0
- package/test/core/Process.test.js +156 -0
- package/test/framework/Route.test.js +239 -0
- package/test/framework/View/EarlyHints.test.js +282 -0
- package/test/scripts/check-coverage.js +132 -0
- package/test/server/Api.test.js +647 -0
- package/test/server/Client.test.js +338 -0
- package/test/server/DNS.test.js +2050 -0
- package/test/server/DNS.test.js.bak +2084 -0
- package/test/server/Log.test.js +73 -0
- package/test/server/Mail.account.test_.js +460 -0
- package/test/server/Mail.init.test_.js +411 -0
- package/test/server/Mail.test_.js +1340 -0
- package/test/server/SSL.test_.js +1491 -0
- package/test/server/Server.test.js +765 -0
- package/test/server/Service.test_.js +1127 -0
- package/test/server/Subdomain.test.js +440 -0
- package/test/server/Web/Firewall.test.js +175 -0
- package/test/server/Web.test_.js +1562 -0
- package/test/server/__mocks__/acme-client.js +17 -0
- package/test/server/__mocks__/bcrypt.js +50 -0
- package/test/server/__mocks__/child_process.js +389 -0
- package/test/server/__mocks__/crypto.js +432 -0
- package/test/server/__mocks__/fs.js +450 -0
- package/test/server/__mocks__/globalCandy.js +227 -0
- package/test/server/__mocks__/http-proxy.js +105 -0
- package/test/server/__mocks__/http.js +575 -0
- package/test/server/__mocks__/https.js +272 -0
- package/test/server/__mocks__/index.js +249 -0
- package/test/server/__mocks__/mail/server.js +100 -0
- package/test/server/__mocks__/mail/smtp.js +31 -0
- package/test/server/__mocks__/mailparser.js +81 -0
- package/test/server/__mocks__/net.js +369 -0
- package/test/server/__mocks__/node-forge.js +328 -0
- package/test/server/__mocks__/os.js +320 -0
- package/test/server/__mocks__/path.js +291 -0
- package/test/server/__mocks__/selfsigned.js +8 -0
- package/test/server/__mocks__/server/src/mail/server.js +100 -0
- package/test/server/__mocks__/server/src/mail/smtp.js +31 -0
- package/test/server/__mocks__/smtp-server.js +106 -0
- package/test/server/__mocks__/sqlite3.js +394 -0
- package/test/server/__mocks__/testFactories.js +299 -0
- package/test/server/__mocks__/testHelpers.js +363 -0
- package/test/server/__mocks__/tls.js +229 -0
- package/watchdog/index.js +3 -0
- package/watchdog/src/Watchdog.js +156 -0
- package/web/config.json +5 -0
- package/web/controller/page/about.js +27 -0
- package/web/controller/page/index.js +34 -0
- package/web/package.json +18 -0
- package/web/public/assets/css/style.css +1835 -0
- package/web/public/assets/js/app.js +96 -0
- package/web/route/www.js +19 -0
- package/web/skeleton/main.html +22 -0
- package/web/view/content/about.html +65 -0
- package/web/view/content/home.html +205 -0
- package/web/view/footer/main.html +11 -0
- package/web/view/head/main.html +5 -0
- package/web/view/header/main.html +14 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
## 🌍 Translations (i18n)
|
|
2
|
+
|
|
3
|
+
CandyPack provides built-in internationalization (i18n) support, allowing you to create multi-language applications easily.
|
|
4
|
+
|
|
5
|
+
### Basic Translation
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<candy translate>Welcome</candy>
|
|
9
|
+
<candy translate>Hello World</candy>
|
|
10
|
+
<candy translate>Login</candy>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The text inside the tag is used as the translation key. CandyPack looks up this key in your locale files.
|
|
14
|
+
|
|
15
|
+
### Translation Files
|
|
16
|
+
|
|
17
|
+
Translation files are stored in the `locale/` directory:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
locale/
|
|
21
|
+
├── en.json
|
|
22
|
+
├── tr.json
|
|
23
|
+
└── de.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Example: `locale/en.json`**
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"Welcome": "Welcome",
|
|
30
|
+
"Hello World": "Hello World",
|
|
31
|
+
"Login": "Login",
|
|
32
|
+
"Logout": "Logout"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Example: `locale/tr.json`**
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"Welcome": "Hoş Geldiniz",
|
|
40
|
+
"Hello World": "Merhaba Dünya",
|
|
41
|
+
"Login": "Giriş Yap",
|
|
42
|
+
"Logout": "Çıkış Yap"
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Translations with Placeholders
|
|
47
|
+
|
|
48
|
+
Use nested `<candy>` tags to insert dynamic values:
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<candy translate>Hello <candy var="user.name" /></candy>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**How it works:**
|
|
55
|
+
1. The content becomes: `Hello %s1`
|
|
56
|
+
2. CandyPack looks up this key in the locale file
|
|
57
|
+
3. `%s1` is replaced with the actual value
|
|
58
|
+
|
|
59
|
+
**Locale file:**
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"Hello %s1": "Hello %s1",
|
|
63
|
+
"Hello %s1": "Merhaba %s1"
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Multiple Placeholders
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<candy translate>
|
|
71
|
+
<candy var="user.firstName" /> <candy var="user.lastName" />
|
|
72
|
+
</candy>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This creates the key `%s1 %s2` and replaces both placeholders.
|
|
76
|
+
|
|
77
|
+
**Locale file:**
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"%s1 %s2": "%s1 %s2",
|
|
81
|
+
"%s1 %s2": "%s1 %s2"
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### String Literals in Translations
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<candy translate>Hello <candy>John</candy>, how are you?</candy>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Locale file:**
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"Hello %s1, how are you?": "Hello %s1, how are you?",
|
|
95
|
+
"Hello %s1, how are you?": "Merhaba %s1, nasılsın?"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Raw HTML in Translations
|
|
100
|
+
|
|
101
|
+
By default, translations are HTML-escaped for security. Use `raw` attribute when your translation contains HTML:
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<!-- Normal translation (HTML will be encoded) -->
|
|
105
|
+
<candy translate>Click <a href="/help">here</a> for help</candy>
|
|
106
|
+
<!-- Output: Click <a href="/help">here</a> for help -->
|
|
107
|
+
|
|
108
|
+
<!-- Raw translation (HTML preserved) -->
|
|
109
|
+
<candy translate raw>Click <a href="/help">here</a> for help</candy>
|
|
110
|
+
<!-- Output: Click <a href="/help">here</a> for help -->
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Locale file:**
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"Click <a href=\"/help\">here</a> for help": "Click <a href=\"/help\">here</a> for help",
|
|
117
|
+
"Click <a href=\"/help\">here</a> for help": "Yardım için <a href=\"/help\">buraya</a> tıklayın"
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Raw Translations with Placeholders
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<candy translate raw>
|
|
125
|
+
Welcome <strong><candy var="user.name" /></strong>!
|
|
126
|
+
</candy>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Locale file:**
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"Welcome <strong>%s1</strong>!": "Welcome <strong>%s1</strong>!",
|
|
133
|
+
"Welcome <strong>%s1</strong>!": "Hoş geldin <strong>%s1</strong>!"
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Practical Examples
|
|
138
|
+
|
|
139
|
+
#### Navigation Menu
|
|
140
|
+
|
|
141
|
+
```html
|
|
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>
|
|
147
|
+
</nav>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Welcome Message
|
|
151
|
+
|
|
152
|
+
```html
|
|
153
|
+
<div class="welcome">
|
|
154
|
+
<h1>
|
|
155
|
+
<candy translate>Welcome back, <candy var="user.name" />!</candy>
|
|
156
|
+
</h1>
|
|
157
|
+
<p>
|
|
158
|
+
<candy translate>You have <candy var="notifications.length" /> new notifications</candy>
|
|
159
|
+
</p>
|
|
160
|
+
</div>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Locale file:**
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"Welcome back, %s1!": "Welcome back, %s1!",
|
|
167
|
+
"Welcome back, %s1!": "Tekrar hoş geldin, %s1!",
|
|
168
|
+
"You have %s1 new notifications": "You have %s1 new notifications",
|
|
169
|
+
"You have %s1 new notifications": "%s1 yeni bildiriminiz var"
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### Form Labels and Buttons
|
|
174
|
+
|
|
175
|
+
```html
|
|
176
|
+
<form>
|
|
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>">
|
|
180
|
+
</div>
|
|
181
|
+
|
|
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>">
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<button type="submit">
|
|
188
|
+
<candy translate>Login</candy>
|
|
189
|
+
</button>
|
|
190
|
+
|
|
191
|
+
<a href="/forgot-password">
|
|
192
|
+
<candy translate>Forgot your password?</candy>
|
|
193
|
+
</a>
|
|
194
|
+
</form>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### Product Information
|
|
198
|
+
|
|
199
|
+
```html
|
|
200
|
+
<div class="product">
|
|
201
|
+
<h2><candy var="product.name" /></h2>
|
|
202
|
+
|
|
203
|
+
<p class="price">
|
|
204
|
+
<candy translate>Price: $<candy var="product.price" /></candy>
|
|
205
|
+
</p>
|
|
206
|
+
|
|
207
|
+
<candy:if condition="product.stock > 0">
|
|
208
|
+
<p class="stock">
|
|
209
|
+
<candy translate><candy var="product.stock" /> units in stock</candy>
|
|
210
|
+
</p>
|
|
211
|
+
<candy:else>
|
|
212
|
+
<p class="out-of-stock">
|
|
213
|
+
<candy translate>Out of stock</candy>
|
|
214
|
+
</p>
|
|
215
|
+
</candy:if>
|
|
216
|
+
|
|
217
|
+
<button>
|
|
218
|
+
<candy translate>Add to Cart</candy>
|
|
219
|
+
</button>
|
|
220
|
+
</div>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Locale file:**
|
|
224
|
+
```json
|
|
225
|
+
{
|
|
226
|
+
"Price: $%s1": "Price: $%s1",
|
|
227
|
+
"Price: $%s1": "Fiyat: $%s1",
|
|
228
|
+
"%s1 units in stock": "%s1 units in stock",
|
|
229
|
+
"%s1 units in stock": "Stokta %s1 adet",
|
|
230
|
+
"Out of stock": "Out of stock",
|
|
231
|
+
"Out of stock": "Stokta yok",
|
|
232
|
+
"Add to Cart": "Add to Cart",
|
|
233
|
+
"Add to Cart": "Sepete Ekle"
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### Error Messages
|
|
238
|
+
|
|
239
|
+
```html
|
|
240
|
+
<candy:if condition="errors">
|
|
241
|
+
<div class="error-box">
|
|
242
|
+
<candy:if condition="errors.email">
|
|
243
|
+
<p><candy translate>Invalid email address</candy></p>
|
|
244
|
+
</candy:if>
|
|
245
|
+
|
|
246
|
+
<candy:if condition="errors.password">
|
|
247
|
+
<p><candy translate>Password must be at least 8 characters</candy></p>
|
|
248
|
+
</candy:if>
|
|
249
|
+
</div>
|
|
250
|
+
</candy:if>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Rich Text with HTML
|
|
254
|
+
|
|
255
|
+
```html
|
|
256
|
+
<div class="notice">
|
|
257
|
+
<candy translate raw>
|
|
258
|
+
By clicking "Register", you agree to our
|
|
259
|
+
<a href="/terms">Terms of Service</a> and
|
|
260
|
+
<a href="/privacy">Privacy Policy</a>.
|
|
261
|
+
</candy>
|
|
262
|
+
</div>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Locale file:**
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"By clicking \"Register\", you agree to our <a href=\"/terms\">Terms of Service</a> and <a href=\"/privacy\">Privacy Policy</a>.": "By clicking \"Register\", you agree to our <a href=\"/terms\">Terms of Service</a> and <a href=\"/privacy\">Privacy Policy</a>.",
|
|
269
|
+
"By clicking \"Register\", you agree to our <a href=\"/terms\">Terms of Service</a> and <a href=\"/privacy\">Privacy Policy</a>.": "\"Kayıt Ol\" butonuna tıklayarak <a href=\"/terms\">Hizmet Şartlarımızı</a> ve <a href=\"/privacy\">Gizlilik Politikamızı</a> kabul etmiş olursunuz."
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Setting the Language
|
|
274
|
+
|
|
275
|
+
The language is typically set based on user preference or browser settings. You can set it in your controller:
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
// Controller
|
|
279
|
+
module.exports = async function(Candy) {
|
|
280
|
+
// Set language from user preference
|
|
281
|
+
const userLang = Candy.Auth.check()
|
|
282
|
+
? Candy.Auth.user().language
|
|
283
|
+
: 'en'
|
|
284
|
+
|
|
285
|
+
Candy.Lang.setLanguage(userLang)
|
|
286
|
+
|
|
287
|
+
// Or from query parameter
|
|
288
|
+
const lang = Candy.Request.get('lang') || 'en'
|
|
289
|
+
Candy.Lang.setLanguage(lang)
|
|
290
|
+
|
|
291
|
+
Candy.View.skeleton('main').set('content', 'home')
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Using Translation Helper in Controllers
|
|
296
|
+
|
|
297
|
+
You can also use translations in your controllers:
|
|
298
|
+
|
|
299
|
+
```javascript
|
|
300
|
+
module.exports = async function(Candy) {
|
|
301
|
+
const message = Candy.__('Welcome back, %s!', user.name)
|
|
302
|
+
|
|
303
|
+
Candy.set('message', message)
|
|
304
|
+
Candy.View.skeleton('main').set('content', 'dashboard')
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Best Practices
|
|
309
|
+
|
|
310
|
+
1. **Use descriptive keys**: Make translation keys meaningful and context-aware
|
|
311
|
+
2. **Keep keys consistent**: Use the same key for the same text across your app
|
|
312
|
+
3. **Organize locale files**: Group related translations together
|
|
313
|
+
4. **Escape HTML carefully**: Only use `raw` with trusted content
|
|
314
|
+
5. **Test all languages**: Ensure translations work correctly in all supported languages
|
|
315
|
+
6. **Handle missing translations**: Provide fallback values
|
|
316
|
+
|
|
317
|
+
**Good locale structure:**
|
|
318
|
+
```json
|
|
319
|
+
{
|
|
320
|
+
"nav.home": "Home",
|
|
321
|
+
"nav.products": "Products",
|
|
322
|
+
"nav.about": "About",
|
|
323
|
+
"form.email": "Email Address",
|
|
324
|
+
"form.password": "Password",
|
|
325
|
+
"form.submit": "Submit",
|
|
326
|
+
"error.invalid_email": "Invalid email address",
|
|
327
|
+
"error.required_field": "This field is required"
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Security Warning:**
|
|
332
|
+
- Never use `raw` with user-generated content
|
|
333
|
+
- Always validate and sanitize user input before translation
|
|
334
|
+
- Be careful with HTML in translation strings
|
|
335
|
+
|
|
336
|
+
### Common Patterns
|
|
337
|
+
|
|
338
|
+
#### Pluralization
|
|
339
|
+
|
|
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>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
#### Date Formatting
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
// Controller
|
|
352
|
+
const formattedDate = new Date(date).toLocaleDateString(Candy.Lang.current())
|
|
353
|
+
Candy.set('date', formattedDate)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
```html
|
|
357
|
+
<p><candy translate>Last updated: <candy var="date" /></candy></p>
|
|
358
|
+
```
|