{"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"]}