@metamask/snaps-utils
Version:
A collection of utilities for MetaMask Snaps
1 lines • 8.39 kB
Source Map (JSON)
{"version":3,"file":"localization.cjs","sourceRoot":"","sources":["../src/localization.ts"],"names":[],"mappings":"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","sourcesContent":["import { getErrorMessage } from '@metamask/snaps-sdk';\nimport type { Infer } from '@metamask/superstruct';\nimport {\n create,\n object,\n optional,\n record,\n string,\n StructError,\n} from '@metamask/superstruct';\n\nimport { parseJson } from './json';\nimport type { SnapManifest } from './manifest';\nimport type { VirtualFile } from './virtual-file';\n\nexport const LOCALIZABLE_FIELDS = ['description', 'proposedName'] as const;\n\nexport const LocalizationFileStruct = object({\n locale: string(),\n messages: record(\n string(),\n object({\n message: string(),\n description: optional(string()),\n }),\n ),\n});\n\nexport type LocalizationFile = Infer<typeof LocalizationFileStruct>;\n\n/**\n * Validate a list of localization files.\n *\n * @param localizationFiles - The localization files to validate.\n * @returns The validated localization files.\n * @throws If any of the files are considered invalid.\n */\nexport function getValidatedLocalizationFiles(\n localizationFiles: VirtualFile[],\n): VirtualFile<LocalizationFile>[] {\n for (const file of localizationFiles) {\n try {\n file.result = create(parseJson(file.toString()), LocalizationFileStruct);\n } catch (error) {\n if (error instanceof StructError) {\n throw new Error(\n `Failed to validate localization file \"${file.path}\": ${error.message}.`,\n );\n }\n\n if (error instanceof SyntaxError) {\n throw new Error(\n `Failed to parse localization file \"${file.path}\" as JSON.`,\n );\n }\n\n throw error;\n }\n }\n\n return localizationFiles as VirtualFile<LocalizationFile>[];\n}\n\n/**\n * Get the localization file for a given locale. If the locale is not found,\n * the English localization file will be returned.\n *\n * @param locale - The locale to use.\n * @param localizationFiles - The localization files to use.\n * @returns The localization file, or `undefined` if no localization file was\n * found.\n */\nexport function getLocalizationFile(\n locale: string,\n localizationFiles: LocalizationFile[],\n) {\n const file = localizationFiles.find(\n (localizationFile) => localizationFile.locale === locale,\n );\n\n if (!file) {\n return localizationFiles.find(\n (localizationFile) => localizationFile.locale === 'en',\n );\n }\n\n return file;\n}\n\nexport const TRANSLATION_REGEX = /\\{\\{\\s?([a-zA-Z0-9-_\\s]+)\\s?\\}\\}/gu;\n\n/**\n * Translate a string using a localization file. This will replace all instances\n * of `{{key}}` with the localized version of `key`.\n *\n * @param value - The string to translate.\n * @param file - The localization file to use, or `undefined` if no localization\n * file was found.\n * @returns The translated string.\n * @throws If the string contains a key that is not present in the localization\n * file, or if no localization file was found.\n */\nexport function translate(value: string, file: LocalizationFile | undefined) {\n const matches = value.matchAll(TRANSLATION_REGEX);\n const array = Array.from(matches);\n\n return array.reduce<string>((result, [match, key]) => {\n if (!file) {\n throw new Error(\n `Failed to translate \"${value}\": No localization file found.`,\n );\n }\n\n const translation = file.messages[key.trim()];\n if (!translation) {\n throw new Error(\n `Failed to translate \"${value}\": No translation found for \"${key.trim()}\" in \"${\n file.locale\n }\" file.`,\n );\n }\n\n return result.replace(match, translation.message);\n }, value);\n}\n\n/**\n * Get the localized Snap manifest for a given locale. This will replace all\n * localized strings in the manifest with the localized version.\n *\n * @param snapManifest - The Snap manifest to localize.\n * @param locale - The locale to use.\n * @param localizationFiles - The localization files to use.\n * @returns The localized Snap manifest.\n */\nexport function getLocalizedSnapManifest(\n snapManifest: SnapManifest,\n locale: string,\n localizationFiles: LocalizationFile[],\n) {\n const file = getLocalizationFile(locale, localizationFiles);\n\n return LOCALIZABLE_FIELDS.reduce((manifest, field) => {\n const translation = translate(manifest[field], file);\n return {\n ...manifest,\n [field]: translation,\n };\n }, snapManifest);\n}\n\n/**\n * Validate the localization files for a Snap manifest.\n *\n * @param snapManifest - The Snap manifest to validate.\n * @param localizationFiles - The localization files to validate.\n * @throws If the manifest cannot be localized.\n */\nexport function validateSnapManifestLocalizations(\n snapManifest: SnapManifest,\n localizationFiles: LocalizationFile[],\n) {\n try {\n // `translate` throws if the manifest cannot be localized, so we just attempt\n // to translate the manifest using all localization files.\n localizationFiles\n .filter((file) => file.locale !== 'en')\n .forEach((file) => {\n getLocalizedSnapManifest(snapManifest, file.locale, localizationFiles);\n });\n\n // The manifest must be localizable in English.\n getLocalizedSnapManifest(snapManifest, 'en', localizationFiles);\n } catch (error) {\n throw new Error(\n `Failed to localize Snap manifest: ${getErrorMessage(error)}`,\n );\n }\n}\n"]}