homey-lib 2.25.0 → 2.26.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.
@@ -0,0 +1,57 @@
1
+ name: Apply Locales
2
+
3
+ # About this workflow:
4
+ # It is triggered on created pull_requests with changes in the "generated_locales" folder. It will apply the locale files from the "generated_locales" folder and commit the changes to the repository.
5
+
6
+ # GitHub repo configuration:
7
+ # 1. Go to Manage access and add 'Github Actions' team with role: admin.
8
+ # 2. If you have protected branches, go to Branches > edit protected branch > enable 'Restrict who can push to
9
+ # matching branches' and add the 'athombv/github-actions' team.
10
+
11
+ # Note: make sure to commit package-lock.json, this is needed for `npm ci`.
12
+
13
+ on:
14
+ pull_request:
15
+ paths:
16
+ - "generated_locales/**"
17
+
18
+ jobs:
19
+ apply_locales:
20
+ name: Apply Locales
21
+
22
+ # Only run this job if initiator is not the Homey Github Actions Bot to prevent loops
23
+ if: github.actor != 'homey-bot'
24
+
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ # Checks out the current repository.
28
+ - name: Checkout git repository
29
+ uses: actions/checkout@v3
30
+ with:
31
+ # The token below is only necessary if you want to push the version bump to a protected branch
32
+ token: ${{ secrets.HOMEY_GITHUB_ACTIONS_BOT_PERSONAL_ACCESS_TOKEN }}
33
+ ref: ${{ github.event.pull_request.head.ref }}
34
+
35
+ # Set git config to reflect Homey Github Actions Bot user
36
+ - name: Set up HomeyGithubActionsBot git user
37
+ run: |
38
+ git config --local user.email "sysadmin+githubactions@athom.com"
39
+ git config --local user.name "Homey Github Actions Bot"
40
+
41
+ # Configures a Node.js environment.
42
+ - name: Set up node 12 environment
43
+ uses: actions/setup-node@v1
44
+ with:
45
+ node-version: "12"
46
+
47
+ - name: Install dependencies
48
+ run: npm ci
49
+
50
+ - name: Apply Locales
51
+ run: node ./scripts/apply-locale-files.js
52
+
53
+ - name: Commit and push applied locales
54
+ run: |
55
+ git add . || echo "No changes due to applying locales."
56
+ git commit -m "ci: applied locales" || echo "No changes to commit."
57
+ git push origin HEAD:${{ github.event.pull_request.head.ref }}
@@ -0,0 +1,60 @@
1
+ name: Generate Locales
2
+
3
+ # About this workflow:
4
+ # It is triggered on push events to master and develop with changes in the "assets" folder. It will generate locale files from the assets and commit the changes to the repository.
5
+
6
+ # GitHub repo configuration:
7
+ # 1. Go to Manage access and add 'Github Actions' team with role: admin.
8
+ # 2. If you have protected branches, go to Branches > edit protected branch > enable 'Restrict who can push to
9
+ # matching branches' and add the 'athombv/github-actions' team.
10
+
11
+ # Note: make sure to commit package-lock.json, this is needed for `npm ci`.
12
+
13
+ on:
14
+ workflow_dispatch:
15
+ push:
16
+ branches:
17
+ - "master"
18
+ - "develop"
19
+ paths:
20
+ - "assets/**"
21
+
22
+ jobs:
23
+ generate_locales:
24
+ name: Generate Locales
25
+
26
+ # Only run this job if initiator is not the Homey Github Actions Bot to prevent loops
27
+ if: github.actor != 'homey-bot'
28
+
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ # Checks out the current repository.
32
+ - name: Checkout git repository
33
+ uses: actions/checkout@v3
34
+ with:
35
+ # The token below is only necessary if you want to push the version bump to a protected branch
36
+ token: ${{ secrets.HOMEY_GITHUB_ACTIONS_BOT_PERSONAL_ACCESS_TOKEN }}
37
+
38
+ # Set git config to reflect Homey Github Actions Bot user
39
+ - name: Set up HomeyGithubActionsBot git user
40
+ run: |
41
+ git config --local user.email "sysadmin+githubactions@athom.com"
42
+ git config --local user.name "Homey Github Actions Bot"
43
+
44
+ # Configures a Node.js environment.
45
+ - name: Set up node 12 environment
46
+ uses: actions/setup-node@v1
47
+ with:
48
+ node-version: "12"
49
+
50
+ - name: Install dependencies
51
+ run: npm ci
52
+
53
+ - name: Generate Locales
54
+ run: node ./scripts/generate-locale-files.js
55
+
56
+ - name: Commit and push generated locales
57
+ run: |
58
+ git add . || echo "No changes due to generated locales."
59
+ git commit -m "ci: generated locales" || echo "No changes to commit."
60
+ git push
package/.idea/misc.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="JavaScriptSettings">
4
+ <option name="languageLevel" value="ES6" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/node-homey-lib.iml" filepath="$PROJECT_DIR$/.idea/node-homey-lib.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="WEB_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/.tmp" />
6
+ <excludeFolder url="file://$MODULE_DIR$/temp" />
7
+ <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
+ </content>
9
+ <orderEntry type="inheritedJdk" />
10
+ <orderEntry type="sourceFolder" forTests="false" />
11
+ </component>
12
+ </module>
package/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
package/README.md CHANGED
@@ -18,3 +18,14 @@ This library can, among other things:
18
18
 
19
19
 
20
20
  See `/examples/` for how-to usage.
21
+
22
+ ## Translations
23
+
24
+ This library contains translations in the following files:
25
+ - `./assets/app/permissions.json`
26
+ - `./assets/capability/capabilities/<capability_id>.json`
27
+ - `./assets/device/classes/<device_class_id>.json`
28
+
29
+ These files are automatically parsed to language specific locale files in `./generated_locales`. The generated locales should not be edited manually, always edit the original files as listed above. Commits to master or develop with changes to the files above will trigger a [GitHub Action](.github/workflows/generate_locales.yml) that [re-generates](scripts/generate-locale-files.js) the locales and commits the result. Incoming PRs with changes to `./generated_locales` will trigger a [GitHub Action](.github/workflows/apply_locales.yml) that [applies](scripts/apply-locale-files.js) the updated generated locales to the files listed above.
30
+
31
+ > Note: when adding new languages to the files listed above, make sure to add the `./generated_locales/<new_language_code>.json` file manually so that the [script that generates the locales](scripts/generate-locale-files.js) will pick it up.
@@ -561,6 +561,12 @@
561
561
  "pattern": {
562
562
  "type": "string"
563
563
  },
564
+ "highlight": {
565
+ "type": "boolean",
566
+ "enum": [
567
+ true
568
+ ]
569
+ },
564
570
  "zwave": {
565
571
  "$ref": "#/definitions/zwaveSetting"
566
572
  }
@@ -618,6 +624,12 @@
618
624
  }
619
625
  }
620
626
  },
627
+ "highlight": {
628
+ "type": "boolean",
629
+ "enum": [
630
+ true
631
+ ]
632
+ },
621
633
  "zwave": {
622
634
  "$ref": "#/definitions/zwaveSetting"
623
635
  }
@@ -676,6 +688,12 @@
676
688
  }
677
689
  }
678
690
  },
691
+ "highlight": {
692
+ "type": "boolean",
693
+ "enum": [
694
+ true
695
+ ]
696
+ },
679
697
  "zwave": {
680
698
  "$ref": "#/definitions/zwaveSetting"
681
699
  }
@@ -714,6 +732,12 @@
714
732
  "value": {
715
733
  "type": "boolean"
716
734
  },
735
+ "highlight": {
736
+ "type": "boolean",
737
+ "enum": [
738
+ true
739
+ ]
740
+ },
717
741
  "zwave": {
718
742
  "$ref": "#/definitions/zwaveSetting"
719
743
  }
@@ -739,6 +763,12 @@
739
763
  "children": {
740
764
  "$ref": "#/definitions/driverSettings"
741
765
  },
766
+ "highlight": {
767
+ "type": "boolean",
768
+ "enum": [
769
+ true
770
+ ]
771
+ },
742
772
  "zwave": {
743
773
  "$ref": "#/definitions/zwaveSetting"
744
774
  }
@@ -749,7 +779,10 @@
749
779
  },
750
780
  "matterDevice": {
751
781
  "type": "object",
752
- "required": ["vendorId", "productId"],
782
+ "required": [
783
+ "vendorId",
784
+ "productId"
785
+ ],
753
786
  "properties": {
754
787
  "vendorId": {
755
788
  "oneOf": [
@@ -837,8 +870,10 @@
837
870
  },
838
871
  "zigbeeDevice": {
839
872
  "type": "object",
840
- "required": [
841
- "manufacturerName", "productId", "endpoints"
873
+ "required": [
874
+ "manufacturerName",
875
+ "productId",
876
+ "endpoints"
842
877
  ],
843
878
  "properties": {
844
879
  "manufacturerName": {
@@ -875,20 +910,20 @@
875
910
  },
876
911
  "additionalProperties": {
877
912
  "type": "object",
878
- "additionalProperties": false,
879
- "properties": {
880
- "clusters": {
881
- "type": "array",
882
- "items": {
883
- "type": "number"
884
- }
885
- },
886
- "bindings": {
887
- "type": "array",
888
- "items": {
889
- "type": "number"
890
- }
913
+ "additionalProperties": false,
914
+ "properties": {
915
+ "clusters": {
916
+ "type": "array",
917
+ "items": {
918
+ "type": "number"
919
+ }
920
+ },
921
+ "bindings": {
922
+ "type": "array",
923
+ "items": {
924
+ "type": "number"
891
925
  }
926
+ }
892
927
  }
893
928
  }
894
929
  },
@@ -12,7 +12,6 @@
12
12
  "da": "Røgalarm",
13
13
  "ru": "Сигнал дыма",
14
14
  "pl": "Alarm przeciwdymny"
15
-
16
15
  },
17
16
  "desc": {
18
17
  "en": "True when smoke has been detected",
@@ -26,7 +25,6 @@
26
25
  "da": "Sandt, når røg er blevet opdaget",
27
26
  "ru": "Верно при обнаружении дыма",
28
27
  "pl": "Adekwatny, kiedy wykryty zostanie dym"
29
-
30
28
  },
31
29
  "insights": true,
32
30
  "insightsTitleTrue": {
@@ -41,7 +39,6 @@
41
39
  "da": "Røgalarm blev aktiveret",
42
40
  "ru": "Сигнал дыма включен",
43
41
  "pl": "Alarm przeciwdymny włączony"
44
-
45
42
  },
46
43
  "insightsTitleFalse": {
47
44
  "en": "Smoke alarm turned off",
@@ -55,7 +52,6 @@
55
52
  "da": "Røgalarm blev deaktiveret",
56
53
  "ru": "Сигнал дыма выключен",
57
54
  "pl": "Alarm przeciwdymny wyłączony"
58
-
59
55
  },
60
56
  "getable": true,
61
57
  "setable": false,
@@ -77,7 +73,6 @@
77
73
  "da": "Røgalarmen blev aktiveret",
78
74
  "ru": "Сигнал дыма включен",
79
75
  "pl": "Alarm przeciwdymny włączony"
80
-
81
76
  }
82
77
  },
83
78
  {
@@ -94,7 +89,6 @@
94
89
  "da": "Røgalarmen blev deaktiveret",
95
90
  "ru": "Сигнал дыма выключен",
96
91
  "pl": "Alarm przeciwdymny wyłączony"
97
-
98
92
  }
99
93
  }
100
94
  ],
@@ -113,7 +107,6 @@
113
107
  "da": "Røgalarmen er !{{tændt|slukket}}",
114
108
  "ru": "Сигнал дыма !{{вкл.|выкл.}}",
115
109
  "pl": "Alarm przeciwdymny !{{włączony|wyłączony}}"
116
-
117
110
  }
118
111
  }
119
112
  ]
@@ -149,4 +149,4 @@
149
149
  }
150
150
  ]
151
151
  }
152
- }
152
+ }
@@ -12,7 +12,6 @@
12
12
  "da": "Lystilstand",
13
13
  "ru": "Режим света",
14
14
  "pl": "Tryb oświetlenia"
15
-
16
15
  },
17
16
  "desc": {
18
17
  "en": "Switch between color or temperature mode",
@@ -26,7 +25,6 @@
26
25
  "da": "Skift mellem farve- eller temperaturtilstand",
27
26
  "ru": "Переключение между цветовым или температурным режимом",
28
27
  "pl": "Przełączaj między trybem barwy lub temperatury"
29
-
30
28
  },
31
29
  "values": [
32
30
  {
@@ -43,7 +41,6 @@
43
41
  "da": "Farve",
44
42
  "ru": "Цвет",
45
43
  "pl": "Barwa"
46
-
47
44
  }
48
45
  },
49
46
  {
@@ -60,7 +57,6 @@
60
57
  "da": "Temperatur",
61
58
  "ru": "Температура",
62
59
  "pl": "Temperatura"
63
-
64
60
  }
65
61
  }
66
62
  ],
@@ -12,7 +12,6 @@
12
12
  "da": "Farvemætning",
13
13
  "ru": "Насыщенность цвета",
14
14
  "pl": "Nasycenie barwy"
15
-
16
15
  },
17
16
  "min": 0,
18
17
  "chartType": "stepLine",
@@ -36,7 +35,6 @@
36
35
  "da": "Indstil farvemætningen",
37
36
  "ru": "Установить насыщенность",
38
37
  "pl": "Ustaw nasycenie"
39
-
40
38
  },
41
39
  "args": [
42
40
  {
@@ -12,7 +12,6 @@
12
12
  "da": "Vindretning",
13
13
  "ru": "Угол порывов ветра",
14
14
  "pl": "Kąt porywu wiatru"
15
-
16
15
  },
17
16
  "units": {
18
17
  "en": "°"
@@ -30,7 +29,6 @@
30
29
  "da": "Vindretning i grader (°)",
31
30
  "ru": "Угол порывов ветра в градусах (°)",
32
31
  "pl": "Kąt porywu wiatru w stopniach (°)"
33
-
34
32
  },
35
33
  "chartType": "stepLine",
36
34
  "decimals": 2,
@@ -64,4 +64,4 @@
64
64
  }
65
65
  ]
66
66
  }
67
- }
67
+ }
@@ -243,4 +243,4 @@
243
243
  }
244
244
  ]
245
245
  }
246
- }
246
+ }
@@ -24,4 +24,4 @@
24
24
  "ru": "Используйте этот класс устройств для кофемашин.",
25
25
  "pl": "Użyj tej klasy urządzeń dla ekspresów do kawy."
26
26
  }
27
- }
27
+ }
@@ -11,12 +11,10 @@
11
11
  "da": "Garageport",
12
12
  "ru": "Дверь гаража",
13
13
  "pl": "Brama garażowa"
14
-
15
14
  },
16
15
  "description": {
17
16
  "en": "Use this device class for garage doors, usually together with the `garagedoor_closed` capability.",
18
17
  "ru": "Используйте этот класс устройств для дверей гаража, обычно вместе с функцией `garagedoor_closed`.",
19
18
  "pl": "Użyj tej klasy urządzeń dla bram garażowych, zwykle razem ze zdolnością „garagedoor_closed”."
20
-
21
19
  }
22
20
  }
@@ -11,7 +11,6 @@
11
11
  "da": "Lys",
12
12
  "ru": "Лампа",
13
13
  "pl": "Oświetlenie"
14
-
15
14
  },
16
15
  "description": {
17
16
  "en": "Use this device class for lights, usually together with the `onoff`, `dim` and `light_*` capabilities.",
@@ -24,6 +23,5 @@
24
23
  "da": "Brug denne enhedsklasse til lys, normalt sammen med `onoff`, `dim` og `light_*` funktionerne.",
25
24
  "ru": "Используйте этот класс устройств для ламп, обычно вместе с функциями `onoff`,`dim` и `light_ *`.",
26
25
  "pl": "Użyj tej klasy urządzeń dla oświetlenia, zwykle razem ze zdolnościami `onoff`, `dim` oraz `light_*`."
27
-
28
26
  }
29
27
  }
@@ -11,7 +11,6 @@
11
11
  "da": "Relæ",
12
12
  "ru": "Узел",
13
13
  "pl": "Przekaźnik"
14
-
15
14
  },
16
15
  "description": {
17
16
  "en": "Use this device class for relays, which are connected to another device.",
@@ -24,7 +23,6 @@
24
23
  "da": "Brug denne enhedsklasse til relæer, som er koblet til en anden enhed.",
25
24
  "ru": "Используйте этот класс устройств для узлов, которые подключены к другому устройству.",
26
25
  "pl": "Użyj tej klasy urządzeń dla przekaźników niepołączonych z żadnym innym urządzeniem."
27
-
28
26
  },
29
27
  "virtualTitle": {
30
28
  "en": "What's connected?",
@@ -38,7 +36,6 @@
38
36
  "da": "Hvad er tilkoblet?",
39
37
  "ru": "Что подключено?",
40
38
  "pl": "Co jest połączone?"
41
-
42
39
  },
43
40
  "allowedVirtual": [
44
41
  "garagedoor",
@@ -8,7 +8,6 @@
8
8
  "da": "Solpanel",
9
9
  "ru": "Солнечная панель",
10
10
  "pl": "Panel fotowoltaiczny"
11
-
12
11
  },
13
12
  "description": {
14
13
  "en": "Use this device class for solar panels.",
@@ -16,6 +15,5 @@
16
15
  "da": "Brug denne enhedsklasse til solpaneler.",
17
16
  "ru": "Используйте этот класс устройств для солнечных панелей.",
18
17
  "pl": "Użyj tej klasy urządzeń dla paneli fotowoltaicznych."
19
-
20
18
  }
21
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homey-lib",
3
- "version": "2.25.0",
3
+ "version": "2.26.0",
4
4
  "description": "Shared Library for Homey",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -33,6 +33,7 @@
33
33
  "eslint-config-athom": "^2.1.1",
34
34
  "mocha": "^9.1.3",
35
35
  "mock-fs": "^5.1.2",
36
+ "object-path": "^0.11.8",
36
37
  "set-value": "^4.1.0",
37
38
  "webpack": "^4.46.0",
38
39
  "webpack-cli": "^4.7.2"
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const objectPath = require('object-path');
7
+
8
+ const ROOT_DIR = path.join(__dirname, '..');
9
+ const INPUT_DIR = path.join(ROOT_DIR, 'generated_locales');
10
+
11
+ console.log(
12
+ `Applying locales from ${INPUT_DIR}...`,
13
+ );
14
+
15
+ // Loop through all input files
16
+ fs.readdirSync(INPUT_DIR).forEach(inputFile => {
17
+ const localePath = path.join(INPUT_DIR, inputFile);
18
+ const locale = inputFile.split('.')[0];
19
+ if (fs.existsSync(localePath)) {
20
+ const localeContent = JSON.parse(fs.readFileSync(localePath, 'utf8'));
21
+ delete localeContent.__comment;
22
+ Object.entries(localeContent).forEach(([key, value]) => {
23
+ // Split file path and translation key
24
+ const [sourceFilePath, translationPath] = key.split('@');
25
+
26
+ // Read original content of file
27
+ const originalContent = JSON.parse(
28
+ fs.readFileSync(sourceFilePath, 'utf8'),
29
+ );
30
+
31
+ // Apply translation to original content
32
+ objectPath.set(originalContent, `${translationPath}.${locale}`, value);
33
+
34
+ // Write updated content back to file
35
+ fs.writeFileSync(
36
+ sourceFilePath,
37
+ JSON.stringify(originalContent, null, 2),
38
+ );
39
+ });
40
+ }
41
+ console.log(`Applied locale ${localePath}`);
42
+ });
43
+ console.log('Done applying locales.');
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const ROOT_DIR = path.join(__dirname, '..');
7
+ const OUTPUT_DIR = path.join(ROOT_DIR, 'generated_locales'); // Directory where you want to save the translations
8
+ const ASSETS_PATH = path.join(ROOT_DIR, 'assets'); // Path to the assets directory
9
+
10
+ // Loop through all input files
11
+ const availableLocales = fs.readdirSync(OUTPUT_DIR).map(outputFile => {
12
+ return outputFile.split('.')[0];
13
+ });
14
+
15
+ // Function to recursively traverse the JSON object and extract translations
16
+ function extractTranslations(
17
+ sourceFilePath,
18
+ obj,
19
+ currentPath = '',
20
+ translations = {},
21
+ ) {
22
+ Object.entries(obj).forEach(([key, value]) => {
23
+ const newPath = currentPath ? `${currentPath}.${key}` : key;
24
+ if (typeof value === 'object' && value !== null) {
25
+ extractTranslations(sourceFilePath, value, newPath, translations);
26
+ } else {
27
+ // Assuming every leaf node is a translation
28
+ const pathParts = newPath.split('.');
29
+ const locale = pathParts.pop(); // Assuming the last part of the path is the locale
30
+ if (availableLocales.includes(locale)) {
31
+ // Only extract translations for the specified locales
32
+ const translationPath = pathParts.join('.');
33
+ if (!translations[locale]) translations[locale] = {};
34
+ const relativeSourceFilePath = sourceFilePath.replace(ROOT_DIR, '.');
35
+ translations[locale][`${relativeSourceFilePath}@${translationPath}`] = value;
36
+ }
37
+ }
38
+ });
39
+ return translations;
40
+ }
41
+
42
+ // Function to write translations to separate files
43
+ function writeTranslations(translations, outputDir) {
44
+ if (!fs.existsSync(outputDir)) {
45
+ fs.mkdirSync(outputDir, { recursive: true });
46
+ }
47
+ Object.entries(translations).forEach(([locale, translationObj]) => {
48
+ if (availableLocales.includes(locale)) {
49
+ // Only write translations for the specified locales
50
+ const filePath = path.join(outputDir, `${locale}.json`);
51
+ // Append to JSON file
52
+ let existingTranslations = {
53
+ __comment: 'This file is generated. Do not edit it directly.',
54
+ };
55
+ if (fs.existsSync(filePath)) {
56
+ existingTranslations = JSON.parse(fs.readFileSync(filePath, 'utf8'));
57
+ }
58
+ translationObj = { ...existingTranslations, ...translationObj };
59
+ fs.writeFileSync(filePath, JSON.stringify(translationObj, null, 2));
60
+ }
61
+ });
62
+ }
63
+
64
+ console.log(
65
+ `Generating locales (${availableLocales.map(x => x.toUpperCase())}) in ${OUTPUT_DIR}...`,
66
+ );
67
+
68
+ // Remove all files in the output directory
69
+ if (fs.existsSync(OUTPUT_DIR)) {
70
+ fs.rmdirSync(OUTPUT_DIR, { recursive: true });
71
+ }
72
+
73
+ // Parse permissions.json
74
+ const sourceFilePath = path.join(ASSETS_PATH, 'app', 'permissions.json');
75
+ const sourceContent = JSON.parse(fs.readFileSync(sourceFilePath, 'utf8'));
76
+ const translations = extractTranslations(sourceFilePath, sourceContent);
77
+ writeTranslations(translations, OUTPUT_DIR);
78
+
79
+ // Parse capabilities
80
+ const sourceDirCapabilities = path.join(
81
+ ASSETS_PATH,
82
+ 'capability',
83
+ 'capabilities',
84
+ );
85
+ const capabilitiesFiles = fs.readdirSync(sourceDirCapabilities);
86
+ capabilitiesFiles.forEach(file => {
87
+ const sourceFilePath = path.join(sourceDirCapabilities, file);
88
+ const sourceContent = JSON.parse(fs.readFileSync(sourceFilePath, 'utf8'));
89
+ const translations = extractTranslations(sourceFilePath, sourceContent);
90
+ writeTranslations(translations, OUTPUT_DIR);
91
+ });
92
+
93
+ // Parse device classes
94
+ const sourceDirDeviceClasses = path.join(ASSETS_PATH, 'device', 'classes');
95
+ const deviceClassesFiles = fs.readdirSync(sourceDirDeviceClasses);
96
+ deviceClassesFiles.forEach(file => {
97
+ const sourceFilePath = path.join(sourceDirDeviceClasses, file);
98
+ const sourceContent = JSON.parse(fs.readFileSync(sourceFilePath, 'utf8'));
99
+ const translations = extractTranslations(sourceFilePath, sourceContent);
100
+ writeTranslations(translations, OUTPUT_DIR);
101
+ });
102
+
103
+ console.log('Done generating locales.');