From e982588aed5b3b58f7e3a18897084d8c6882d333 Mon Sep 17 00:00:00 2001 From: Sasha Sorokin <10401817+brawaru@users.noreply.github.com> Date: Sun, 11 Jun 2023 19:08:16 +0100 Subject: [PATCH] Add internationalization support (#738) --- composables/compact-number.ts | 18 ++ composables/how-ago.ts | 18 ++ crowdin.yml | 7 + locales/en-US/index.json | 17 ++ locales/en-US/languages.json | 3 + locales/en-US/meta.json | 6 + nuxt.config.ts | 91 +++++++- package.json | 8 +- pages/[type]/[id]/gallery.vue | 4 +- pages/frog.vue | 60 ++++- pnpm-lock.yaml | 419 ++++++++++++++++++++++++++++++++++ types/vintl.d.ts | 10 + 12 files changed, 651 insertions(+), 10 deletions(-) create mode 100644 composables/compact-number.ts create mode 100644 composables/how-ago.ts create mode 100644 crowdin.yml create mode 100644 locales/en-US/index.json create mode 100644 locales/en-US/languages.json create mode 100644 locales/en-US/meta.json create mode 100644 types/vintl.d.ts diff --git a/composables/compact-number.ts b/composables/compact-number.ts new file mode 100644 index 00000000000..5970bb0506c --- /dev/null +++ b/composables/compact-number.ts @@ -0,0 +1,18 @@ +import { createFormatter, type Formatter } from '@vintl/compact-number' +import { IntlController } from '@vintl/vintl/controller' + +const formatters = new WeakMap, Formatter>() + +export function useCompactNumber(): Formatter { + const vintl = useVIntl() + + let formatter = formatters.get(vintl) + + if (formatter == null) { + const formatterRef = computed(() => createFormatter(vintl.intl)) + formatter = (value, options) => formatterRef.value(value, options) + formatters.set(vintl, formatter) + } + + return formatter +} diff --git a/composables/how-ago.ts b/composables/how-ago.ts new file mode 100644 index 00000000000..499b4ceec75 --- /dev/null +++ b/composables/how-ago.ts @@ -0,0 +1,18 @@ +import { createFormatter, type Formatter } from '@vintl/how-ago' +import { IntlController } from '@vintl/vintl/controller' + +const formatters = new WeakMap, Formatter>() + +export function useRelativeTime(): Formatter { + const vintl = useVIntl() + + let formatter = formatters.get(vintl) + + if (formatter == null) { + const formatterRef = computed(() => createFormatter(vintl.intl)) + formatter = (value, options) => formatterRef.value(value, options) + formatters.set(vintl, formatter) + } + + return formatter +} diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000000..a1522367d6e --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,7 @@ +project_id: 518556 +preserve_hierarchy: true + +files: + - source: /locales/en-US/* + dest: /%original_file_name% + translation: /locales/%locale%/%original_file_name% diff --git a/locales/en-US/index.json b/locales/en-US/index.json new file mode 100644 index 00000000000..82ee14ec076 --- /dev/null +++ b/locales/en-US/index.json @@ -0,0 +1,17 @@ +{ + "frog": { + "message": "You've been frogged! 🐸" + }, + "frog.altText": { + "message": "A photorealistic painting of a frog labyrinth" + }, + "frog.froggedPeople": { + "message": "{count, plural, one {{count} more person} other {{count} more people}} were also frogged!" + }, + "frog.sinceOpened": { + "message": "This page was opened {ago}" + }, + "frog.title": { + "message": "Frog" + } +} diff --git a/locales/en-US/languages.json b/locales/en-US/languages.json new file mode 100644 index 00000000000..139d95c7636 --- /dev/null +++ b/locales/en-US/languages.json @@ -0,0 +1,3 @@ +{ + "en-US": "American English" +} diff --git a/locales/en-US/meta.json b/locales/en-US/meta.json new file mode 100644 index 00000000000..a171dc51658 --- /dev/null +++ b/locales/en-US/meta.json @@ -0,0 +1,6 @@ +{ + "displayName": { + "description": "The name of the language in dialect form (e.g. Français canadien for French spoken in Canada, not French (Canada))", + "message": "American English" + } +} diff --git a/nuxt.config.ts b/nuxt.config.ts index 576903584df..b18a5baf95c 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,8 +1,11 @@ import { promises as fs } from 'fs' +import { pathToFileURL } from 'node:url' import svgLoader from 'vite-svg-loader' -import { resolve } from 'pathe' +import { resolve, basename } from 'pathe' import { defineNuxtConfig } from 'nuxt/config' import { $fetch } from 'ofetch' +import { globIterate } from 'glob' +import { match as matchLocale } from '@formatjs/intl-localematcher' const STAGING_API_URL = 'https://staging-api.modrinth.com/v2/' const STAGING_ARIADNE_URL = 'https://staging-ariadne.modrinth.com/v1/' @@ -39,6 +42,14 @@ const meta = { 'twitter:site': '@modrinth', } +/** + * Tags of locales that are auto-discovered besides the default locale. + * + * Preferably only the locales that reach a certain threshold of complete + * translations would be included in this array. + */ +const ENABLED_LOCALES: string[] = [] + export default defineNuxtConfig({ app: { head: { @@ -176,6 +187,75 @@ export default defineNuxtConfig({ }) ) }, + async 'vintl:extendOptions'(opts) { + opts.locales ??= [] + + const resolveCompactNumberDataImport = await (async () => { + const compactNumberLocales: string[] = [] + const resolvedImports = new Map() + + for await (const localeFile of globIterate( + 'node_modules/@vintl/compact-number/dist/locale-data/*.mjs', + { ignore: '**/*.data.mjs' } + )) { + const tag = basename(localeFile, '.mjs') + compactNumberLocales.push(tag) + resolvedImports.set(tag, String(pathToFileURL(resolve(localeFile)))) + } + + function resolveImport(tag: string) { + const matchedTag = matchLocale([tag], compactNumberLocales, 'en-x-placeholder') + return matchedTag === 'en-x-placeholder' + ? undefined + : `@vintl/compact-number/locale-data/${matchedTag}` + } + + return resolveImport + })() + + for await (const localeDir of globIterate('locales/*/', { posix: true })) { + const tag = basename(localeDir) + if (!ENABLED_LOCALES.includes(tag) && opts.defaultLocale !== tag) continue + + const locale = + opts.locales.find((locale) => locale.tag === tag) ?? + opts.locales[opts.locales.push({ tag }) - 1] + + for await (const localeFile of globIterate(`${localeDir}/*`, { posix: true })) { + const fileName = basename(localeFile) + if (fileName === 'index.json') { + if (locale.file == null) { + locale.file = { + from: `./${localeFile}`, + format: 'crowdin', + } + } else { + ;(locale.files ??= []).push({ + from: `./${localeFile}`, + format: 'crowdin', + }) + } + } else if (fileName === 'meta.json') { + /** @type {Record} */ + const meta = await fs.readFile(localeFile, 'utf8').then((date) => JSON.parse(date)) + locale.meta ??= {} + for (const key in meta) { + locale.meta[key] = meta[key].message + } + } else { + ;(locale.resources ??= {})[fileName] = `./${localeFile}` + } + } + + const cnDataImport = resolveCompactNumberDataImport(tag) + if (cnDataImport != null) { + ;(locale.additionalImports ??= []).push({ + from: cnDataImport, + resolve: false, + }) + } + } + }, }, runtimeConfig: { apiBaseUrl: process.env.BASE_URL ?? getApiUrl(), @@ -202,6 +282,15 @@ export default defineNuxtConfig({ }, }, }, + modules: ['@vintl/nuxt'], + vintl: { + defaultLocale: 'en-US', + storage: 'cookie', + parserless: 'only-prod', + }, + nitro: { + moduleSideEffects: ['@vintl/compact-number/locale-data'], + }, }) function getApiUrl() { diff --git a/package.json b/package.json index 113d8ad583c..da3d52dc3ca 100644 --- a/package.json +++ b/package.json @@ -8,19 +8,25 @@ "postinstall": "nuxi prepare", "lint:js": "eslint . --ext .js,.vue,.ts", "lint": "npm run lint:js && prettier --check .", - "fix": "eslint . --fix --ext .js,.vue,.ts && prettier --write ." + "fix": "eslint . --fix --ext .js,.vue,.ts && prettier --write .", + "intl:extract": "formatjs extract \"{,components,composables,layouts,middleware,modules,pages,plugins,utils}/**/*.{vue,ts,tsx,js,jsx,mts,cts,mjs,cjs}\" --ignore '**/*.d.ts' --ignore 'node_modules' --out-file locales/en-US/index.json --format crowdin" }, "devDependencies": { + "@formatjs/cli": "^6.1.2", "@nuxtjs/eslint-config-typescript": "^12.0.0", "@types/node": "^20.1.0", "@typescript-eslint/eslint-plugin": "^5.59.8", "@typescript-eslint/parser": "^5.59.8", + "@vintl/compact-number": "^2.0.4", + "@vintl/how-ago": "^2.0.1", + "@vintl/nuxt": "^1.2.2", "eslint": "^8.41.0", "eslint-config-prettier": "^8.8.0", "eslint-import-resolver-typescript": "^3.5.5", "eslint-plugin-import": "^2.27.5", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-vue": "^9.14.1", + "glob": "^10.2.7", "nuxt": "^3.5.3", "prettier": "^2.8.8", "sass": "^1.58.0", diff --git a/pages/[type]/[id]/gallery.vue b/pages/[type]/[id]/gallery.vue index ed7692f9e67..9ba31d11eda 100644 --- a/pages/[type]/[id]/gallery.vue +++ b/pages/[type]/[id]/gallery.vue @@ -150,10 +150,10 @@ : 'https://cdn.modrinth.com/placeholder-banner.svg' " :alt="expandedGalleryItem.title ? expandedGalleryItem.title : 'gallery-image'" - @click.stop="" + @click.stop /> -
+

{{ expandedGalleryItem.title }} diff --git a/pages/frog.vue b/pages/frog.vue index e3512c00ed4..7b61486cb86 100644 --- a/pages/frog.vue +++ b/pages/frog.vue @@ -1,11 +1,59 @@ + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 664c7afaad5..5e0bbef7af9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,9 @@ dependencies: version: 1.0.14 devDependencies: + '@formatjs/cli': + specifier: ^6.1.2 + version: 6.1.2 '@nuxtjs/eslint-config-typescript': specifier: ^12.0.0 version: 12.0.0(eslint@8.42.0)(typescript@5.0.4) @@ -46,6 +49,15 @@ devDependencies: '@typescript-eslint/parser': specifier: ^5.59.8 version: 5.59.9(eslint@8.42.0)(typescript@5.0.4) + '@vintl/compact-number': + specifier: ^2.0.4 + version: 2.0.4(@formatjs/intl@2.7.2) + '@vintl/how-ago': + specifier: ^2.0.1 + version: 2.0.1(@formatjs/intl@2.7.2) + '@vintl/nuxt': + specifier: ^1.2.2 + version: 1.2.2(typescript@5.0.4)(vite@4.3.9)(vue@3.3.4) eslint: specifier: ^8.41.0 version: 8.42.0 @@ -64,6 +76,9 @@ devDependencies: eslint-plugin-vue: specifier: ^9.14.1 version: 9.14.1(eslint@8.42.0) + glob: + specifier: ^10.2.7 + version: 10.2.7 nuxt: specifier: ^3.5.3 version: 3.5.3(@types/node@20.2.5)(eslint@8.42.0)(sass@1.63.2)(typescript@5.0.4)(vue-tsc@1.6.5) @@ -394,6 +409,14 @@ packages: '@babel/helper-validator-identifier': 7.22.5 to-fast-properties: 2.0.0 + /@braw/async-computed@5.0.2(vue@3.3.4): + resolution: {integrity: sha512-fThqjZBTPvWtbD90Nkd4IldN7dpCkxfvthuk12ZBjkPPjh+wuRGi3HYiUqUSAOOVS0NHSxpsQFfg+qO275FtYA==} + peerDependencies: + vue: ^2.7 || ^3.2.45 + dependencies: + vue: 3.3.4 + dev: true + /@cloudflare/kv-asset-handler@0.3.0: resolution: {integrity: sha512-9CB/MKf/wdvbfkUdfrj+OkEwZ5b7rws0eogJ4293h+7b6KX5toPwym+VQKmILafNB9YiehqY0DlNrDcDhdWHSQ==} dependencies: @@ -645,6 +668,132 @@ packages: '@floating-ui/core': 0.3.1 dev: false + /@formatjs/cli-lib@6.1.1: + resolution: {integrity: sha512-Wal5E7iBWcENfGBti9rmxCHUz1C5k3PJliP/KiIJEqrafzKo54xusdTZtSyHCP/cJhH19ohiNZpA6D+e6wLvjA==} + engines: {node: '>= 16'} + peerDependencies: + '@vue/compiler-core': ^3.2.23 + '@vue/compiler-sfc': ^3.2.34 + peerDependenciesMeta: + '@vue/compiler-core': + optional: true + '@vue/compiler-sfc': + optional: true + dependencies: + '@formatjs/icu-messageformat-parser': 2.4.0 + '@formatjs/ts-transformer': 3.13.1 + '@types/estree': 0.0.50 + '@types/fs-extra': 9.0.13 + '@types/json-stable-stringify': 1.0.34 + '@types/node': 17.0.45 + chalk: 4.1.2 + commander: 8.3.0 + fast-glob: 3.2.12 + fs-extra: 10.1.0 + json-stable-stringify: 1.0.2 + loud-rejection: 2.2.0 + tslib: 2.5.3 + typescript: 5.0.4 + transitivePeerDependencies: + - ts-jest + dev: true + + /@formatjs/cli@6.1.2: + resolution: {integrity: sha512-npYK86T/6KAGloIRsX9jKjTkm9PIchGv5cPK9sE4+/kPfml0vFmLoVFxYkHu25FV5CMf0jnvodnLOIkhH46kvQ==} + engines: {node: '>= 16'} + hasBin: true + peerDependencies: + '@vue/compiler-sfc': ^3.2.34 + peerDependenciesMeta: + '@vue/compiler-sfc': + optional: true + dev: true + + /@formatjs/ecma402-abstract@1.15.0: + resolution: {integrity: sha512-7bAYAv0w4AIao9DNg0avfOLTCPE9woAgs6SpXuMq11IN3A+l+cq8ghczwqSZBM11myvPSJA7vLn72q0rJ0QK6Q==} + dependencies: + '@formatjs/intl-localematcher': 0.2.32 + tslib: 2.5.3 + dev: true + + /@formatjs/fast-memoize@2.0.1: + resolution: {integrity: sha512-M2GgV+qJn5WJQAYewz7q2Cdl6fobQa69S1AzSM2y0P68ZDbK5cWrJIcPCO395Of1ksftGZoOt4LYCO/j9BKBSA==} + dependencies: + tslib: 2.5.3 + dev: true + + /@formatjs/icu-messageformat-parser@2.4.0: + resolution: {integrity: sha512-6Dh5Z/gp4F/HovXXu/vmd0If5NbYLB5dZrmhWVNb+BOGOEU3wt7Z/83KY1dtd7IDhAnYHasbmKE1RbTE0J+3hw==} + dependencies: + '@formatjs/ecma402-abstract': 1.15.0 + '@formatjs/icu-skeleton-parser': 1.4.0 + tslib: 2.5.3 + dev: true + + /@formatjs/icu-skeleton-parser@1.4.0: + resolution: {integrity: sha512-Qq347VM616rVLkvN6QsKJELazRyNlbCiN47LdH0Mc5U7E2xV0vatiVhGqd3KFgbc055BvtnUXR7XX60dCGFuWg==} + dependencies: + '@formatjs/ecma402-abstract': 1.15.0 + tslib: 2.5.3 + dev: true + + /@formatjs/intl-displaynames@6.3.2: + resolution: {integrity: sha512-kBOh0O7QYKLUqaZujLSEF2+au017plPp63R6Hrokl+oDtLyTt9y9pEuCTbOKh/P8CC9THnDLKRKgeVWZw5Ek8A==} + dependencies: + '@formatjs/ecma402-abstract': 1.15.0 + '@formatjs/intl-localematcher': 0.2.32 + tslib: 2.5.3 + dev: true + + /@formatjs/intl-listformat@7.2.2: + resolution: {integrity: sha512-YIruRGwUrmgVOXjWi6VbwPcRNBkEfgK2DFjyyqopCmpfJ+39vnl46oLpVchErnuXs6kkARy5GcGaGV7xRsH4lw==} + dependencies: + '@formatjs/ecma402-abstract': 1.15.0 + '@formatjs/intl-localematcher': 0.2.32 + tslib: 2.5.3 + dev: true + + /@formatjs/intl-localematcher@0.2.32: + resolution: {integrity: sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==} + dependencies: + tslib: 2.5.3 + dev: true + + /@formatjs/intl@2.7.2(typescript@5.0.4): + resolution: {integrity: sha512-ziiQfnXwY0/rXhtohSAmYMqDjRsihoMKdl8H2aA+FvxG9638E0XrvfBFCb+1HhimNiuqRz5fTY7F/bZtsJxsjA==} + peerDependencies: + typescript: ^4.7 || 5 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@formatjs/ecma402-abstract': 1.15.0 + '@formatjs/fast-memoize': 2.0.1 + '@formatjs/icu-messageformat-parser': 2.4.0 + '@formatjs/intl-displaynames': 6.3.2 + '@formatjs/intl-listformat': 7.2.2 + intl-messageformat: 10.3.5 + tslib: 2.5.3 + typescript: 5.0.4 + dev: true + + /@formatjs/ts-transformer@3.13.1: + resolution: {integrity: sha512-U5BuLqFx5wre5Q0NrZhBh7itMJZISYuZGoj8HdN/UO1EKaTL2HQjE1G040GjTpY0k+AAyaHK3b8WPqgHLvIaIQ==} + peerDependencies: + ts-jest: '>=27' + peerDependenciesMeta: + ts-jest: + optional: true + dependencies: + '@formatjs/icu-messageformat-parser': 2.4.0 + '@types/json-stable-stringify': 1.0.34 + '@types/node': 17.0.45 + chalk: 4.1.2 + json-stable-stringify: 1.0.2 + tslib: 2.5.3 + typescript: 5.0.4 + dev: true + /@humanwhocodes/config-array@0.11.10: resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} engines: {node: '>=10.10.0'} @@ -669,6 +818,18 @@ packages: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} dev: true + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} @@ -941,6 +1102,13 @@ packages: - supports-color dev: true + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + /@pkgr/utils@2.4.1: resolution: {integrity: sha512-JOqwkgFEyi+OROIyq7l4Jy28h/WwhDnG/cPkXG2Z1iFbubB6jsHW1NDvmyOzTBxHr3yg68YGirmh1JUgMqa+9w==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1106,10 +1274,20 @@ packages: '@types/json-schema': 7.0.12 dev: true + /@types/estree@0.0.50: + resolution: {integrity: sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==} + dev: true + /@types/estree@1.0.1: resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} dev: true + /@types/fs-extra@9.0.13: + resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + dependencies: + '@types/node': 20.2.5 + dev: true + /@types/http-proxy@1.17.11: resolution: {integrity: sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==} dependencies: @@ -1120,10 +1298,18 @@ packages: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true + /@types/json-stable-stringify@1.0.34: + resolution: {integrity: sha512-s2cfwagOQAS8o06TcwKfr9Wx11dNGbH2E9vJz1cqV+a/LOyhWNLUNd6JSRYNzvB4d29UuJX2M0Dj9vE1T8fRXw==} + dev: true + /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true + /@types/node@17.0.45: + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + dev: true + /@types/node@20.2.5: resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==} dev: true @@ -1330,6 +1516,97 @@ packages: - supports-color dev: true + /@vintl/compact-number@2.0.4(@formatjs/intl@2.7.2): + resolution: {integrity: sha512-Hk1kEIEMh52eGt6nD8WoT2BDY5zACJ+Gj1J49MRygkaeCNAnIEQ0O7yf/PDk9tWJWNqc5OOZcb1WgdTAoAkP6g==} + peerDependencies: + '@formatjs/intl': '>=2.7.1 <=2.7.2' + dependencies: + '@formatjs/ecma402-abstract': 1.15.0 + '@formatjs/intl': 2.7.2(typescript@5.0.4) + '@formatjs/intl-localematcher': 0.2.32 + intl-messageformat: 10.3.5 + dev: true + + /@vintl/how-ago@2.0.1(@formatjs/intl@2.7.2): + resolution: {integrity: sha512-nPmXpT9whVUL2f2FC54heHC10iA/TQk2FEmkXIdq4n6c1nZvWyod8WEx2TA9RKXfNQydQaEN3OLLce7T1Qs8gg==} + peerDependencies: + '@formatjs/intl': '>=2.7.1 <=2.7.2' + dependencies: + '@formatjs/intl': 2.7.2(typescript@5.0.4) + intl-messageformat: 10.3.5 + dev: true + + /@vintl/nuxt@1.2.2(typescript@5.0.4)(vite@4.3.9)(vue@3.3.4): + resolution: {integrity: sha512-/barKaJWoB/2Y7On1wImAGwoFZsVoAC23lKQsvs8Afa19mlgiuihawdmE5AJDE6s8gzfdJ8QrwXgA+jWXbzY3A==} + dependencies: + '@formatjs/intl': 2.7.2(typescript@5.0.4) + '@nuxt/kit': 3.5.3 + '@vintl/unplugin': 1.2.4(vite@4.3.9) + '@vintl/vintl': 4.2.1(typescript@5.0.4)(vue@3.3.4) + astring: 1.8.6 + consola: 3.1.0 + hash-sum: 2.0.0 + import-meta-resolve: 3.0.0 + pathe: 1.1.1 + picocolors: 1.0.0 + slash: 5.1.0 + zod: 3.21.4 + transitivePeerDependencies: + - '@vue/compiler-core' + - '@vue/compiler-sfc' + - rollup + - supports-color + - ts-jest + - typescript + - vite + - vue + - webpack + dev: true + + /@vintl/unplugin@1.2.4(vite@4.3.9): + resolution: {integrity: sha512-yGhUGcjqaREuGgm3ULokmovPuaij0hJf8lQoyFhbl1mLHW+GaP3y23WBzr87+t4/T341HHM2KaOTjf7my8JqAg==} + engines: {node: '>=16'} + peerDependencies: + rollup: ^3 + vite: ^4 + webpack: ^5 + peerDependenciesMeta: + rollup: + optional: true + vite: + optional: true + webpack: + optional: true + dependencies: + '@formatjs/cli-lib': 6.1.1 + '@formatjs/icu-messageformat-parser': 2.4.0 + '@rollup/pluginutils': 5.0.2(rollup@3.24.0) + glob: 10.2.7 + import-meta-resolve: 3.0.0 + pathe: 1.1.1 + unplugin: 1.3.1 + vite: 4.3.9(@types/node@20.2.5)(sass@1.63.2) + transitivePeerDependencies: + - '@vue/compiler-core' + - '@vue/compiler-sfc' + - ts-jest + dev: true + + /@vintl/vintl@4.2.1(typescript@5.0.4)(vue@3.3.4): + resolution: {integrity: sha512-ofHXpTafQrSLmW6J9O5iTo7p0juheWLc4vzTtm94q8TR1un894D88p0DFY7mwL1bcooauwBsQdMvCHUI2eTQIQ==} + peerDependencies: + vue: ^3.2.47 + dependencies: + '@braw/async-computed': 5.0.2(vue@3.3.4) + '@formatjs/icu-messageformat-parser': 2.4.0 + '@formatjs/intl': 2.7.2(typescript@5.0.4) + '@formatjs/intl-localematcher': 0.2.32 + intl-messageformat: 10.3.5 + vue: 3.3.4 + transitivePeerDependencies: + - typescript + dev: true + /@vitejs/plugin-vue-jsx@3.0.1(vite@4.3.9)(vue@3.3.4): resolution: {integrity: sha512-+Jb7ggL48FSPS1uhPnJbJwWa9Sr90vQ+d0InW+AhBM22n+cfuYqJZDckBc+W3QSHe1WDvewMZfa4wZOtk5pRgw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -1572,6 +1849,11 @@ packages: engines: {node: '>=8'} dev: true + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -1586,6 +1868,11 @@ packages: color-convert: 2.0.1 dev: true + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -1649,6 +1936,11 @@ packages: is-array-buffer: 3.0.2 dev: true + /array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} + dev: true + /array-includes@3.1.6: resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} @@ -1693,6 +1985,11 @@ packages: '@babel/types': 7.22.5 dev: true + /astring@1.8.6: + resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} + hasBin: true + dev: true + /async-sema@3.1.1: resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} dev: true @@ -2233,6 +2530,13 @@ packages: resolution: {integrity: sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==} dev: true + /currently-unhandled@0.4.1: + resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} + engines: {node: '>=0.10.0'} + dependencies: + array-find-index: 1.0.2 + dev: true + /data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} @@ -2431,6 +2735,10 @@ packages: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} dev: true + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: true @@ -2443,6 +2751,10 @@ packages: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -3180,6 +3492,14 @@ packages: is-callable: 1.2.7 dev: true + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.0.2 + dev: true + /formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -3359,6 +3679,18 @@ packages: is-glob: 4.0.3 dev: true + /glob@10.2.7: + resolution: {integrity: sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.2.1 + minimatch: 9.0.1 + minipass: 5.0.0 + path-scurry: 1.9.2 + dev: true + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: @@ -3614,6 +3946,10 @@ packages: resolve-from: 4.0.0 dev: true + /import-meta-resolve@3.0.0: + resolution: {integrity: sha512-4IwhLhNNA8yy445rPjD/lWh++7hMDOml2eHtd58eG7h+qK3EryMuuRbsHGPikCoAgIkkDnckKfWSk2iDla/ejg==} + dev: true + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -3668,6 +4004,15 @@ packages: side-channel: 1.0.4 dev: true + /intl-messageformat@10.3.5: + resolution: {integrity: sha512-6kPkftF8Jg3XJCkGKa5OD+nYQ+qcSxF4ZkuDdXZ6KGG0VXn+iblJqRFyDdm9VvKcMyC0Km2+JlVQffFM52D0YA==} + dependencies: + '@formatjs/ecma402-abstract': 1.15.0 + '@formatjs/fast-memoize': 2.0.1 + '@formatjs/icu-messageformat-parser': 2.4.0 + tslib: 2.5.3 + dev: true + /ioredis@5.3.2: resolution: {integrity: sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==} engines: {node: '>=12.22.0'} @@ -3920,6 +4265,15 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /jackspeak@2.2.1: + resolution: {integrity: sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + /jiti@1.18.2: resolution: {integrity: sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==} hasBin: true @@ -3953,6 +4307,12 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true + /json-stable-stringify@1.0.2: + resolution: {integrity: sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==} + dependencies: + jsonify: 0.0.1 + dev: true + /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -3978,6 +4338,10 @@ packages: graceful-fs: 4.2.11 dev: true + /jsonify@0.0.1: + resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} + dev: true + /jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} dependencies: @@ -4125,6 +4489,14 @@ packages: is-unicode-supported: 0.1.0 dev: true + /loud-rejection@2.2.0: + resolution: {integrity: sha512-S0FayMXku80toa5sZ6Ro4C+s+EtFDCsyJNG/AzFMfX3AxD5Si4dZsgzm/kKnbOxHl5Cv8jBlno8+3XYIh2pNjQ==} + engines: {node: '>=8'} + dependencies: + currently-unhandled: 0.4.1 + signal-exit: 3.0.7 + dev: true + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -4886,6 +5258,14 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true + /path-scurry@1.9.2: + resolution: {integrity: sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 9.1.2 + minipass: 5.0.0 + dev: true + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -5672,6 +6052,11 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /signal-exit@4.0.2: + resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} + engines: {node: '>=14'} + dev: true + /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: true @@ -5686,6 +6071,11 @@ packages: engines: {node: '>=12'} dev: true + /slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + dev: true + /smob@1.4.0: resolution: {integrity: sha512-MqR3fVulhjWuRNSMydnTlweu38UhQ0HXM4buStD/S3mc/BzX3CuM9OmhyQpmtYCvoYdl5ris6TI0ZqH355Ymqg==} dev: true @@ -5760,6 +6150,15 @@ packages: strip-ansi: 6.0.1 dev: true + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + /string.prototype.trim@1.2.7: resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} engines: {node: '>= 0.4'} @@ -5803,6 +6202,13 @@ packages: ansi-regex: 5.0.1 dev: true + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -6607,6 +7013,15 @@ packages: strip-ansi: 6.0.1 dev: true + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true @@ -6684,3 +7099,7 @@ packages: compress-commons: 4.1.1 readable-stream: 3.6.2 dev: true + + /zod@3.21.4: + resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} + dev: true diff --git a/types/vintl.d.ts b/types/vintl.d.ts new file mode 100644 index 00000000000..86298889be2 --- /dev/null +++ b/types/vintl.d.ts @@ -0,0 +1,10 @@ +import '@vintl/vintl' +import { CompactNumber } from '@vintl/compact-number/dist/index.mjs' + +declare global { + namespace VueIntlController { + interface MessageValueTypes { + compactNumber: CompactNumber + } + } +}