handlebars-i18n-cli 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.
- package/.travis.yml +15 -0
- package/LICENSE +21 -0
- package/README.md +253 -0
- package/bin/i18n-collect +4 -0
- package/examples/generated/translations.json +145 -0
- package/examples/templates/sample-template.html +363 -0
- package/package.json +49 -0
- package/src/i18n-collect.js +561 -0
- package/test/handlebars-i18n-cli.test.js +174 -0
- package/test/test-assets/custom-func.html +10 -0
- package/test/test-assets/empty.html +9 -0
- package/test/test-assets/multiple.html +12 -0
- package/test/test-assets/simple.html +10 -0
- package/test/test-generated/test-12.json +8 -0
package/.travis.yml
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Florian Walzel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# handlebars-i18n-cli
|
|
2
|
+
|
|
3
|
+
`handlebars-i18n-cli` is an additional command line interface for [handlebars-i18n](https://github.com/fwalzel/handlebars-i18n.git).
|
|
4
|
+
It will help to automatically extract translation strings from your handlebars templates and generate i18next conform
|
|
5
|
+
json files from it. It also helps to keep your translations up to date when changes are made in the templates.
|
|
6
|
+
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2022 Florian Walzel,
|
|
13
|
+
MIT License
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
$ npm i handlebars-i18n-cli
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
Abstract syntax is:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
i18n-collect <source> <target> <options...>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This will generate a file `translations.json` holding the translations for `de`, `fr`, and `en` by extracting all key names intended for i18next translation from all html files in your project:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
$ i18n-collect my-project/**/*.html my-project/translations.json --lng=de,en,fr
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
From a very simple template like this …
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<!DOCTYPE html>
|
|
41
|
+
<html lang="{{_locale}}">
|
|
42
|
+
<head>
|
|
43
|
+
<title>{{__ title}}</title>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
{{__ body.greeting textvar1="hello" textvar2="world"}}
|
|
47
|
+
</body>
|
|
48
|
+
</html>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
… the generated translations.json would be:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"translations": {
|
|
56
|
+
"de": {
|
|
57
|
+
"title": "de of title",
|
|
58
|
+
"body": {
|
|
59
|
+
"greeting": "de of body.greeting with variables {{textvar1}} {{textvar2}}"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"en": {
|
|
63
|
+
"title": "en of title",
|
|
64
|
+
"body": {
|
|
65
|
+
"greeting": "en of body.greeting with variables {{textvar1}} {{textvar2}}"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"fr": {
|
|
69
|
+
"title": "fr of title",
|
|
70
|
+
"body": {
|
|
71
|
+
"greeting": "fr of body.greeting with variables {{textvar1}} {{textvar2}}"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Motivation
|
|
79
|
+
|
|
80
|
+
Managing large volumes of translations can be a tedious and time-consuming task, for each change in the template needs
|
|
81
|
+
to be mapped to all languages. Usually this comes along with a lot of redundant typing or copy/paste action. Furthermore
|
|
82
|
+
the chance of missing some translation strings increases with many translations in play.
|
|
83
|
+
|
|
84
|
+
`handlebars-i18n-cli` automates the task of extracting and updating key names indicating translation strings and
|
|
85
|
+
generating template JSON files from them. The key names for the translations need to specified only once in the template,
|
|
86
|
+
the carry to the according language JSON is done by the CLI. You then only have to fill in according translations.
|
|
87
|
+
In case a translation string expects variables for replacement, these variables will be added to your json template.
|
|
88
|
+
|
|
89
|
+
If you are not using [handlebars-i18n](https://github.com/fwalzel/handlebars-i18n.git) for translation but a custom
|
|
90
|
+
integration of i18next into handlebars.js, you might be able to appropriate this cli by using the option --translFunc (see below).
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
## Example
|
|
94
|
+
|
|
95
|
+
Try the examples folder within this repo.
|
|
96
|
+
|
|
97
|
+
For generating a single JSON file:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
$ i18n-collect examples/templates/*.html examples/generated/translations.json --lng=de,fr,en
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
For one JSON file per language:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
$ i18n-collect examples/templates/*.html examples/generated/translations.json --separateLngFiles --lng=de,fr,en
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
## Source and Target
|
|
111
|
+
|
|
112
|
+
`<source>`
|
|
113
|
+
|
|
114
|
+
* The source files can be passed in as [glob](https://www.npmjs.com/package/glob) pattern.
|
|
115
|
+
* i18n-collect is agnostic against the data type of the template(s) you want to extract translations keys from. It works with `.html` as well as `.js` files.
|
|
116
|
+
|
|
117
|
+
`<target>`
|
|
118
|
+
|
|
119
|
+
* The output will always be in `.json` format. The file(s) can then be required for your i18next translation as [JSON v2](https://www.i18next.com/misc/json-format#i18next-json-v2)
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
i18next.init({
|
|
123
|
+
compatibilityJSON: 'v2'
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
## Usage options
|
|
129
|
+
|
|
130
|
+
`--alphabetical` or `-a`
|
|
131
|
+
|
|
132
|
+
This will order the keys to the translation strings alphabetically in the generated json file(s). When the flag
|
|
133
|
+
--alphabetical is not set the keys appear in order as within the template(s).
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
`--dryRun` or `-dr`
|
|
138
|
+
|
|
139
|
+
For simulation: Logs the result to console, but does not write out the file(s) to disk.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
`--empty` or `-e`
|
|
144
|
+
|
|
145
|
+
Create empty value strings for the translations in the json files(s). When the flag --empty is not set the
|
|
146
|
+
value strings contain current language and key name.
|
|
147
|
+
|
|
148
|
+
Example:
|
|
149
|
+
|
|
150
|
+
The template
|
|
151
|
+
|
|
152
|
+
```html
|
|
153
|
+
<h1>{{__ headline userName="Frank"}}</h1>
|
|
154
|
+
<p>{{__ paragraph}}</p>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
would become
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"translations": {
|
|
162
|
+
"en": {
|
|
163
|
+
"headline": "{{userName}}",
|
|
164
|
+
"paragraph": ""
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
instead of
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"translations": {
|
|
175
|
+
"en": {
|
|
176
|
+
"headline": "en of headline with variables {{userName}}",
|
|
177
|
+
"paragraph": "en of paragraph"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
`--lng=language1,language2,...languageN`
|
|
186
|
+
|
|
187
|
+
The list of language shortcodes you want to be generated with an own set in the json. Arguments are comma separated (no blank space between, no quotation marks around).
|
|
188
|
+
If no language is defined, "en" is the default.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
`--log` or `-l`
|
|
193
|
+
|
|
194
|
+
Logs the final result that is written to the json files(s) into the console as well.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
`--separateLngFiles` or `-sf`
|
|
199
|
+
|
|
200
|
+
Write each language in a separate json file instead of a single one.
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
$ i18n-collect my-project/template.html my-project/translation.json --lng=de,en,fr --separateLngFiles
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Will generate three json files: **translation.de.json**, **translation.en.json**, and **translation.en.json** each holding
|
|
207
|
+
only the translation for their respective language. By default all translations are written to a single json file.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
`--translFunc=yourCustomFunctionName`
|
|
212
|
+
|
|
213
|
+
If you are not using handlebars-i18n for translations but a custom handlebars helper, you might be able to use
|
|
214
|
+
i18n-collect as well.Say your translation function has the name *t* instead of handlebars-i18n’s *__* (double underscore)
|
|
215
|
+
and your template usage would look like
|
|
216
|
+
|
|
217
|
+
```html
|
|
218
|
+
{{t myKeyNameToTranslation}}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
you can do
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
$ i18n-collect my-project/template.html my-project/translation.json --translFunc=t
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
--translFunc=t then substitutes the default *__* with a search for t.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
`--update` or `-u`
|
|
232
|
+
|
|
233
|
+
Update an existing .json file with new translations. All keys in the existing .json are kept, new ones from the template
|
|
234
|
+
will be added.
|
|
235
|
+
|
|
236
|
+
Works also with the option --separateLngFiles:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
$ i18n-collect my-project/**/*.html my-project/translation --update --lng=de,en,fr --separateLngFiles
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Leave out the language ending and json file extension and give only the base name for <target>. In this example case handlebars-i18n-cli would look for *translation.de.json*, *translation.en.json*, and *translation.en.json* to update them. A language file that does not exist yet will be generated.
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
## Run tests
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
$ npm test
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
package/bin/i18n-collect
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
{
|
|
2
|
+
"translations": {
|
|
3
|
+
"de": {
|
|
4
|
+
"Sample_invoice_title": "de of Sample_invoice_title",
|
|
5
|
+
"Company_slogan": "de of Company_slogan",
|
|
6
|
+
"Mr": "de of Mr",
|
|
7
|
+
"Ms": "de of Ms",
|
|
8
|
+
"Confirmation": {
|
|
9
|
+
"Delivery_Address": "de of Confirmation.Delivery_Address",
|
|
10
|
+
"Order_confirmation": "de of Confirmation.Order_confirmation",
|
|
11
|
+
"Intro_statement": "de of Confirmation.Intro_statement with variables {{refLetterId}} {{refLetterDate}}",
|
|
12
|
+
"NoVat_requires_TaxId": "de of Confirmation.NoVat_requires_TaxId",
|
|
13
|
+
"General_Sale_and_Delivery_Terms": "de of Confirmation.General_Sale_and_Delivery_Terms with variables {{webAgb}}"
|
|
14
|
+
},
|
|
15
|
+
"Project_no": "de of Project_no",
|
|
16
|
+
"Receipt_no": "de of Receipt_no",
|
|
17
|
+
"Your_customer_no": "de of Your_customer_no",
|
|
18
|
+
"Contact_partner": "de of Contact_partner",
|
|
19
|
+
"Telephone": "de of Telephone",
|
|
20
|
+
"E-mail": "de of E-mail",
|
|
21
|
+
"Date_accepted": "de of Date_accepted",
|
|
22
|
+
"Your_enquiry_no": "de of Your_enquiry_no",
|
|
23
|
+
"Supplier_no": "de of Supplier_no",
|
|
24
|
+
"Order_no": "de of Order_no",
|
|
25
|
+
"Dear_Ladies_and_Gentlemen": "de of Dear_Ladies_and_Gentlemen",
|
|
26
|
+
"Dear_Mr": "de of Dear_Mr",
|
|
27
|
+
"Dear_Ms": "de of Dear_Ms",
|
|
28
|
+
"Item": "de of Item",
|
|
29
|
+
"Description": "de of Description",
|
|
30
|
+
"Material": "de of Material",
|
|
31
|
+
"Quantity": "de of Quantity",
|
|
32
|
+
"UnitPrice": "de of UnitPrice",
|
|
33
|
+
"Total": "de of Total",
|
|
34
|
+
"Carry": "de of Carry",
|
|
35
|
+
"Subtotal": "de of Subtotal",
|
|
36
|
+
"Surcharge": "de of Surcharge",
|
|
37
|
+
"Discount": "de of Discount",
|
|
38
|
+
"Net_price": "de of Net_price",
|
|
39
|
+
"VAT": "de of VAT",
|
|
40
|
+
"Total_price": "de of Total_price",
|
|
41
|
+
"Your_conditions": "de of Your_conditions",
|
|
42
|
+
"Delivery_time": "de of Delivery_time",
|
|
43
|
+
"Delivery_date": "de of Delivery_date",
|
|
44
|
+
"Shipping_terms": "de of Shipping_terms",
|
|
45
|
+
"Payment_terms": "de of Payment_terms",
|
|
46
|
+
"Special_remarks": "de of Special_remarks",
|
|
47
|
+
"Should_you_have_questions": "de of Should_you_have_questions with variables {{telHref}} {{phone}}",
|
|
48
|
+
"Kind_regards": "de of Kind_regards"
|
|
49
|
+
},
|
|
50
|
+
"fr": {
|
|
51
|
+
"Sample_invoice_title": "fr of Sample_invoice_title",
|
|
52
|
+
"Company_slogan": "fr of Company_slogan",
|
|
53
|
+
"Mr": "fr of Mr",
|
|
54
|
+
"Ms": "fr of Ms",
|
|
55
|
+
"Confirmation": {
|
|
56
|
+
"Delivery_Address": "fr of Confirmation.Delivery_Address",
|
|
57
|
+
"Order_confirmation": "fr of Confirmation.Order_confirmation",
|
|
58
|
+
"Intro_statement": "fr of Confirmation.Intro_statement with variables {{refLetterId}} {{refLetterDate}}",
|
|
59
|
+
"NoVat_requires_TaxId": "fr of Confirmation.NoVat_requires_TaxId",
|
|
60
|
+
"General_Sale_and_Delivery_Terms": "fr of Confirmation.General_Sale_and_Delivery_Terms with variables {{webAgb}}"
|
|
61
|
+
},
|
|
62
|
+
"Project_no": "fr of Project_no",
|
|
63
|
+
"Receipt_no": "fr of Receipt_no",
|
|
64
|
+
"Your_customer_no": "fr of Your_customer_no",
|
|
65
|
+
"Contact_partner": "fr of Contact_partner",
|
|
66
|
+
"Telephone": "fr of Telephone",
|
|
67
|
+
"E-mail": "fr of E-mail",
|
|
68
|
+
"Date_accepted": "fr of Date_accepted",
|
|
69
|
+
"Your_enquiry_no": "fr of Your_enquiry_no",
|
|
70
|
+
"Supplier_no": "fr of Supplier_no",
|
|
71
|
+
"Order_no": "fr of Order_no",
|
|
72
|
+
"Dear_Ladies_and_Gentlemen": "fr of Dear_Ladies_and_Gentlemen",
|
|
73
|
+
"Dear_Mr": "fr of Dear_Mr",
|
|
74
|
+
"Dear_Ms": "fr of Dear_Ms",
|
|
75
|
+
"Item": "fr of Item",
|
|
76
|
+
"Description": "fr of Description",
|
|
77
|
+
"Material": "fr of Material",
|
|
78
|
+
"Quantity": "fr of Quantity",
|
|
79
|
+
"UnitPrice": "fr of UnitPrice",
|
|
80
|
+
"Total": "fr of Total",
|
|
81
|
+
"Carry": "fr of Carry",
|
|
82
|
+
"Subtotal": "fr of Subtotal",
|
|
83
|
+
"Surcharge": "fr of Surcharge",
|
|
84
|
+
"Discount": "fr of Discount",
|
|
85
|
+
"Net_price": "fr of Net_price",
|
|
86
|
+
"VAT": "fr of VAT",
|
|
87
|
+
"Total_price": "fr of Total_price",
|
|
88
|
+
"Your_conditions": "fr of Your_conditions",
|
|
89
|
+
"Delivery_time": "fr of Delivery_time",
|
|
90
|
+
"Delivery_date": "fr of Delivery_date",
|
|
91
|
+
"Shipping_terms": "fr of Shipping_terms",
|
|
92
|
+
"Payment_terms": "fr of Payment_terms",
|
|
93
|
+
"Special_remarks": "fr of Special_remarks",
|
|
94
|
+
"Should_you_have_questions": "fr of Should_you_have_questions with variables {{telHref}} {{phone}}",
|
|
95
|
+
"Kind_regards": "fr of Kind_regards"
|
|
96
|
+
},
|
|
97
|
+
"en": {
|
|
98
|
+
"Sample_invoice_title": "en of Sample_invoice_title",
|
|
99
|
+
"Company_slogan": "en of Company_slogan",
|
|
100
|
+
"Mr": "en of Mr",
|
|
101
|
+
"Ms": "en of Ms",
|
|
102
|
+
"Confirmation": {
|
|
103
|
+
"Delivery_Address": "en of Confirmation.Delivery_Address",
|
|
104
|
+
"Order_confirmation": "en of Confirmation.Order_confirmation",
|
|
105
|
+
"Intro_statement": "en of Confirmation.Intro_statement with variables {{refLetterId}} {{refLetterDate}}",
|
|
106
|
+
"NoVat_requires_TaxId": "en of Confirmation.NoVat_requires_TaxId",
|
|
107
|
+
"General_Sale_and_Delivery_Terms": "en of Confirmation.General_Sale_and_Delivery_Terms with variables {{webAgb}}"
|
|
108
|
+
},
|
|
109
|
+
"Project_no": "en of Project_no",
|
|
110
|
+
"Receipt_no": "en of Receipt_no",
|
|
111
|
+
"Your_customer_no": "en of Your_customer_no",
|
|
112
|
+
"Contact_partner": "en of Contact_partner",
|
|
113
|
+
"Telephone": "en of Telephone",
|
|
114
|
+
"E-mail": "en of E-mail",
|
|
115
|
+
"Date_accepted": "en of Date_accepted",
|
|
116
|
+
"Your_enquiry_no": "en of Your_enquiry_no",
|
|
117
|
+
"Supplier_no": "en of Supplier_no",
|
|
118
|
+
"Order_no": "en of Order_no",
|
|
119
|
+
"Dear_Ladies_and_Gentlemen": "en of Dear_Ladies_and_Gentlemen",
|
|
120
|
+
"Dear_Mr": "en of Dear_Mr",
|
|
121
|
+
"Dear_Ms": "en of Dear_Ms",
|
|
122
|
+
"Item": "en of Item",
|
|
123
|
+
"Description": "en of Description",
|
|
124
|
+
"Material": "en of Material",
|
|
125
|
+
"Quantity": "en of Quantity",
|
|
126
|
+
"UnitPrice": "en of UnitPrice",
|
|
127
|
+
"Total": "en of Total",
|
|
128
|
+
"Carry": "en of Carry",
|
|
129
|
+
"Subtotal": "en of Subtotal",
|
|
130
|
+
"Surcharge": "en of Surcharge",
|
|
131
|
+
"Discount": "en of Discount",
|
|
132
|
+
"Net_price": "en of Net_price",
|
|
133
|
+
"VAT": "en of VAT",
|
|
134
|
+
"Total_price": "en of Total_price",
|
|
135
|
+
"Your_conditions": "en of Your_conditions",
|
|
136
|
+
"Delivery_time": "en of Delivery_time",
|
|
137
|
+
"Delivery_date": "en of Delivery_date",
|
|
138
|
+
"Shipping_terms": "en of Shipping_terms",
|
|
139
|
+
"Payment_terms": "en of Payment_terms",
|
|
140
|
+
"Special_remarks": "en of Special_remarks",
|
|
141
|
+
"Should_you_have_questions": "en of Should_you_have_questions with variables {{telHref}} {{phone}}",
|
|
142
|
+
"Kind_regards": "en of Kind_regards"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|