npm package diff

Package: @forge/manifest

Versions: 7.7.0-next.8-experimental-c7a7d36 - 7.7.0-next.11

Removed:package/out/utils/module-i18n-helper.js

Removed:package/out/utils/translation-value-getter.js

Removed:package/out/utils/module-i18n-helper.d.ts.map

Removed:package/out/utils/translation-value-getter.d.ts.map

Removed:package/out/utils/module-i18n-helper.d.ts

Removed:package/out/utils/translation-value-getter.d.ts

Added:package/out/utils/i18n/index.js

Added:package/out/utils/i18n/module-i18n-helper.js

Added:package/out/utils/i18n/translation-value-getter.js

Added:package/out/utils/i18n/index.d.ts.map

Added:package/out/utils/i18n/module-i18n-helper.d.ts.map

Added:package/out/utils/i18n/translation-value-getter.d.ts.map

Added:package/out/utils/i18n/index.d.ts

Added:package/out/utils/i18n/module-i18n-helper.d.ts

Added:package/out/utils/i18n/translation-value-getter.d.ts

Modified:package/out/text/errors.js

Index: package/out/text/errors.js
===================================================================
--- package/out/text/errors.js
+++ package/out/text/errors.js
@@ -182,9 +182,10 @@
         invalidLanguageFile: (languageLocaleCode, path) => `An error occurred while reading JSON file for '${languageLocaleCode}' at the specified path: ${path}`,
         duplicateResourceKey: (languageLocaleCode) => `Duplicate translations resource key found: '${languageLocaleCode}'`,
         i18nKeyNotFound: (keyName) => `i18n key '${keyName}' could not be found in default locale file.`,
         missingTranslationsPropertyError: 'i18n key(s) found but translations property is missing in manifest file',
-        internalI18nPropertyKeyFound: (propertyKey, moduleKey) => `Unexpected property key '${propertyKey}' found in '${moduleKey}' module`
+        internalI18nPropertyKeyFound: (propertyKey, moduleKey) => `Unexpected property key '${propertyKey}' found in '${moduleKey}' module`,
+        i18nValueValidationError: (keyName, languageLocaleCode, errorMsg) => `i18n value for key '${keyName}' for locale '${languageLocaleCode}' ${errorMsg}`
     }
 };
 var References;
 (function (References) {

Modified:package/out/utils/index.js

Index: package/out/utils/index.js
===================================================================
--- package/out/utils/index.js
+++ package/out/utils/index.js
@@ -5,6 +5,5 @@
 tslib_1.__exportStar(require("./line-finder"), exports);
 tslib_1.__exportStar(require("./module-key-cleaner"), exports);
 tslib_1.__exportStar(require("./module-references"), exports);
 tslib_1.__exportStar(require("./manifest-parser-builder"), exports);
-tslib_1.__exportStar(require("./module-i18n-helper"), exports);
-tslib_1.__exportStar(require("./translation-value-getter"), exports);
+tslib_1.__exportStar(require("./i18n"), exports);

Modified:package/out/validators/translations-validator.js

Index: package/out/validators/translations-validator.js
===================================================================
--- package/out/validators/translations-validator.js
+++ package/out/validators/translations-validator.js
@@ -3,16 +3,21 @@
 exports.TranslationsValidator = void 0;
 const tslib_1 = require("tslib");
 const fs_1 = tslib_1.__importDefault(require("fs"));
 const path_1 = require("path");
+const lodash_1 = require("lodash");
+const ajv_1 = tslib_1.__importDefault(require("ajv"));
+const manifest_schema_json_1 = tslib_1.__importDefault(require("../schema/manifest-schema.json"));
 const text_1 = require("../text");
 const text_2 = require("../text");
 const utils_1 = require("../utils");
 class TranslationsValidator {
+    validateCache = new Map();
+    ajv = new ajv_1.default({ allErrors: true, verbose: true, strict: false });
     ensureValidResourcesDefinition(validationErrors, manifest) {
-        const { resources, fallback } = manifest.yamlContent.translations;
+        const { resources } = manifest.yamlContent.translations;
         const resourcesMap = new Map();
-        resources.forEach(({ key, path }) => {
+        for (const { key, path } of resources) {
             if (resourcesMap.has(key)) {
                 validationErrors.push({
                     message: text_1.errors.translations.duplicateResourceKey(key),
                     reference: text_2.References.SchemaError,
@@ -22,18 +27,16 @@
             }
             else {
                 resourcesMap.set(key, path);
             }
-        });
-        let defaultLanguageLookup = {};
-        resourcesMap.forEach((path, key) => {
+        }
+        const allLanguageLookup = {};
+        for (const [key, path] of resourcesMap) {
             const resourcePath = (0, path_1.resolve)(path);
             try {
                 if (fs_1.default.lstatSync(resourcePath).isFile()) {
                     const data = JSON.parse(fs_1.default.readFileSync((0, path_1.resolve)(path), 'utf8'));
-                    if (fallback?.default === key) {
-                        defaultLanguageLookup = data;
-                    }
+                    allLanguageLookup[key] = data;
                 }
             }
             catch (e) {
                 validationErrors.push({
@@ -42,27 +45,27 @@
                     level: 'error',
                     ...(0, utils_1.findPosition)(`path: ${path}`, manifest?.yamlContentByLine)
                 });
             }
-        });
-        return defaultLanguageLookup;
+        }
+        return allLanguageLookup;
     }
     ensureValidFallbackDefinition(validationErrors, manifest) {
         const { resources, fallback } = manifest.yamlContent.translations;
         const defaultLanguage = fallback.default;
         const resourcesSet = new Set(resources.map((resource) => resource.key));
         const fallbackLanguages = Object.keys(fallback).filter((fallbackLanguage) => fallbackLanguage !== 'default');
         const allFallbackLanguagesSet = new Set([defaultLanguage, ...fallbackLanguages]);
-        allFallbackLanguagesSet.forEach((fallbackLanguage) => {
+        for (const fallbackLanguage of allFallbackLanguagesSet) {
             if (!resourcesSet.has(fallbackLanguage)) {
                 validationErrors.push({
                     message: text_1.errors.translations.missingTranslationsJsonFile(fallbackLanguage),
                     reference: text_2.References.SchemaError,
                     level: 'error',
                     ...(0, utils_1.findPosition)(fallbackLanguage === defaultLanguage ? `default: ${fallbackLanguage}` : `${fallbackLanguage}:`, manifest.yamlContentByLine)
                 });
             }
-        });
+        }
         const allLanguagesList = [
             defaultLanguage,
             ...fallbackLanguages,
             ...fallbackLanguages.flatMap((language) => fallback[language])
@@ -70,33 +73,140 @@
         const [, duplicates] = allLanguagesList.reduce(([languageSet, duplicates], language) => {
             languageSet.has(language) ? duplicates.add(language) : languageSet.add(language);
             return [languageSet, duplicates];
         }, [new Set(), new Set()]);
-        duplicates.forEach((duplicate) => {
+        for (const duplicate of duplicates) {
             validationErrors.push({
                 message: text_1.errors.translations.duplicateFallbackConfig(duplicate),
                 reference: text_2.References.SchemaError,
                 level: 'error',
                 ...(0, utils_1.findPosition)(duplicate, manifest.yamlContentByLine)
             });
-        });
+        }
     }
-    ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, defaultLanguageLookup, manifest) {
-        const i18nKeysSet = new Set(i18nKeys);
-        const defaultLocalCode = manifest.yamlContent.translations.fallback.default;
-        const languageLookUp = { [defaultLocalCode]: defaultLanguageLookup };
-        i18nKeysSet.forEach((key) => {
-            const i18nValue = (0, utils_1.getTranslationValue)(languageLookUp, key, defaultLocalCode);
+    getAllLocalesLookup(validationErrors, i18nKeys, translationsLookup, manifest) {
+        const { resources, fallback } = manifest.yamlContent.translations;
+        const defaultLocaleCode = fallback.default;
+        return resources
+            .map((resource) => resource.key)
+            .reduce((allLocalesLookup, locale) => {
+            const i18nMap = this.getI18nMap(i18nKeys, translationsLookup, locale);
+            if (locale === defaultLocaleCode) {
+                this.ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, translationsLookup, locale, manifest);
+            }
+            allLocalesLookup.set(locale, i18nMap);
+            return allLocalesLookup;
+        }, new Map());
+    }
+    ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, translationsLookup, locale, manifest) {
+        for (const i18nKey of i18nKeys) {
+            const i18nValue = (0, utils_1.getTranslationValue)(translationsLookup, i18nKey, locale);
             if (!i18nValue) {
                 validationErrors.push({
-                    message: text_1.errors.translations.i18nKeyNotFound(key),
+                    message: text_1.errors.translations.i18nKeyNotFound(i18nKey),
                     reference: text_2.References.SchemaError,
                     level: 'error',
-                    ...(0, utils_1.findPosition)(`i18n: ${key}`, manifest.yamlContentByLine)
+                    ...(0, utils_1.findPosition)(`i18n: ${i18nKey}`, manifest.yamlContentByLine)
                 });
             }
+        }
+    }
+    getI18nMap(i18nKeys, translationsLookup, locale) {
+        return i18nKeys.reduce((i18nMap, key) => {
+            const i18nValue = (0, utils_1.getTranslationValue)(translationsLookup, key, locale);
+            if (i18nValue) {
+                i18nMap.set(key, i18nValue);
+            }
+            return i18nMap;
+        }, new Map());
+    }
+    getI18nPropertySchema(schemaSlice, i18nPath) {
+        if (typeof schemaSlice !== 'object' || schemaSlice === null) {
+            return [];
+        }
+        const [propertyName, ...restPath] = i18nPath;
+        if (Array.isArray(schemaSlice)) {
+            return schemaSlice.flatMap((object) => {
+                return this.getI18nPropertySchema(object, i18nPath);
+            });
+        }
+        return Object.entries(schemaSlice).flatMap(([key, value]) => {
+            if (key === propertyName) {
+                if (restPath.length === 0 && typeof value === 'object') {
+                    return [value];
+                }
+                else if (restPath.length > 0) {
+                    return this.getI18nPropertySchema(value, restPath);
+                }
+                else {
+                    return [];
+                }
+            }
+            else {
+                return this.getI18nPropertySchema(value, i18nPath);
+            }
         });
     }
+    getValidateI18nFn(i18nPropertySchema) {
+        const schemaKey = JSON.stringify(i18nPropertySchema);
+        if (this.validateCache.has(schemaKey)) {
+            return this.validateCache.get(schemaKey);
+        }
+        const validate = this.ajv.compile(i18nPropertySchema);
+        this.validateCache.set(schemaKey, validate);
+        return validate;
+    }
+    getI18nPropertyValidator({ modulesSchema, i18nPropertyPath, i18nKey, locale, manifest }) {
+        const i18nPropertySchemas = this.getI18nPropertySchema(modulesSchema, i18nPropertyPath);
+        return (i18nValue) => {
+            const validationResults = i18nPropertySchemas.reduce((validationResults, i18nPropertySchema) => {
+                const validate = this.getValidateI18nFn(i18nPropertySchema);
+                if (!validationResults.isValid && !validate(i18nValue)) {
+                    const validationErrors = validate.errors.reduce((validationErrors, validationError) => {
+                        if (validationError.message) {
+                            validationErrors.push({
+                                message: text_1.errors.translations.i18nValueValidationError(i18nKey, locale, validationError.message),
+                                reference: text_2.References.SchemaError,
+                                level: 'error',
+                                ...(0, utils_1.findPosition)(`i18n: ${i18nKey}`, manifest?.yamlContentByLine)
+                            });
+                        }
+                        return validationErrors;
+                    }, []);
+                    validationResults.errors.push(validationErrors);
+                }
+                else {
+                    validationResults.isValid = true;
+                }
+                return validationResults;
+            }, { errors: [], isValid: false });
+            return validationResults.isValid ? [] : validationResults.errors;
+        };
+    }
+    ensureValidI18nValue(validationErrors, i18nMap, moduleI18nProperties, locale, manifest) {
+        for (const i18n of moduleI18nProperties) {
+            const i18nValue = i18nMap.get(i18n.key);
+            if (i18nValue) {
+                const modulesSchema = (0, lodash_1.get)(manifest_schema_json_1.default.definitions.ModuleSchema.properties, i18n.moduleName);
+                const validator = this.getI18nPropertyValidator({
+                    modulesSchema,
+                    i18nPropertyPath: i18n.propertyPath,
+                    i18nKey: i18n.key,
+                    locale,
+                    manifest
+                });
+                const validationResults = validator(i18nValue);
+                if (validationResults.length > 0) {
+                    validationErrors.push(...validationResults[0]);
+                }
+            }
+        }
+    }
+    ensureAllValidI18nValue(validationErrors, allI18nMap, moduleI18nProperties, manifest) {
+        for (const [locale, i18nMap] of allI18nMap) {
+            this.ensureValidI18nValue(validationErrors, i18nMap, moduleI18nProperties, locale, manifest);
+        }
+    }
     validateManifestWithoutI18nConfig(manifest, i18nKeys) {
         if (i18nKeys.length === 0) {
             return {
                 success: true,
@@ -116,13 +226,14 @@
             manifestObject: manifest,
             errors: missingTranslationsPropertyError
         };
     }
-    validateManifestI18nConfig(manifest, i18nKeys) {
+    validateManifestI18nConfig(manifest, i18nKeys, moduleI18nProperties) {
         const validationErrors = [];
-        const defaultLanguageLookup = this.ensureValidResourcesDefinition(validationErrors, manifest);
+        const allLanguageLookup = this.ensureValidResourcesDefinition(validationErrors, manifest);
         this.ensureValidFallbackDefinition(validationErrors, manifest);
-        this.ensureI18nKeysExistInDefaultJson(validationErrors, i18nKeys, defaultLanguageLookup, manifest);
+        const i18nMap = this.getAllLocalesLookup(validationErrors, i18nKeys, allLanguageLookup, manifest);
+        this.ensureAllValidI18nValue(validationErrors, i18nMap, moduleI18nProperties, manifest);
         return validationErrors;
     }
     validateInternalI18nPropertyKeysNotInModules(manifest) {
         const modules = manifest?.typedContent?.modules ?? {};
@@ -140,15 +251,16 @@
                 success: false,
                 manifestObject: manifest
             };
         }
-        const i18nKeys = (0, utils_1.extractI18nKeysFromModules)(manifest?.typedContent?.modules ?? {});
+        const moduleI18nProperties = (0, utils_1.extractI18nPropertiesFromModules)(manifest?.typedContent?.modules ?? {});
+        const i18nKeys = moduleI18nProperties.map((i18nConfig) => i18nConfig.key);
         const i18nConfig = manifest?.yamlContent?.translations;
         if (!i18nConfig) {
             return this.validateManifestWithoutI18nConfig(manifest, i18nKeys);
         }
         const validationErrors = [
-            ...this.validateManifestI18nConfig(manifest, i18nKeys),
+            ...this.validateManifestI18nConfig(manifest, i18nKeys, moduleI18nProperties),
             ...this.validateInternalI18nPropertyKeysNotInModules(manifest)
         ];
         return {
             success: validationErrors.length === 0,

Modified:package/package.json

Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@forge/manifest",
-  "version": "7.7.0-next.8-experimental-c7a7d36",
+  "version": "7.7.0-next.11",
   "description": "Definitions and validations of the Forge manifest",
   "main": "out/index.js",
   "scripts": {
     "build": "yarn run compile",

Modified:package/out/text/errors.d.ts.map

Index: package/out/text/errors.d.ts.map
===================================================================
--- package/out/text/errors.d.ts.map
+++ package/out/text/errors.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/text/errors.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/text/errors.ts"],"names":[],"mappings":"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"}
\ No newline at end of file

Modified:package/out/utils/index.d.ts.map

Index: package/out/utils/index.d.ts.map
===================================================================
--- package/out/utils/index.d.ts.map
+++ package/out/utils/index.d.ts.map
@@ -1,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"}
\ No newline at end of file
+{"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"}
\ No newline at end of file

Modified:package/out/validators/translations-validator.d.ts.map

Index: package/out/validators/translations-validator.d.ts.map
===================================================================
--- package/out/validators/translations-validator.d.ts.map
+++ package/out/validators/translations-validator.d.ts.map
@@ -1,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"}
\ No newline at end of file
+{"version":3,"file":"translations-validator.d.ts","sourceRoot":"","sources":["../../src/validators/translations-validator.ts"],"names":[],"mappings":"AAKA,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;AAW3D,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;IA+CrC,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"}
\ No newline at end of file

Modified:package/CHANGELOG.md

Index: package/CHANGELOG.md
===================================================================
--- package/CHANGELOG.md
+++ package/CHANGELOG.md
@@ -1,27 +1,25 @@
 # @forge/manifest
 
-## 7.7.0-next.8-experimental-c7a7d36
+## 7.7.0-next.11
 
 ### Minor Changes
 
-- 7e506ec: Show warning if action doesn't have name attribute
-- 7e506ec: Show warning if action is not referenced by any agent
-- 7e506ec: Interpolate string resources in modules
-- 7e506ec: Lint unique module key across Connect and Forge modules
+- bf34881: Add translations schema to manifest schema template to enable Forge i18n support.
+  Additionally relevant validators (i.e. `translations-validator`) are added to validate the translations schema in the manifest.
 
+## 7.7.0-next.10
+
 ### Patch Changes
 
-- 7e506ec: Update package readme to include instruction on how to update schema in the package
-- 7e506ec: Add translations section in manifest schema for Forge i18n Support (EAP)
-- 7e506ec: Update unit test in manifest validator
-- 7e506ec: Update manifest definitions
-- 7e506ec: Update manifest definitions
-- 7e506ec: Update manifest definitions
-- 7e506ec: Update manifest definitions
-- 7e506ec: Update manifest definitions
-- 7e506ec: Update manifest definitions
+- 26f8528: Update manifest definitions
 
+## 7.7.0-next.9
+
+### Patch Changes
+
+- 13fb92c: Update forge repo with unit tests for manifest schema changes Jira, Confluence, Bitbucket
+
 ## 7.7.0-next.8
 
 ### Patch Changes

Modified:package/out/text/errors.d.ts

Index: package/out/text/errors.d.ts
===================================================================
--- package/out/text/errors.d.ts
+++ package/out/text/errors.d.ts
@@ -1,4 +1,5 @@
+import { type ForgeSupportedLocaleCode } from '../schema/manifest';
 import { AllModuleTypes } from '../types';
 export declare const errors: {
     invalidManifest: (reason: string) => string;
     missingManifest: () => string;
@@ -163,15 +164,16 @@
             };
         };
     };
     translations: {
-        missingTranslationsJsonFile: (languageLocaleCode: string) => string;
-        duplicateFallbackConfig: (languageLocaleCode: string) => string;
-        invalidLanguageFile: (languageLocaleCode: string, path: string) => string;
-        duplicateResourceKey: (languageLocaleCode: string) => string;
+        missingTranslationsJsonFile: (languageLocaleCode: ForgeSupportedLocaleCode) => string;
+        duplicateFallbackConfig: (languageLocaleCode: ForgeSupportedLocaleCode) => string;
+        invalidLanguageFile: (languageLocaleCode: ForgeSupportedLocaleCode, path: string) => string;
+        duplicateResourceKey: (languageLocaleCode: ForgeSupportedLocaleCode) => string;
         i18nKeyNotFound: (keyName: string) => string;
         missingTranslationsPropertyError: string;
         internalI18nPropertyKeyFound: (propertyKey: string, moduleKey: string) => string;
+        i18nValueValidationError: (keyName: string, languageLocaleCode: ForgeSupportedLocaleCode, errorMsg: string) => string;
     };
 };
 export declare enum References {
     MissingManifest = "manifest-file-required",

Modified:package/out/utils/index.d.ts

Index: package/out/utils/index.d.ts
===================================================================
--- package/out/utils/index.d.ts
+++ package/out/utils/index.d.ts
@@ -3,7 +3,6 @@
 export * from './module-key-cleaner';
 export * from './module-references';
 export * from './manifest-parser-builder';
 export type { ManifestParser } from './manifest-parser';
-export * from './module-i18n-helper';
-export * from './translation-value-getter';
+export * from './i18n';
 //# sourceMappingURL=index.d.ts.map
\ No newline at end of file

Modified:package/out/validators/translations-validator.d.ts

Index: package/out/validators/translations-validator.d.ts
===================================================================
--- package/out/validators/translations-validator.d.ts
+++ package/out/validators/translations-validator.d.ts
@@ -1,11 +1,20 @@
 import { type ManifestSchema } from '../schema/manifest';
 import { ManifestObject, ManifestValidationResult } from '../types';
 import { ValidatorInterface } from './validator-interface';
 export declare class TranslationsValidator implements ValidatorInterface<ManifestObject<ManifestSchema> | undefined, ManifestSchema> {
+    private validateCache;
+    private ajv;
     private ensureValidResourcesDefinition;
     private ensureValidFallbackDefinition;
+    private getAllLocalesLookup;
     private ensureI18nKeysExistInDefaultJson;
+    private getI18nMap;
+    private getI18nPropertySchema;
+    private getValidateI18nFn;
+    private getI18nPropertyValidator;
+    private ensureValidI18nValue;
+    private ensureAllValidI18nValue;
     private validateManifestWithoutI18nConfig;
     private validateManifestI18nConfig;
     private validateInternalI18nPropertyKeysNotInModules;
     validate(manifest: ManifestObject<ManifestSchema> | undefined): Promise<ManifestValidationResult<ManifestSchema>>;