UNPKG

@metamask/snaps-utils

Version:
128 lines 5.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateSnapManifestLocalizations = exports.getLocalizedSnapManifest = exports.translate = exports.TRANSLATION_REGEX = exports.getLocalizationFile = exports.getValidatedLocalizationFiles = exports.LocalizationFileStruct = exports.LOCALIZABLE_FIELDS = void 0; const snaps_sdk_1 = require("@metamask/snaps-sdk"); const superstruct_1 = require("@metamask/superstruct"); const json_1 = require("./json.cjs"); exports.LOCALIZABLE_FIELDS = ['description', 'proposedName']; exports.LocalizationFileStruct = (0, superstruct_1.object)({ locale: (0, superstruct_1.string)(), messages: (0, superstruct_1.record)((0, superstruct_1.string)(), (0, superstruct_1.object)({ message: (0, superstruct_1.string)(), description: (0, superstruct_1.optional)((0, superstruct_1.string)()), })), }); /** * Validate a list of localization files. * * @param localizationFiles - The localization files to validate. * @returns The validated localization files. * @throws If any of the files are considered invalid. */ function getValidatedLocalizationFiles(localizationFiles) { for (const file of localizationFiles) { try { file.result = (0, superstruct_1.create)((0, json_1.parseJson)(file.toString()), exports.LocalizationFileStruct); } catch (error) { if (error instanceof superstruct_1.StructError) { throw new Error(`Failed to validate localization file "${file.path}": ${error.message}.`); } if (error instanceof SyntaxError) { throw new Error(`Failed to parse localization file "${file.path}" as JSON.`); } throw error; } } return localizationFiles; } exports.getValidatedLocalizationFiles = getValidatedLocalizationFiles; /** * Get the localization file for a given locale. If the locale is not found, * the English localization file will be returned. * * @param locale - The locale to use. * @param localizationFiles - The localization files to use. * @returns The localization file, or `undefined` if no localization file was * found. */ function getLocalizationFile(locale, localizationFiles) { const file = localizationFiles.find((localizationFile) => localizationFile.locale === locale); if (!file) { return localizationFiles.find((localizationFile) => localizationFile.locale === 'en'); } return file; } exports.getLocalizationFile = getLocalizationFile; exports.TRANSLATION_REGEX = /\{\{\s?([a-zA-Z0-9-_\s]+)\s?\}\}/gu; /** * Translate a string using a localization file. This will replace all instances * of `{{key}}` with the localized version of `key`. * * @param value - The string to translate. * @param file - The localization file to use, or `undefined` if no localization * file was found. * @returns The translated string. * @throws If the string contains a key that is not present in the localization * file, or if no localization file was found. */ function translate(value, file) { const matches = value.matchAll(exports.TRANSLATION_REGEX); const array = Array.from(matches); return array.reduce((result, [match, key]) => { if (!file) { throw new Error(`Failed to translate "${value}": No localization file found.`); } const translation = file.messages[key.trim()]; if (!translation) { throw new Error(`Failed to translate "${value}": No translation found for "${key.trim()}" in "${file.locale}" file.`); } return result.replace(match, translation.message); }, value); } exports.translate = translate; /** * Get the localized Snap manifest for a given locale. This will replace all * localized strings in the manifest with the localized version. * * @param snapManifest - The Snap manifest to localize. * @param locale - The locale to use. * @param localizationFiles - The localization files to use. * @returns The localized Snap manifest. */ function getLocalizedSnapManifest(snapManifest, locale, localizationFiles) { const file = getLocalizationFile(locale, localizationFiles); return exports.LOCALIZABLE_FIELDS.reduce((manifest, field) => { const translation = translate(manifest[field], file); return { ...manifest, [field]: translation, }; }, snapManifest); } exports.getLocalizedSnapManifest = getLocalizedSnapManifest; /** * Validate the localization files for a Snap manifest. * * @param snapManifest - The Snap manifest to validate. * @param localizationFiles - The localization files to validate. * @throws If the manifest cannot be localized. */ function validateSnapManifestLocalizations(snapManifest, localizationFiles) { try { // `translate` throws if the manifest cannot be localized, so we just attempt // to translate the manifest using all localization files. localizationFiles .filter((file) => file.locale !== 'en') .forEach((file) => { getLocalizedSnapManifest(snapManifest, file.locale, localizationFiles); }); // The manifest must be localizable in English. getLocalizedSnapManifest(snapManifest, 'en', localizationFiles); } catch (error) { throw new Error(`Failed to localize Snap manifest: ${(0, snaps_sdk_1.getErrorMessage)(error)}`); } } exports.validateSnapManifestLocalizations = validateSnapManifestLocalizations; //# sourceMappingURL=localization.cjs.map