@forge/manifest 7.7.0-next.9 → 7.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,85 @@
1
1
  # @forge/manifest
2
2
 
3
+ ## 7.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bf34881: Add translations schema to manifest schema template to enable Forge i18n support.
8
+ Additionally relevant validators (i.e. `translations-validator`) are added to validate the translations schema in the manifest.
9
+ - c341349: Show warning if action doesn't have name attribute
10
+ - c113f86: Show warning if action is not referenced by any agent
11
+ - be67acb: Interpolate string resources in modules
12
+ - 9a546fd: Lint unique module key across Connect and Forge modules
13
+
14
+ ### Patch Changes
15
+
16
+ - 10f4545: Update package readme to include instruction on how to update schema in the package
17
+ - c74ca63: Add translations section in manifest schema for Forge i18n Support (EAP)
18
+ - c6377ba: Update unit test in manifest validator
19
+ - 13fb92c: Update forge repo with unit tests for manifest schema changes Jira, Confluence, Bitbucket
20
+ - 23f6675: Make `@forge/manifest` depends on `@forge/i18n` to access i18n related helper functions.
21
+ - 27249cd: Make i18n fallback syntax confirm to industry convention. That is, `en-US: en-GB` indicate `en-GB` is fallback to `en-US`
22
+ - 99b6dd4: Update manifest definitions
23
+ - b0ad6d7: Update manifest definitions
24
+ - ce41b8c: Update manifest definitions
25
+ - 7160171: Update manifest definitions
26
+ - b90e809: Update manifest definitions
27
+ - 5f82d22: Update manifest definitions
28
+ - f40d3b5: Update manifest definitions
29
+ - 26f8528: Update manifest definitions
30
+ - 313b8e1: Update manifest definitions
31
+ - bf0fab6: Update manifest definitions
32
+ - Updated dependencies [c74ca63]
33
+ - Updated dependencies [d51b7be]
34
+ - Updated dependencies [23f6675]
35
+ - Updated dependencies [c81fa57]
36
+ - Updated dependencies [27249cd]
37
+ - Updated dependencies [fdaaeab]
38
+ - @forge/i18n@0.0.1
39
+
40
+ ## 7.7.0-next.15
41
+
42
+ ### Patch Changes
43
+
44
+ - 99b6dd4: Update manifest definitions
45
+
46
+ ## 7.7.0-next.14
47
+
48
+ ### Patch Changes
49
+
50
+ - Updated dependencies [d51b7be]
51
+ - @forge/i18n@0.0.1-next.13
52
+
53
+ ## 7.7.0-next.13
54
+
55
+ ### Patch Changes
56
+
57
+ - 23f6675: Make `@forge/manifest` depends on `@forge/i18n` to access i18n related helper functions.
58
+ - 27249cd: Make i18n fallback syntax confirm to industry convention. That is, `en-US: en-GB` indicate `en-GB` is fallback to `en-US`
59
+ - 5f82d22: Update manifest definitions
60
+ - Updated dependencies [23f6675]
61
+ - Updated dependencies [27249cd]
62
+ - @forge/i18n@0.0.1-next.12
63
+
64
+ ## 7.7.0-next.12
65
+
66
+ ### Patch Changes
67
+
68
+ - ce41b8c: Update manifest definitions
69
+
70
+ ## 7.7.0-next.11
71
+
72
+ ### Minor Changes
73
+
74
+ - bf34881: Add translations schema to manifest schema template to enable Forge i18n support.
75
+ Additionally relevant validators (i.e. `translations-validator`) are added to validate the translations schema in the manifest.
76
+
77
+ ## 7.7.0-next.10
78
+
79
+ ### Patch Changes
80
+
81
+ - 26f8528: Update manifest definitions
82
+
3
83
  ## 7.7.0-next.9
4
84
 
5
85
  ### Patch Changes
@@ -820,7 +820,6 @@
820
820
  "items": {
821
821
  "oneOf": [
822
822
  {
823
- "additionalProperties": false,
824
823
  "type": "object",
825
824
  "properties": {
826
825
  "description": {
@@ -850,6 +849,25 @@
850
849
  "description": "The url for the icon image to be displayed in the UI",
851
850
  "type": "string"
852
851
  },
852
+ "config": {
853
+ "type": "object",
854
+ "properties": {
855
+ "resource": {
856
+ "type": "string",
857
+ "minLength": 1,
858
+ "maxLength": 23,
859
+ "pattern": "^[a-zA-Z0-9_\\-]+$"
860
+ },
861
+ "render": {
862
+ "default": "default",
863
+ "enum": [
864
+ "default",
865
+ "native"
866
+ ],
867
+ "type": "string"
868
+ }
869
+ }
870
+ },
853
871
  "key": {
854
872
  "$ref": "#/definitions/ModuleKeySchema"
855
873
  }
@@ -867,7 +885,6 @@
867
885
  }
868
886
  },
869
887
  {
870
- "additionalProperties": false,
871
888
  "type": "object",
872
889
  "properties": {
873
890
  "description": {
@@ -890,6 +907,25 @@
890
907
  "description": "The url for the icon image to be displayed in the UI",
891
908
  "type": "string"
892
909
  },
910
+ "config": {
911
+ "type": "object",
912
+ "properties": {
913
+ "resource": {
914
+ "type": "string",
915
+ "minLength": 1,
916
+ "maxLength": 23,
917
+ "pattern": "^[a-zA-Z0-9_\\-]+$"
918
+ },
919
+ "render": {
920
+ "default": "default",
921
+ "enum": [
922
+ "default",
923
+ "native"
924
+ ],
925
+ "type": "string"
926
+ }
927
+ }
928
+ },
893
929
  "actionVerb": {
894
930
  "description": "The operation that will be performed as a result of calling this action",
895
931
  "type": "string",
@@ -908,6 +944,13 @@
908
944
  },
909
945
  "maxProperties": 10
910
946
  },
947
+ "outputs": {
948
+ "type": "object",
949
+ "additionalProperties": {
950
+ "$ref": "#/definitions/ActionOutput"
951
+ },
952
+ "maxProperties": 10
953
+ },
911
954
  "key": {
912
955
  "$ref": "#/definitions/ModuleKeySchema"
913
956
  }
@@ -925,7 +968,6 @@
925
968
  }
926
969
  },
927
970
  {
928
- "additionalProperties": false,
929
971
  "type": "object",
930
972
  "properties": {
931
973
  "description": {
@@ -942,6 +984,25 @@
942
984
  "description": "The url for the icon image to be displayed in the UI",
943
985
  "type": "string"
944
986
  },
987
+ "config": {
988
+ "type": "object",
989
+ "properties": {
990
+ "resource": {
991
+ "type": "string",
992
+ "minLength": 1,
993
+ "maxLength": 23,
994
+ "pattern": "^[a-zA-Z0-9_\\-]+$"
995
+ },
996
+ "render": {
997
+ "default": "default",
998
+ "enum": [
999
+ "default",
1000
+ "native"
1001
+ ],
1002
+ "type": "string"
1003
+ }
1004
+ }
1005
+ },
945
1006
  "endpoint": {
946
1007
  "$ref": "#/definitions/ExtensionKey",
947
1008
  "title": "endpoint",
@@ -965,6 +1026,13 @@
965
1026
  },
966
1027
  "maxProperties": 10
967
1028
  },
1029
+ "outputs": {
1030
+ "type": "object",
1031
+ "additionalProperties": {
1032
+ "$ref": "#/definitions/ActionOutput"
1033
+ },
1034
+ "maxProperties": 10
1035
+ },
968
1036
  "key": {
969
1037
  "$ref": "#/definitions/ModuleKeySchema"
970
1038
  }
@@ -982,9 +1050,27 @@
982
1050
  }
983
1051
  },
984
1052
  {
985
- "additionalProperties": false,
986
1053
  "type": "object",
987
1054
  "properties": {
1055
+ "config": {
1056
+ "type": "object",
1057
+ "properties": {
1058
+ "resource": {
1059
+ "type": "string",
1060
+ "minLength": 1,
1061
+ "maxLength": 23,
1062
+ "pattern": "^[a-zA-Z0-9_\\-]+$"
1063
+ },
1064
+ "render": {
1065
+ "default": "default",
1066
+ "enum": [
1067
+ "default",
1068
+ "native"
1069
+ ],
1070
+ "type": "string"
1071
+ }
1072
+ }
1073
+ },
988
1074
  "description": {
989
1075
  "description": "The description that the Rovo agent will use to decide when to invoke this action.",
990
1076
  "minLength": 1,
@@ -23243,7 +23329,8 @@
23243
23329
  },
23244
23330
  "name": {
23245
23331
  "type": "string",
23246
- "minLength": 1
23332
+ "minLength": 1,
23333
+ "maxLength": 30
23247
23334
  },
23248
23335
  "description": {
23249
23336
  "minLength": 1,
@@ -24228,7 +24315,7 @@
24228
24315
  "auth"
24229
24316
  ]
24230
24317
  },
24231
- "CoreActionInputsType": {
24318
+ "CoreActionIOType": {
24232
24319
  "type": "string",
24233
24320
  "enum": [
24234
24321
  "boolean",
@@ -24253,7 +24340,28 @@
24253
24340
  "description": "A description of what this particular input is intended for. Example: 'ID of the Issue that will be updated as a result of this action'\n"
24254
24341
  },
24255
24342
  "type": {
24256
- "$ref": "#/definitions/CoreActionInputsType"
24343
+ "$ref": "#/definitions/CoreActionIOType"
24344
+ }
24345
+ }
24346
+ },
24347
+ "ActionOutput": {
24348
+ "type": "object",
24349
+ "required": [
24350
+ "description",
24351
+ "nullable",
24352
+ "type"
24353
+ ],
24354
+ "properties": {
24355
+ "description": {
24356
+ "type": "string",
24357
+ "description": "A description of what this particular output represents. Example: 'ID of the Issue that was created as a result of this action'\n"
24358
+ },
24359
+ "nullable": {
24360
+ "type": "boolean",
24361
+ "description": "A flag to indicate whether the output can have a value of null."
24362
+ },
24363
+ "type": {
24364
+ "$ref": "#/definitions/CoreActionIOType"
24257
24365
  }
24258
24366
  }
24259
24367
  },
@@ -110,7 +110,7 @@ export type Function3 = string;
110
110
  * Name of the key of the function that will handle this action.
111
111
  */
112
112
  export type Function4 = string;
113
- export type CoreActionInputsType = 'boolean' | 'integer' | 'number' | 'string';
113
+ export type CoreActionIOType = 'boolean' | 'integer' | 'number' | 'string';
114
114
  /**
115
115
  * The key for an extension in CaaS. That means that this is a reference to another
116
116
  * extension in your descriptor / manifest.
@@ -992,7 +992,13 @@ export interface Modules {
992
992
  * The url for the icon image to be displayed in the UI
993
993
  */
994
994
  icon?: string;
995
+ config?: {
996
+ resource?: string;
997
+ render?: 'default' | 'native';
998
+ [k: string]: unknown;
999
+ };
995
1000
  key: ModuleKeySchema;
1001
+ [k: string]: unknown;
996
1002
  }
997
1003
  | {
998
1004
  /**
@@ -1008,6 +1014,11 @@ export interface Modules {
1008
1014
  * The url for the icon image to be displayed in the UI
1009
1015
  */
1010
1016
  icon?: string;
1017
+ config?: {
1018
+ resource?: string;
1019
+ render?: 'default' | 'native';
1020
+ [k: string]: unknown;
1021
+ };
1011
1022
  /**
1012
1023
  * The operation that will be performed as a result of calling this action
1013
1024
  */
@@ -1015,7 +1026,11 @@ export interface Modules {
1015
1026
  inputs?: {
1016
1027
  [k: string]: ActionInput;
1017
1028
  };
1029
+ outputs?: {
1030
+ [k: string]: ActionOutput;
1031
+ };
1018
1032
  key: ModuleKeySchema;
1033
+ [k: string]: unknown;
1019
1034
  }
1020
1035
  | {
1021
1036
  /**
@@ -1030,6 +1045,11 @@ export interface Modules {
1030
1045
  * The url for the icon image to be displayed in the UI
1031
1046
  */
1032
1047
  icon?: string;
1048
+ config?: {
1049
+ resource?: string;
1050
+ render?: 'default' | 'native';
1051
+ [k: string]: unknown;
1052
+ };
1033
1053
  endpoint: Endpoint2;
1034
1054
  /**
1035
1055
  * The operation that will be performed as a result of calling this action
@@ -1038,9 +1058,18 @@ export interface Modules {
1038
1058
  inputs?: {
1039
1059
  [k: string]: ActionInput;
1040
1060
  };
1061
+ outputs?: {
1062
+ [k: string]: ActionOutput;
1063
+ };
1041
1064
  key: ModuleKeySchema;
1065
+ [k: string]: unknown;
1042
1066
  }
1043
1067
  | {
1068
+ config?: {
1069
+ resource?: string;
1070
+ render?: 'default' | 'native';
1071
+ [k: string]: unknown;
1072
+ };
1044
1073
  /**
1045
1074
  * The description that the Rovo agent will use to decide when to invoke this action.
1046
1075
  */
@@ -1062,6 +1091,7 @@ export interface Modules {
1062
1091
  */
1063
1092
  icon?: string;
1064
1093
  key: ModuleKeySchema;
1094
+ [k: string]: unknown;
1065
1095
  }
1066
1096
  ),
1067
1097
  ...(
@@ -1086,7 +1116,13 @@ export interface Modules {
1086
1116
  * The url for the icon image to be displayed in the UI
1087
1117
  */
1088
1118
  icon?: string;
1119
+ config?: {
1120
+ resource?: string;
1121
+ render?: 'default' | 'native';
1122
+ [k: string]: unknown;
1123
+ };
1089
1124
  key: ModuleKeySchema;
1125
+ [k: string]: unknown;
1090
1126
  }
1091
1127
  | {
1092
1128
  /**
@@ -1102,6 +1138,11 @@ export interface Modules {
1102
1138
  * The url for the icon image to be displayed in the UI
1103
1139
  */
1104
1140
  icon?: string;
1141
+ config?: {
1142
+ resource?: string;
1143
+ render?: 'default' | 'native';
1144
+ [k: string]: unknown;
1145
+ };
1105
1146
  /**
1106
1147
  * The operation that will be performed as a result of calling this action
1107
1148
  */
@@ -1109,7 +1150,11 @@ export interface Modules {
1109
1150
  inputs?: {
1110
1151
  [k: string]: ActionInput;
1111
1152
  };
1153
+ outputs?: {
1154
+ [k: string]: ActionOutput;
1155
+ };
1112
1156
  key: ModuleKeySchema;
1157
+ [k: string]: unknown;
1113
1158
  }
1114
1159
  | {
1115
1160
  /**
@@ -1124,6 +1169,11 @@ export interface Modules {
1124
1169
  * The url for the icon image to be displayed in the UI
1125
1170
  */
1126
1171
  icon?: string;
1172
+ config?: {
1173
+ resource?: string;
1174
+ render?: 'default' | 'native';
1175
+ [k: string]: unknown;
1176
+ };
1127
1177
  endpoint: Endpoint2;
1128
1178
  /**
1129
1179
  * The operation that will be performed as a result of calling this action
@@ -1132,9 +1182,18 @@ export interface Modules {
1132
1182
  inputs?: {
1133
1183
  [k: string]: ActionInput;
1134
1184
  };
1185
+ outputs?: {
1186
+ [k: string]: ActionOutput;
1187
+ };
1135
1188
  key: ModuleKeySchema;
1189
+ [k: string]: unknown;
1136
1190
  }
1137
1191
  | {
1192
+ config?: {
1193
+ resource?: string;
1194
+ render?: 'default' | 'native';
1195
+ [k: string]: unknown;
1196
+ };
1138
1197
  /**
1139
1198
  * The description that the Rovo agent will use to decide when to invoke this action.
1140
1199
  */
@@ -1156,6 +1215,7 @@ export interface Modules {
1156
1215
  */
1157
1216
  icon?: string;
1158
1217
  key: ModuleKeySchema;
1218
+ [k: string]: unknown;
1159
1219
  }
1160
1220
  )[]
1161
1221
  ];
@@ -10646,7 +10706,20 @@ export interface ActionInput {
10646
10706
  *
10647
10707
  */
10648
10708
  description: string;
10649
- type: CoreActionInputsType;
10709
+ type: CoreActionIOType;
10710
+ [k: string]: unknown;
10711
+ }
10712
+ export interface ActionOutput {
10713
+ /**
10714
+ * A description of what this particular output represents. Example: 'ID of the Issue that was created as a result of this action'
10715
+ *
10716
+ */
10717
+ description: string;
10718
+ /**
10719
+ * A flag to indicate whether the output can have a value of null.
10720
+ */
10721
+ nullable: boolean;
10722
+ type: CoreActionIOType;
10650
10723
  [k: string]: unknown;
10651
10724
  }
10652
10725
  /**
@@ -1,3 +1,4 @@
1
+ import { type ForgeSupportedLocaleCode } from '../schema/manifest';
1
2
  import { AllModuleTypes } from '../types';
2
3
  export declare const errors: {
3
4
  invalidManifest: (reason: string) => string;
@@ -164,13 +165,14 @@ export declare const errors: {
164
165
  };
165
166
  };
166
167
  translations: {
167
- missingTranslationsJsonFile: (languageLocaleCode: string) => string;
168
- duplicateFallbackConfig: (languageLocaleCode: string) => string;
169
- invalidLanguageFile: (languageLocaleCode: string, path: string) => string;
170
- duplicateResourceKey: (languageLocaleCode: string) => string;
168
+ missingTranslationsJsonFile: (languageLocaleCode: ForgeSupportedLocaleCode) => string;
169
+ duplicateFallbackConfig: (languageLocaleCode: ForgeSupportedLocaleCode) => string;
170
+ invalidLanguageFile: (languageLocaleCode: ForgeSupportedLocaleCode, path: string) => string;
171
+ duplicateResourceKey: (languageLocaleCode: ForgeSupportedLocaleCode) => string;
171
172
  i18nKeyNotFound: (keyName: string) => string;
172
173
  missingTranslationsPropertyError: string;
173
174
  internalI18nPropertyKeyFound: (propertyKey: string, moduleKey: string) => string;
175
+ i18nValueValidationError: (keyName: string, languageLocaleCode: ForgeSupportedLocaleCode, errorMsg: string) => string;
174
176
  };
175
177
  };
176
178
  export declare enum References {
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/text/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/text/errors.ts"],"names":[],"mappings":"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"}
@@ -183,7 +183,8 @@ exports.errors = {
183
183
  duplicateResourceKey: (languageLocaleCode) => `Duplicate translations resource key found: '${languageLocaleCode}'`,
184
184
  i18nKeyNotFound: (keyName) => `i18n key '${keyName}' could not be found in default locale file.`,
185
185
  missingTranslationsPropertyError: 'i18n key(s) found but translations property is missing in manifest file',
186
- internalI18nPropertyKeyFound: (propertyKey, moduleKey) => `Unexpected property key '${propertyKey}' found in '${moduleKey}' module`
186
+ internalI18nPropertyKeyFound: (propertyKey, moduleKey) => `Unexpected property key '${propertyKey}' found in '${moduleKey}' module`,
187
+ i18nValueValidationError: (keyName, languageLocaleCode, errorMsg) => `i18n value for key '${keyName}' for locale '${languageLocaleCode}' ${errorMsg}`
187
188
  }
188
189
  };
189
190
  var References;
@@ -0,0 +1,2 @@
1
+ export * from './module-i18n-helper';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/i18n/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./module-i18n-helper"), exports);
@@ -0,0 +1,3 @@
1
+ import { Modules } from '../../schema/manifest';
2
+ export declare const extractInternalI18nPropertyKeysFromModules: (modules: Modules) => [string, string][];
3
+ //# sourceMappingURL=module-i18n-helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-i18n-helper.d.ts","sourceRoot":"","sources":["../../../src/utils/i18n/module-i18n-helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAsChD,eAAO,MAAM,0CAA0C,YAAa,OAAO,KAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAS7F,CAAC"}
@@ -1,32 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.extractInternalI18nPropertyKeysFromModules = exports.extractI18nKeysFromModules = void 0;
3
+ exports.extractInternalI18nPropertyKeysFromModules = void 0;
4
+ const i18n_1 = require("@forge/i18n");
5
+ const INTERNAL_I18N_PROPERTY_KEY_SUFFIX = '__i18n';
4
6
  const isObject = (value) => {
5
7
  return typeof value === 'object' && value !== null && !Array.isArray(value);
6
8
  };
7
- const isI18nValue = (value) => {
8
- return typeof value?.i18n === 'string';
9
- };
10
- const getI18nKeysFromObject = (obj) => {
11
- const visited = new Set();
12
- const visit = (value) => {
13
- if (!isObject(value) || visited.has(value)) {
14
- return [];
15
- }
16
- visited.add(value);
17
- return Object.values(value).flatMap((propValue) => {
18
- if (isI18nValue(propValue)) {
19
- return [propValue.i18n];
20
- }
21
- else if (Array.isArray(propValue)) {
22
- return propValue.flatMap((item) => visit(item));
23
- }
24
- return visit(propValue);
25
- });
26
- };
27
- return visit(obj);
28
- };
29
- const INTERNAL_I18N_PROPERTY_KEY_SUFFIX = '__i18n';
30
9
  const isInternalI18nPropertyKey = (key) => {
31
10
  return key.length > INTERNAL_I18N_PROPERTY_KEY_SUFFIX.length && key.endsWith(INTERNAL_I18N_PROPERTY_KEY_SUFFIX);
32
11
  };
@@ -52,28 +31,9 @@ const getInternalI18nPropertyKeysFromObject = (obj) => {
52
31
  };
53
32
  return visit(obj);
54
33
  };
55
- const getAllModuleEntries = (modules) => {
56
- return Object.entries(modules).flatMap(([moduleKey, moduleEntries]) => {
57
- if (moduleEntries && Array.isArray(moduleEntries) && moduleEntries.length > 0) {
58
- return moduleEntries.map((moduleEntry) => [moduleEntry, moduleKey]);
59
- }
60
- return [];
61
- });
62
- };
63
- const extractI18nKeysFromModules = (modules) => {
64
- const i18nKeys = new Set();
65
- for (const moduleEntry of getAllModuleEntries(modules)) {
66
- const i18nKeysForEntryValue = getI18nKeysFromObject(moduleEntry[0]);
67
- for (const key of i18nKeysForEntryValue) {
68
- i18nKeys.add(key);
69
- }
70
- }
71
- return i18nKeys.size > 0 ? Array.from(i18nKeys) : [];
72
- };
73
- exports.extractI18nKeysFromModules = extractI18nKeysFromModules;
74
34
  const extractInternalI18nPropertyKeysFromModules = (modules) => {
75
35
  const i18nKeys = new Set();
76
- for (const [moduleEntryObject, moduleKey] of getAllModuleEntries(modules)) {
36
+ for (const [moduleEntryObject, moduleKey] of (0, i18n_1.getI18nSupportedModuleEntries)(modules)) {
77
37
  const i18nKeysForEntryValue = getInternalI18nPropertyKeysFromObject(moduleEntryObject);
78
38
  for (const key of i18nKeysForEntryValue) {
79
39
  i18nKeys.add(`${key},${moduleKey}`);
@@ -0,0 +1,7 @@
1
+ import { ForgeSupportedLocaleCode as ExpectedForgeSupportedLocaleCode } from '@forge/i18n';
2
+ import { ForgeSupportedLocaleCode as ActualForgeSupportedLocaleCode } from '../../schema/manifest';
3
+ declare type IsSameType<T, U> = T extends U ? (U extends T ? true : false) : false;
4
+ declare type AreForgeSupportedLocaleCodesConsistent = IsSameType<ExpectedForgeSupportedLocaleCode, ActualForgeSupportedLocaleCode>;
5
+ export declare const __supportedForgeLocaleCodeConsistencyCheck: AreForgeSupportedLocaleCodesConsistent;
6
+ export {};
7
+ //# sourceMappingURL=type-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-check.d.ts","sourceRoot":"","sources":["../../../src/utils/i18n/type-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,IAAI,gCAAgC,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,wBAAwB,IAAI,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AAEnG,aAAK,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;AAE3E,aAAK,sCAAsC,GAAG,UAAU,CACtD,gCAAgC,EAChC,8BAA8B,CAC/B,CAAC;AAEF,eAAO,MAAM,0CAA0C,EAAE,sCAA6C,CAAC"}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.__supportedForgeLocaleCodeConsistencyCheck = void 0;
4
+ exports.__supportedForgeLocaleCodeConsistencyCheck = true;
@@ -4,6 +4,5 @@ export * from './module-key-cleaner';
4
4
  export * from './module-references';
5
5
  export * from './manifest-parser-builder';
6
6
  export type { ManifestParser } from './manifest-parser';
7
- export * from './module-i18n-helper';
8
- export * from './translation-value-getter';
7
+ export * from './i18n';
9
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,cAAc,QAAQ,CAAC"}
@@ -6,5 +6,4 @@ tslib_1.__exportStar(require("./line-finder"), exports);
6
6
  tslib_1.__exportStar(require("./module-key-cleaner"), exports);
7
7
  tslib_1.__exportStar(require("./module-references"), exports);
8
8
  tslib_1.__exportStar(require("./manifest-parser-builder"), exports);
9
- tslib_1.__exportStar(require("./module-i18n-helper"), exports);
10
- tslib_1.__exportStar(require("./translation-value-getter"), exports);
9
+ tslib_1.__exportStar(require("./i18n"), exports);
@@ -2,9 +2,18 @@ import { type ManifestSchema } from '../schema/manifest';
2
2
  import { ManifestObject, ManifestValidationResult } from '../types';
3
3
  import { ValidatorInterface } from './validator-interface';
4
4
  export declare class TranslationsValidator implements ValidatorInterface<ManifestObject<ManifestSchema> | undefined, ManifestSchema> {
5
+ private validateCache;
6
+ private ajv;
5
7
  private ensureValidResourcesDefinition;
6
8
  private ensureValidFallbackDefinition;
9
+ private getAllLocalesLookup;
7
10
  private ensureI18nKeysExistInDefaultJson;
11
+ private getI18nMap;
12
+ private getI18nPropertySchema;
13
+ private getValidateI18nFn;
14
+ private getI18nPropertyValidator;
15
+ private ensureValidI18nValue;
16
+ private ensureAllValidI18nValue;
8
17
  private validateManifestWithoutI18nConfig;
9
18
  private validateManifestI18nConfig;
10
19
  private validateInternalI18nPropertyKeysNotInModules;
@@ -1 +1 @@
1
- {"version":3,"file":"translations-validator.d.ts","sourceRoot":"","sources":["../../src/validators/translations-validator.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+C,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGtG,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAmB,MAAM,UAAU,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAQ3D,qBAAa,qBACX,YAAW,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,EAAE,cAAc,CAAC;IAEzF,OAAO,CAAC,8BAA8B;IA8CtC,OAAO,CAAC,6BAA6B;IA8CrC,OAAO,CAAC,gCAAgC;IAsBxC,OAAO,CAAC,iCAAiC;IAwBzC,OAAO,CAAC,0BAA0B;IASlC,OAAO,CAAC,4CAA4C;IAe9C,QAAQ,CACZ,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;CAyBrD"}
1
+ {"version":3,"file":"translations-validator.d.ts","sourceRoot":"","sources":["../../src/validators/translations-validator.ts"],"names":[],"mappings":"AAOA,OAAO,EAA+C,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAItG,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAmB,MAAM,UAAU,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAM3D,qBAAa,qBACX,YAAW,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,EAAE,cAAc,CAAC;IAEzF,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,GAAG,CAA8D;IAEzE,OAAO,CAAC,8BAA8B;IA4CtC,OAAO,CAAC,6BAA6B;IAwCrC,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,gCAAgC;IAoBxC,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,qBAAqB;IA4B7B,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,wBAAwB;IAiDhC,OAAO,CAAC,oBAAoB;IA2B5B,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,iCAAiC;IAwBzC,OAAO,CAAC,0BAA0B;IAalC,OAAO,CAAC,4CAA4C;IAe9C,QAAQ,CACZ,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;CA0BrD"}
@@ -4,14 +4,20 @@ exports.TranslationsValidator = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fs_1 = tslib_1.__importDefault(require("fs"));
6
6
  const path_1 = require("path");
7
+ const lodash_1 = require("lodash");
8
+ const ajv_1 = tslib_1.__importDefault(require("ajv"));
9
+ const i18n_1 = require("@forge/i18n");
10
+ const manifest_schema_json_1 = tslib_1.__importDefault(require("../schema/manifest-schema.json"));
7
11
  const text_1 = require("../text");
8
12
  const text_2 = require("../text");
9
13
  const utils_1 = require("../utils");
10
14
  class TranslationsValidator {
15
+ validateCache = new Map();
16
+ ajv = new ajv_1.default({ allErrors: true, verbose: true, strict: false });
11
17
  ensureValidResourcesDefinition(validationErrors, manifest) {
12
- const { resources, fallback } = manifest.yamlContent.translations;
18
+ const { resources } = manifest.yamlContent.translations;
13
19
  const resourcesMap = new Map();
14
- resources.forEach(({ key, path }) => {
20
+ for (const { key, path } of resources) {
15
21
  if (resourcesMap.has(key)) {
16
22
  validationErrors.push({
17
23
  message: text_1.errors.translations.duplicateResourceKey(key),
@@ -23,16 +29,14 @@ class TranslationsValidator {
23
29
  else {
24
30
  resourcesMap.set(key, path);
25
31
  }
26
- });
27
- let defaultLanguageLookup = {};
28
- resourcesMap.forEach((path, key) => {
32
+ }
33
+ const allLanguageLookup = {};
34
+ for (const [key, path] of resourcesMap) {
29
35
  const resourcePath = (0, path_1.resolve)(path);
30
36
  try {
31
37
  if (fs_1.default.lstatSync(resourcePath).isFile()) {
32
38
  const data = JSON.parse(fs_1.default.readFileSync((0, path_1.resolve)(path), 'utf8'));
33
- if (fallback?.default === key) {
34
- defaultLanguageLookup = data;
35
- }
39
+ allLanguageLookup[key] = data;
36
40
  }
37
41
  }
38
42
  catch (e) {
@@ -43,59 +47,159 @@ class TranslationsValidator {
43
47
  ...(0, utils_1.findPosition)(`path: ${path}`, manifest?.yamlContentByLine)
44
48
  });
45
49
  }
46
- });
47
- return defaultLanguageLookup;
50
+ }
51
+ return allLanguageLookup;
48
52
  }
49
53
  ensureValidFallbackDefinition(validationErrors, manifest) {
50
54
  const { resources, fallback } = manifest.yamlContent.translations;
51
- const defaultLanguage = fallback.default;
52
55
  const resourcesSet = new Set(resources.map((resource) => resource.key));
53
- const fallbackLanguages = Object.keys(fallback).filter((fallbackLanguage) => fallbackLanguage !== 'default');
54
- const allFallbackLanguagesSet = new Set([defaultLanguage, ...fallbackLanguages]);
55
- allFallbackLanguagesSet.forEach((fallbackLanguage) => {
56
- if (!resourcesSet.has(fallbackLanguage)) {
56
+ const fallbackLocales = new Set(Object.values(fallback).flatMap((locales) => Array.isArray(locales) ? locales : [locales]));
57
+ for (const fallbackLocale of fallbackLocales) {
58
+ if (!resourcesSet.has(fallbackLocale)) {
59
+ const targetLocale = Object.entries(fallback).find(([, locales]) => locales === fallbackLocale || locales.includes(fallbackLocale))?.[0];
57
60
  validationErrors.push({
58
- message: text_1.errors.translations.missingTranslationsJsonFile(fallbackLanguage),
61
+ message: text_1.errors.translations.missingTranslationsJsonFile(fallbackLocale),
59
62
  reference: text_2.References.SchemaError,
60
63
  level: 'error',
61
- ...(0, utils_1.findPosition)(fallbackLanguage === defaultLanguage ? `default: ${fallbackLanguage}` : `${fallbackLanguage}:`, manifest.yamlContentByLine)
64
+ ...(0, utils_1.findPosition)(`${targetLocale}:`, manifest.yamlContentByLine)
62
65
  });
63
66
  }
64
- });
65
- const allLanguagesList = [
66
- defaultLanguage,
67
- ...fallbackLanguages,
68
- ...fallbackLanguages.flatMap((language) => fallback[language])
69
- ];
70
- const [, duplicates] = allLanguagesList.reduce(([languageSet, duplicates], language) => {
71
- languageSet.has(language) ? duplicates.add(language) : languageSet.add(language);
72
- return [languageSet, duplicates];
73
- }, [new Set(), new Set()]);
74
- duplicates.forEach((duplicate) => {
75
- validationErrors.push({
76
- message: text_1.errors.translations.duplicateFallbackConfig(duplicate),
77
- reference: text_2.References.SchemaError,
78
- level: 'error',
79
- ...(0, utils_1.findPosition)(duplicate, manifest.yamlContentByLine)
80
- });
81
- });
67
+ }
68
+ for (const [targetLocale, fallbackLocales] of Object.entries(fallback)) {
69
+ const locales = [targetLocale, ...(Array.isArray(fallbackLocales) ? fallbackLocales : [fallbackLocales])];
70
+ if (locales.length !== new Set(locales).size) {
71
+ validationErrors.push({
72
+ message: text_1.errors.translations.duplicateFallbackConfig(targetLocale),
73
+ reference: text_2.References.SchemaError,
74
+ level: 'error',
75
+ ...(0, utils_1.findPosition)(`${targetLocale}:`, manifest.yamlContentByLine)
76
+ });
77
+ }
78
+ }
82
79
  }
83
- ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, defaultLanguageLookup, manifest) {
84
- const i18nKeysSet = new Set(i18nKeys);
85
- const defaultLocalCode = manifest.yamlContent.translations.fallback.default;
86
- const languageLookUp = { [defaultLocalCode]: defaultLanguageLookup };
87
- i18nKeysSet.forEach((key) => {
88
- const i18nValue = (0, utils_1.getTranslationValue)(languageLookUp, key, defaultLocalCode);
80
+ getAllLocalesLookup(validationErrors, i18nKeys, translationsLookup, manifest) {
81
+ const { resources, fallback } = manifest.yamlContent.translations;
82
+ const defaultLocaleCode = fallback.default;
83
+ return resources
84
+ .map((resource) => resource.key)
85
+ .reduce((allLocalesLookup, locale) => {
86
+ const i18nMap = this.getI18nMap(i18nKeys, translationsLookup, locale);
87
+ if (locale === defaultLocaleCode) {
88
+ this.ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, translationsLookup, locale, manifest);
89
+ }
90
+ allLocalesLookup.set(locale, i18nMap);
91
+ return allLocalesLookup;
92
+ }, new Map());
93
+ }
94
+ ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, translationsLookup, locale, manifest) {
95
+ for (const i18nKey of i18nKeys) {
96
+ const i18nValue = (0, i18n_1.getTranslationValue)(translationsLookup, i18nKey, locale);
89
97
  if (!i18nValue) {
90
98
  validationErrors.push({
91
- message: text_1.errors.translations.i18nKeyNotFound(key),
99
+ message: text_1.errors.translations.i18nKeyNotFound(i18nKey),
92
100
  reference: text_2.References.SchemaError,
93
101
  level: 'error',
94
- ...(0, utils_1.findPosition)(`i18n: ${key}`, manifest.yamlContentByLine)
102
+ ...(0, utils_1.findPosition)(`i18n: ${i18nKey}`, manifest.yamlContentByLine)
95
103
  });
96
104
  }
105
+ }
106
+ }
107
+ getI18nMap(i18nKeys, translationsLookup, locale) {
108
+ return i18nKeys.reduce((i18nMap, key) => {
109
+ const i18nValue = (0, i18n_1.getTranslationValue)(translationsLookup, key, locale);
110
+ if (i18nValue) {
111
+ i18nMap.set(key, i18nValue);
112
+ }
113
+ return i18nMap;
114
+ }, new Map());
115
+ }
116
+ getI18nPropertySchema(schemaSlice, i18nPath) {
117
+ if (typeof schemaSlice !== 'object' || schemaSlice === null) {
118
+ return [];
119
+ }
120
+ const [propertyName, ...restPath] = i18nPath;
121
+ if (Array.isArray(schemaSlice)) {
122
+ return schemaSlice.flatMap((object) => {
123
+ return this.getI18nPropertySchema(object, i18nPath);
124
+ });
125
+ }
126
+ return Object.entries(schemaSlice).flatMap(([key, value]) => {
127
+ if (key === propertyName) {
128
+ if (restPath.length === 0 && typeof value === 'object') {
129
+ return [value];
130
+ }
131
+ else if (restPath.length > 0) {
132
+ return this.getI18nPropertySchema(value, restPath);
133
+ }
134
+ else {
135
+ return [];
136
+ }
137
+ }
138
+ else {
139
+ return this.getI18nPropertySchema(value, i18nPath);
140
+ }
97
141
  });
98
142
  }
143
+ getValidateI18nFn(i18nPropertySchema) {
144
+ const schemaKey = JSON.stringify(i18nPropertySchema);
145
+ if (this.validateCache.has(schemaKey)) {
146
+ return this.validateCache.get(schemaKey);
147
+ }
148
+ const validate = this.ajv.compile(i18nPropertySchema);
149
+ this.validateCache.set(schemaKey, validate);
150
+ return validate;
151
+ }
152
+ getI18nPropertyValidator({ modulesSchema, i18nPropertyPath, i18nKey, locale, manifest }) {
153
+ const i18nPropertySchemas = this.getI18nPropertySchema(modulesSchema, i18nPropertyPath);
154
+ return (i18nValue) => {
155
+ const validationResults = i18nPropertySchemas.reduce((validationResults, i18nPropertySchema) => {
156
+ const validate = this.getValidateI18nFn(i18nPropertySchema);
157
+ if (!validationResults.isValid && !validate(i18nValue)) {
158
+ const validationErrors = validate.errors.reduce((validationErrors, validationError) => {
159
+ if (validationError.message) {
160
+ validationErrors.push({
161
+ message: text_1.errors.translations.i18nValueValidationError(i18nKey, locale, validationError.message),
162
+ reference: text_2.References.SchemaError,
163
+ level: 'error',
164
+ ...(0, utils_1.findPosition)(`i18n: ${i18nKey}`, manifest?.yamlContentByLine)
165
+ });
166
+ }
167
+ return validationErrors;
168
+ }, []);
169
+ validationResults.errors.push(validationErrors);
170
+ }
171
+ else {
172
+ validationResults.isValid = true;
173
+ }
174
+ return validationResults;
175
+ }, { errors: [], isValid: false });
176
+ return validationResults.isValid ? [] : validationResults.errors;
177
+ };
178
+ }
179
+ ensureValidI18nValue(validationErrors, i18nMap, moduleI18nProperties, locale, manifest) {
180
+ for (const i18n of moduleI18nProperties) {
181
+ const i18nValue = i18nMap.get(i18n.key);
182
+ if (i18nValue) {
183
+ const modulesSchema = (0, lodash_1.get)(manifest_schema_json_1.default.definitions.ModuleSchema.properties, i18n.moduleName);
184
+ const validator = this.getI18nPropertyValidator({
185
+ modulesSchema,
186
+ i18nPropertyPath: i18n.propertyPath,
187
+ i18nKey: i18n.key,
188
+ locale,
189
+ manifest
190
+ });
191
+ const validationResults = validator(i18nValue);
192
+ if (validationResults.length > 0) {
193
+ validationErrors.push(...validationResults[0]);
194
+ }
195
+ }
196
+ }
197
+ }
198
+ ensureAllValidI18nValue(validationErrors, allI18nMap, moduleI18nProperties, manifest) {
199
+ for (const [locale, i18nMap] of allI18nMap) {
200
+ this.ensureValidI18nValue(validationErrors, i18nMap, moduleI18nProperties, locale, manifest);
201
+ }
202
+ }
99
203
  validateManifestWithoutI18nConfig(manifest, i18nKeys) {
100
204
  if (i18nKeys.length === 0) {
101
205
  return {
@@ -117,11 +221,12 @@ class TranslationsValidator {
117
221
  errors: missingTranslationsPropertyError
118
222
  };
119
223
  }
120
- validateManifestI18nConfig(manifest, i18nKeys) {
224
+ validateManifestI18nConfig(manifest, i18nKeys, moduleI18nProperties) {
121
225
  const validationErrors = [];
122
- const defaultLanguageLookup = this.ensureValidResourcesDefinition(validationErrors, manifest);
226
+ const allLanguageLookup = this.ensureValidResourcesDefinition(validationErrors, manifest);
123
227
  this.ensureValidFallbackDefinition(validationErrors, manifest);
124
- this.ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, defaultLanguageLookup, manifest);
228
+ const i18nMap = this.getAllLocalesLookup(validationErrors, i18nKeys, allLanguageLookup, manifest);
229
+ this.ensureAllValidI18nValue(validationErrors, i18nMap, moduleI18nProperties, manifest);
125
230
  return validationErrors;
126
231
  }
127
232
  validateInternalI18nPropertyKeysNotInModules(manifest) {
@@ -141,13 +246,14 @@ class TranslationsValidator {
141
246
  manifestObject: manifest
142
247
  };
143
248
  }
144
- const i18nKeys = (0, utils_1.extractI18nKeysFromModules)(manifest?.typedContent?.modules ?? {});
249
+ const moduleI18nProperties = (0, i18n_1.extractI18nPropertiesFromModules)(manifest?.typedContent?.modules ?? {});
250
+ const i18nKeys = moduleI18nProperties.map((i18nConfig) => i18nConfig.key);
145
251
  const i18nConfig = manifest?.yamlContent?.translations;
146
252
  if (!i18nConfig) {
147
253
  return this.validateManifestWithoutI18nConfig(manifest, i18nKeys);
148
254
  }
149
255
  const validationErrors = [
150
- ...this.validateManifestI18nConfig(manifest, i18nKeys),
256
+ ...this.validateManifestI18nConfig(manifest, i18nKeys, moduleI18nProperties),
151
257
  ...this.validateInternalI18nPropertyKeysNotInModules(manifest)
152
258
  ];
153
259
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/manifest",
3
- "version": "7.7.0-next.9",
3
+ "version": "7.7.0",
4
4
  "description": "Definitions and validations of the Forge manifest",
5
5
  "main": "out/index.js",
6
6
  "scripts": {
@@ -24,6 +24,7 @@
24
24
  "author": "Atlassian",
25
25
  "license": "UNLICENSED",
26
26
  "dependencies": {
27
+ "@forge/i18n": "0.0.1",
27
28
  "@sentry/node": "7.100.1",
28
29
  "ajv": "^8.12.0",
29
30
  "ajv-formats": "2.1.1",
@@ -1,4 +0,0 @@
1
- import { Modules } from '../schema/manifest';
2
- export declare const extractI18nKeysFromModules: (modules: Modules) => string[];
3
- export declare const extractInternalI18nPropertyKeysFromModules: (modules: Modules) => [string, string][];
4
- //# sourceMappingURL=module-i18n-helper.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"module-i18n-helper.d.ts","sourceRoot":"","sources":["../../src/utils/module-i18n-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AA8E7C,eAAO,MAAM,0BAA0B,YAAa,OAAO,KAAG,MAAM,EASnE,CAAC;AAEF,eAAO,MAAM,0CAA0C,YAAa,OAAO,KAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAS7F,CAAC"}
@@ -1,10 +0,0 @@
1
- import { type ForgeSupportedLocaleCode } from '../schema/manifest';
2
- interface TranslationContent {
3
- [key: string]: string | TranslationContent;
4
- }
5
- declare type TranslationContentByLocaleCode = {
6
- [key in ForgeSupportedLocaleCode]?: TranslationContent;
7
- };
8
- export declare const getTranslationValue: (translationLookup: TranslationContentByLocaleCode, i18nKey: string, locale: ForgeSupportedLocaleCode) => string | null;
9
- export {};
10
- //# sourceMappingURL=translation-value-getter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"translation-value-getter.d.ts","sourceRoot":"","sources":["../../src/utils/translation-value-getter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAEnE,UAAU,kBAAkB;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,kBAAkB,CAAC;CAC5C;AAED,aAAK,8BAA8B,GAAG;KACnC,GAAG,IAAI,wBAAwB,CAAC,CAAC,EAAE,kBAAkB;CACvD,CAAC;AAIF,eAAO,MAAM,mBAAmB,sBACX,8BAA8B,WACxC,MAAM,UACP,wBAAwB,KAC/B,MAAM,GAAG,IAcX,CAAC"}
@@ -1,20 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTranslationValue = void 0;
4
- const tslib_1 = require("tslib");
5
- const get_1 = tslib_1.__importDefault(require("lodash/get"));
6
- const getTranslationValue = (translationLookup, i18nKey, locale) => {
7
- const translation = translationLookup[locale];
8
- if (!translation) {
9
- return null;
10
- }
11
- let translationValue = translation[i18nKey];
12
- if (!translationValue) {
13
- const keyTokens = i18nKey.split('.');
14
- if (keyTokens.length > 1) {
15
- translationValue = (0, get_1.default)(translation, keyTokens, null);
16
- }
17
- }
18
- return typeof translationValue === 'string' ? translationValue : null;
19
- };
20
- exports.getTranslationValue = getTranslationValue;