1
0

Add internationalization support (#738)

This commit is contained in:
Sasha Sorokin
2023-06-11 19:08:16 +01:00
committed by GitHub
parent 776c16cd49
commit de991041c4
12 changed files with 651 additions and 10 deletions

View File

@@ -0,0 +1,18 @@
import { createFormatter, type Formatter } from '@vintl/compact-number'
import { IntlController } from '@vintl/vintl/controller'
const formatters = new WeakMap<IntlController<any>, 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
}

18
composables/how-ago.ts Normal file
View File

@@ -0,0 +1,18 @@
import { createFormatter, type Formatter } from '@vintl/how-ago'
import { IntlController } from '@vintl/vintl/controller'
const formatters = new WeakMap<IntlController<any>, 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
}

7
crowdin.yml Normal file
View File

@@ -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%

17
locales/en-US/index.json Normal file
View File

@@ -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"
}
}

View File

@@ -0,0 +1,3 @@
{
"en-US": "American English"
}

6
locales/en-US/meta.json Normal file
View File

@@ -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"
}
}

View File

@@ -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<string, string>()
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<string, { message: string }>} */
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() {

View File

@@ -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",

View File

@@ -150,10 +150,10 @@
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
:alt="expandedGalleryItem.title ? expandedGalleryItem.title : 'gallery-image'"
@click.stop=""
@click.stop
/>
<div class="floating" @click.stop="">
<div class="floating" @click.stop>
<div class="text">
<h2 v-if="expandedGalleryItem.title">
{{ expandedGalleryItem.title }}

View File

@@ -1,11 +1,59 @@
<script setup lang="ts">
const vintl = useVIntl()
const { formatMessage } = vintl
const messages = defineMessages({
frogTitle: {
id: 'frog.title',
defaultMessage: 'Frog',
},
frogDescription: {
id: 'frog',
defaultMessage: "You've been frogged! 🐸",
},
frogAltText: {
id: 'frog.altText',
defaultMessage: 'A photorealistic painting of a frog labyrinth',
},
frogSinceOpened: {
id: 'frog.sinceOpened',
defaultMessage: 'This page was opened {ago}',
},
frogFroggedPeople: {
id: 'frog.froggedPeople',
defaultMessage:
'{count, plural, one {{count} more person} other {{count} more people}} were also frogged!',
},
})
const formatCompactNumber = useCompactNumber()
const formatRelativeTime = useRelativeTime()
const pageOpen = useState('frogPageOpen', () => Date.now())
const peopleFrogged = useState('frogPeopleFrogged', () => Math.round(Math.random() * 100_000_000))
const peopleFroggedCount = computed(() => formatCompactNumber(peopleFrogged.value))
let interval: ReturnType<typeof setTimeout>
const formattedOpenedCounter = ref(formatRelativeTime(Date.now()))
onMounted(() => {
interval = setInterval(() => {
formattedOpenedCounter.value = formatRelativeTime(pageOpen.value)
}, 1000)
})
onUnmounted(() => clearInterval(interval))
</script>
<template>
<div class="card">
<h1>Frog</h1>
<p>You've been frogged! 🐸</p>
<img
src="https://cdn.modrinth.com/frog.png"
alt="a photorealistic painting of a frog labyrinth"
/>
<h1>{{ formatMessage(messages.frogTitle) }}</h1>
<p>{{ formatMessage(messages.frogDescription) }}</p>
<img src="https://cdn.modrinth.com/frog.png" :alt="formatMessage(messages.frogAltText)" />
<p>{{ formatMessage(messages.frogSinceOpened, { ago: formattedOpenedCounter }) }}</p>
<p>{{ formatMessage(messages.frogFroggedPeople, { count: peopleFroggedCount }) }}</p>
</div>
</template>

419
pnpm-lock.yaml generated
View File

@@ -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

10
types/vintl.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
import '@vintl/vintl'
import { CompactNumber } from '@vintl/compact-number/dist/index.mjs'
declare global {
namespace VueIntlController {
interface MessageValueTypes {
compactNumber: CompactNumber
}
}
}