mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70c4dfab73 | ||
|
|
e1c501caad | ||
|
|
b883a37aeb | ||
|
|
951f36381f | ||
|
|
ae71089e74 | ||
|
|
e45e0fdde9 | ||
|
|
db449d439a | ||
|
|
333d55741c | ||
|
|
2590b2f942 | ||
|
|
f59c0af86e | ||
|
|
47f1739873 | ||
|
|
f62ae92791 | ||
|
|
d5b7e30494 | ||
|
|
1d21fc02fe | ||
|
|
9756d4acb9 | ||
|
|
3d41dd1757 | ||
|
|
355a7d0726 | ||
|
|
1a470e9ee2 | ||
|
|
d36cd55167 | ||
|
|
b872f41ea1 | ||
|
|
256598c87f | ||
|
|
19908fb197 | ||
|
|
bfbcfd7c06 | ||
|
|
d46362362d | ||
|
|
8f4ca76780 | ||
|
|
016c6938b8 | ||
|
|
25b5acfdd4 |
@@ -0,0 +1,79 @@
|
||||
name: Test pull request
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, next, alpha, beta, rc]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Check changed files
|
||||
uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
shared: &shared
|
||||
- .npmrc
|
||||
- package.json
|
||||
- pnpm-lock.yaml
|
||||
nvintl:
|
||||
- *shared
|
||||
- 'packages/vintl-nuxt/**'
|
||||
playground:
|
||||
- *shared
|
||||
- 'apps/playground/**'
|
||||
- 'packages/translations/**'
|
||||
docs:
|
||||
- *shared
|
||||
- 'apps/docs/**'
|
||||
|
||||
- name: Install pnpm via corepack
|
||||
shell: bash
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Prepare everything
|
||||
run: pnpm all:prepare
|
||||
|
||||
- name: Lint everything
|
||||
run: pnpm all:lint
|
||||
|
||||
- name: Build module
|
||||
if: steps.filter.outputs.nvintl == 'true'
|
||||
run: pnpm mod:build
|
||||
|
||||
- name: Build playground
|
||||
if: steps.filter.outputs.playground == 'true' || steps.filter.outputs.nvintl == 'true'
|
||||
run: pnpm pg:build
|
||||
|
||||
- name: Build docs
|
||||
if: steps.filter.outputs.docs == 'true' || steps.filter.outputs.nvintl == 'true'
|
||||
run: pnpm docs:build
|
||||
@@ -12,15 +12,16 @@ Represents the VIntl module options.
|
||||
|
||||
**Properties**
|
||||
|
||||
| Property | Default | Description |
|
||||
| :---------------------- | :------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `defaultLocale` | | A string that represents the BCP 47 code of the locale to use by default. |
|
||||
| `resolveDir` | `'.'` | An optional string that represents a directory where all the imports associated with the locales are being resolved. If it's relative, then it will be resolved against the Nuxt `srcDir` directory. If this property is not set, modules will be resolved from the Nuxt `srcDir`. |
|
||||
| `locales` | | An array of [`LocaleDescriptor`] objects that represent all the configured locales. |
|
||||
| `storage` | | An optional string that represents either a built-in storage name (`localStorage` / `cookie`), or a node import specifier that exports a custom storage adapter as the default export. |
|
||||
| `broadcastLocaleChange` | `true` | An optional boolean value that determines whether to use [`BroadcastChannel`] (if available) to synchronize the locale changes between the tabs on the same origin. |
|
||||
| `hostLanguageParam` | `'hl'` | An optional name of the query parameter used to override the user language (including automatically detected one). It is used to generate SEO meta tags. Using `null` will disable them. |
|
||||
| `parserless` | `{ enabled: false }` | An optional [`ParserlessOptions`] object or [`ParserlessMode`] which configures the parserless mode. |
|
||||
| Property | Default | Description |
|
||||
| :---------------------- | :-----: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `defaultLocale` | | A string that represents the BCP 47 code of the locale to use by default. |
|
||||
| `resolveDir` | `'.'` | An optional string that represents a directory where all the imports associated with the locales are being resolved. If it's relative, then it will be resolved against the Nuxt `srcDir` directory. If this property is not set, modules will be resolved from the Nuxt `srcDir`. |
|
||||
| `locales` | | An array of [`LocaleDescriptor`] objects that represent all the configured locales. |
|
||||
| `storage` | | An optional string that represents either a built-in storage name (`localStorage` / `cookie`), or a node import specifier that exports a custom storage adapter as the default export. |
|
||||
| `broadcastLocaleChange` | `true` | An optional boolean value that determines whether to use [`BroadcastChannel`] (if available) to synchronize the locale changes between the tabs on the same origin. |
|
||||
| `hostLanguageParam` | `'hl'` | **Deprecated.** An optional name of the query parameter used to override the user language (including automatically detected one). It is used to generate SEO meta tags. Using `null` will disable them. |
|
||||
| `parserless` | `<...>` | An optional [`ParserlessOptions`] object or [`ParserlessMode`] which configures the parserless mode. |
|
||||
| `seo` | `<...>` | An optional [`SEOOptions`] object which configures automatic head tags to improve discoverability of other languages by search engines. |
|
||||
|
||||
[`BroadcastChannel`]: https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel
|
||||
[`ParserlessOptions`]: #parserlessoptions
|
||||
@@ -131,9 +132,9 @@ Represents an import source for the messages file. It is similar to the [`Import
|
||||
|
||||
Represents options for the parserless mode.
|
||||
|
||||
| Property | Description |
|
||||
| :-------- | :----------------------------------------------------------------------- |
|
||||
| `enabled` | A `ParserlessMode` value representing the status of the parserless mode. |
|
||||
| Property | Default | Description |
|
||||
| :-------- | :-----: | :----------------------------------------------------------------------- |
|
||||
| `enabled` | `false` | A `ParserlessMode` value representing the status of the parserless mode. |
|
||||
|
||||
## `ParserlessMode`
|
||||
|
||||
@@ -144,3 +145,17 @@ A string or boolean value representing the status of the parserless mode.
|
||||
| `always` | `true` | Parserless mode is always enabled, regardless of the mode in which Nuxt is running. |
|
||||
| `only-prod` | | Parserless mode is only enabled when building Nuxt app for production. |
|
||||
| `never` | `false` | Parserless mode is never enabled, the parser is always present in the runtime. |
|
||||
|
||||
## `SEOOptions`
|
||||
|
||||
[`SEOOptions`]: #seooptions
|
||||
|
||||
Represents options for the automatic head tags.
|
||||
|
||||
By default VIntl will add `<link>` tags for every language to make search engines aware of other languages, you can disable this by setting `enabled` to `false`.
|
||||
|
||||
| Property | Default | Description |
|
||||
| :----------------------- | :-----: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `enabled` | `true` | A boolean value representing whether VIntl should automatically add `<link>` tags to `<head>` of the site. These tags make search engines aware that your site is provided in different languages. |
|
||||
| `hostLanguageParameter`: | `hl` | A string value representing the query parameter that VIntl would use to configure the language of the site. |
|
||||
| `baseURL` | | **Recommended.** An optional string value representing the base URL of the site. If not set, VIntl will try to guess the URL based on inital request URL or the current `window.location`. |
|
||||
|
||||
@@ -13,13 +13,15 @@
|
||||
"start": "node .output/server/index.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^6.0.4",
|
||||
"@nuxt-themes/docus": "^1.10.1",
|
||||
"@formatjs/cli": "^6.1.2",
|
||||
"@nuxt-themes/docus": "^1.12.3",
|
||||
"@nuxt/eslint-config": "^0.1.1",
|
||||
"@vintl-dev/eslint-config-peony": "workspace:^",
|
||||
"@vintl/nuxt": "workspace:^",
|
||||
"eslint": "^8.39.0",
|
||||
"nuxt": "^3.4.2",
|
||||
"theme-colors": "^0.0.5"
|
||||
"eslint": "^8.42.0",
|
||||
"nuxi": "^3.5.3",
|
||||
"nuxt": "^3.5.3",
|
||||
"theme-colors": "^0.0.5",
|
||||
"vue": "^3.3.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
"index.other-page": {
|
||||
"message": "To the other page"
|
||||
},
|
||||
"index.use-automatic": {
|
||||
"message": "Use automatic"
|
||||
},
|
||||
"language": {
|
||||
"message": "Language"
|
||||
},
|
||||
@@ -17,6 +20,9 @@
|
||||
"other-page.back": {
|
||||
"message": "Go back"
|
||||
},
|
||||
"other-page.description": {
|
||||
"message": "You must've clicked me a thousand times"
|
||||
},
|
||||
"other-page.title": {
|
||||
"message": "Hello from the other page!"
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
"generate": "nuxi generate",
|
||||
"preview": "nuxi preview",
|
||||
"lint": "eslint --cache .",
|
||||
"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.json --format simple",
|
||||
"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.json --format crowdin",
|
||||
"start": "node .output/server/index.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vintl-dev/eslint-config-peony": "workspace:^",
|
||||
"@vintl-dev/pg-messages": "workspace:^",
|
||||
"@vintl/nuxt": "workspace:^",
|
||||
"eslint": "^8.39.0",
|
||||
"nuxi": "^3.4.2",
|
||||
"nuxt": "^3.4.2"
|
||||
"eslint": "^8.42.0",
|
||||
"nuxi": "^3.5.3",
|
||||
"nuxt": "^3.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,47 +23,80 @@ const messages = defineMessages({
|
||||
id: 'index.other-page',
|
||||
defaultMessage: 'To the other page',
|
||||
},
|
||||
useAutomatic: {
|
||||
id: 'index.use-automatic',
|
||||
defaultMessage: 'Use automatic',
|
||||
},
|
||||
} as const)
|
||||
|
||||
const vintl = useVIntl()
|
||||
const { formatMessage } = vintl
|
||||
|
||||
const changing = ref(false)
|
||||
|
||||
async function changeLocale(locale: string) {
|
||||
if (changing.value) return
|
||||
changing.value = true
|
||||
try {
|
||||
await vintl.changeLocale(locale)
|
||||
} catch (err) {
|
||||
console.error('Error changing locale', err)
|
||||
} finally {
|
||||
changing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
const currentLocale = computed({
|
||||
get() {
|
||||
return vintl.locale
|
||||
},
|
||||
set() {
|
||||
// ignore
|
||||
set(value) {
|
||||
changeLocale(value).then(noop, noop)
|
||||
},
|
||||
})
|
||||
|
||||
async function onLocaleChange(e: Event) {
|
||||
await vintl.changeLocale(
|
||||
(e as Event & { target: HTMLSelectElement }).target.value,
|
||||
)
|
||||
}
|
||||
const useAutomatic = computed({
|
||||
get() {
|
||||
return vintl.automatic
|
||||
},
|
||||
set(value) {
|
||||
changeLocale(value ? 'auto' : vintl.locale).then(noop, noop)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<h3>{{ formatMessage(messages.options) }}</h3>
|
||||
<label for="language-select">
|
||||
{{ formatMessage(messages.language) }}
|
||||
</label>
|
||||
<select
|
||||
id="language-select"
|
||||
v-model="currentLocale"
|
||||
@change="onLocaleChange"
|
||||
>
|
||||
<option
|
||||
v-for="locale in [...$nuxt.$i18n.$locales.value.keys()]"
|
||||
:key="locale.tag"
|
||||
:value="locale.tag"
|
||||
>
|
||||
{{ locale.tag }}
|
||||
</option>
|
||||
</select>
|
||||
<div>
|
||||
<label>
|
||||
<input v-model="useAutomatic" type="checkbox" />
|
||||
{{ formatMessage(messages.useAutomatic) }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{ formatMessage(messages.language) }}
|
||||
<select
|
||||
id="language-select"
|
||||
v-model="currentLocale"
|
||||
:disabled="vintl.automatic"
|
||||
@change="onLocaleChange"
|
||||
>
|
||||
<option
|
||||
v-for="locale in [...$nuxt.$i18n.$locales.value.keys()]"
|
||||
:key="locale.tag"
|
||||
:value="locale.tag"
|
||||
>
|
||||
{{ locale.tag }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
+2
-5
@@ -8,7 +8,7 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.26.1",
|
||||
"turbo": "^1.8.7"
|
||||
"turbo": "^1.10.1"
|
||||
},
|
||||
"scripts": {
|
||||
"pg:prepare": "turbo run --no-daemon @vintl-dev/pg#dev:prepare",
|
||||
@@ -28,9 +28,6 @@
|
||||
"_ci:publish": "changeset publish"
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"astring@1.8.4": "patches/astring@1.8.4.patch"
|
||||
},
|
||||
"packageExtensions": {
|
||||
"@nuxt/kit": {
|
||||
"dependencies": {
|
||||
@@ -39,5 +36,5 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@8.3.1"
|
||||
"packageManager": "pnpm@8.6.1"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"no-useless-constructor": "off",
|
||||
"@typescript-eslint/no-useless-constructor": "warn",
|
||||
"brace-style": "off",
|
||||
"vue/singleline-html-element-content-newline": "off"
|
||||
"vue/singleline-html-element-content-newline": "off",
|
||||
"vue/max-attributes-per-line": "off",
|
||||
"vue/html-self-closing": "off"
|
||||
},
|
||||
"parserOptions": {
|
||||
"extraFileExtensions": [".vue"]
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
"config.json"
|
||||
],
|
||||
"dependencies": {
|
||||
"@rushstack/eslint-patch": "^1.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"eslint-plugin-vue": "^9.11.0",
|
||||
"typescript": "^5.0.4"
|
||||
"@rushstack/eslint-patch": "^1.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.9",
|
||||
"@typescript-eslint/parser": "^5.59.9",
|
||||
"eslint-plugin-vue": "^9.14.1",
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/eslint": "^8.37.0",
|
||||
"eslint": "^8.38.0"
|
||||
"@types/eslint": "^8.40.0",
|
||||
"eslint": "^8.42.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,85 @@
|
||||
# @vintl/nuxt
|
||||
|
||||
## 1.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- e1c501c: Improve alternate links generation
|
||||
|
||||
Generation of `alternate` `hreflang` links has been improved to properly use absolute URLs.
|
||||
|
||||
Since there's no good way to know the URL of the site, there's now also `seo.baseURL` option which allows to set site's proper domain.
|
||||
|
||||
`hostLanguageParam` option has been deperecated in favour of `seo.hostLanguageParameter`, which functions almost the same way, except it does not accept `null`. If you want to disable generation of such tags or handle them yourself, you can set `seo.enabled` to `false`.
|
||||
|
||||
See [Configuration](https://vintl-nuxt.netlify.app/introduction/configuration#seooptions) documentation page for more details.
|
||||
|
||||
## 1.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 951f363: Add graceful fallback for unknown locales in storage
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ae71089: Use automatic locale if none returned by the storage
|
||||
|
||||
Fixed a bug where automatic locale would not be restored from the storage properly on the next page reload, despite it being saved properly.
|
||||
|
||||
## 1.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- db449d4: Fix missing options in the newer Nuxt versions
|
||||
|
||||
## 1.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2590b2f: Downgrade and pin versions of FormatJS packages
|
||||
|
||||
Newest versions of FormatJS packages contain exports map that result in illegal ESM as CJS imports. This downgrades them
|
||||
|
||||
For more details see the issue at https://github.com/formatjs/formatjs/issues/4126.
|
||||
|
||||
## 1.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- f62ae92: Adapt to new export conditions of the parser
|
||||
|
||||
`@formatjs/icu-messageformat-parser` has been updated and now has export conditions, this change adapts and fixes the error caused by the previous direct import of the file for `no-parser` alias.
|
||||
|
||||
- 47f1739: Fix consola not being actually listed as a dependency or used
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 3d41dd1: Update VIntl to 4.2.0
|
||||
|
||||
Previously VIntl was depending on Vue directly, which caused issues, and wasn't correct, as Vue is not its implementation detail. 4.2.0 made Vue a peer dependency, fixing this issue. It also brought updates to other dependencies like `@formatjs/intl`.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9756d4a: Upgrade `import-meta-resolve` to v3
|
||||
|
||||
## 1.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8f4ca76: Fix compatibility with newer versions of Nuxt
|
||||
|
||||
It seems that TypeScript has a trouble identifying similar types from different packages, which caused it to disregard any types from VIntl.
|
||||
|
||||
Now that the `@nuxt/schema` is moved to `devDependencies` (since it's used for types only anyway), and doesn't have to strictly match the version, this should be fixed.
|
||||
|
||||
## 1.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 25b5acf: Don't require additionalImports to be a non-empty array
|
||||
|
||||
## 1.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vintl/nuxt",
|
||||
"version": "1.1.2",
|
||||
"version": "1.4.0",
|
||||
"description": "Nuxt Module for VIntl integration",
|
||||
"keywords": [
|
||||
"i18n",
|
||||
@@ -39,27 +39,31 @@
|
||||
"prepack": "pnpm run -s lint && pnpm run -s build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/module-builder": "^0.3.0",
|
||||
"@nuxt/module-builder": "^0.4.0",
|
||||
"@nuxt/schema": "^3.5.3",
|
||||
"@types/hash-sum": "^1.0.0",
|
||||
"@types/node": "^18.15.12",
|
||||
"@unhead/vue": "^1.1.26",
|
||||
"@types/node": "^18.16.16",
|
||||
"@unhead/vue": "^1.1.27",
|
||||
"@vintl-dev/eslint-config-peony": "workspace:^",
|
||||
"hookable": "^5.5.3",
|
||||
"prettier-plugin-jsdoc": "^0.4.2",
|
||||
"typescript": "^5.0.4"
|
||||
"typescript": "^5.1.3",
|
||||
"vue-router": "^4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formatjs/intl": "^2.7.1",
|
||||
"@nuxt/kit": "^3.4.2",
|
||||
"@nuxt/schema": "^3.4.2",
|
||||
"@vintl/unplugin": "^1.2.1",
|
||||
"@vintl/vintl": "^4.1.2",
|
||||
"astring": "^1.8.4",
|
||||
"@formatjs/intl": "2.7.2",
|
||||
"@formatjs/intl-localematcher": "^0.4.0",
|
||||
"@nuxt/kit": "^3.5.3",
|
||||
"@vintl/unplugin": "^1.2.4",
|
||||
"@vintl/vintl": "^4.2.1",
|
||||
"astring": "^1.8.6",
|
||||
"consola": "^3.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
"import-meta-resolve": "^2.2.2",
|
||||
"pathe": "^1.1.0",
|
||||
"import-meta-resolve": "^3.0.0",
|
||||
"pathe": "^1.1.1",
|
||||
"picocolors": "^1.0.0",
|
||||
"slash": "^5.0.0",
|
||||
"slash": "^5.1.0",
|
||||
"ufo": "^1.1.2",
|
||||
"zod": "^3.21.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,16 +21,16 @@ import { moduleOptionsSchema } from './schemas/index.js'
|
||||
import { PluginOptionsBank } from './parser-bank.js'
|
||||
import { formatZodError } from './utils/zod-error.js'
|
||||
import { OptionsError } from './errors.js'
|
||||
import * as consola from 'console'
|
||||
import { consola } from 'consola'
|
||||
|
||||
/** Path to the options file relative to `buildDir`. */
|
||||
const optionsFilePath = 'i18n/options.mjs'
|
||||
|
||||
type _InputModuleOptions = typeof moduleOptionsSchema
|
||||
|
||||
export interface InputModuleOptions extends t.input<_InputModuleOptions> {}
|
||||
export interface ModuleOptions extends t.input<_InputModuleOptions> {}
|
||||
|
||||
export default defineNuxtModule<InputModuleOptions>({
|
||||
export default defineNuxtModule<ModuleOptions>({
|
||||
meta: {
|
||||
name: '@vintl/nuxt',
|
||||
configKey: 'vintl',
|
||||
@@ -48,7 +48,7 @@ export default defineNuxtModule<InputModuleOptions>({
|
||||
|
||||
const resolveInRuntime = createDirResolver(runtimeDir)
|
||||
|
||||
addPlugin((await resolveInRuntime('./plugin.js')).path)
|
||||
addPlugin(resolveInRuntime('./plugin.js').path)
|
||||
|
||||
if (!nuxt.options._prepare) {
|
||||
let options: t.output<typeof moduleOptionsSchema>
|
||||
@@ -86,16 +86,14 @@ export default defineNuxtModule<InputModuleOptions>({
|
||||
const optionsFile = addTemplate({
|
||||
filename: optionsFilePath,
|
||||
write: true,
|
||||
async getContents() {
|
||||
getContents() {
|
||||
const resolveInResDir = createDirResolver(
|
||||
resolvePath(nuxt.options.srcDir, options.resolveDir ?? '.'),
|
||||
)
|
||||
|
||||
return await generateOptions(options, {
|
||||
async resolve(specifier) {
|
||||
return (await resolveInResDir(specifier)).relativeTo(
|
||||
optionsFile.dst,
|
||||
)
|
||||
return generateOptions(options, {
|
||||
resolve(specifier) {
|
||||
return resolveInResDir(specifier).relativeTo(optionsFile.dst)
|
||||
},
|
||||
registerMessagesFile(file, importPath) {
|
||||
pluginOptionsBank.registerFile(
|
||||
@@ -103,10 +101,8 @@ export default defineNuxtModule<InputModuleOptions>({
|
||||
resolvePath(dirname(optionsFile.dst), importPath),
|
||||
)
|
||||
},
|
||||
async resolveRuntimeModule(specifier) {
|
||||
return (await resolveInRuntime(specifier)).relativeTo(
|
||||
optionsFile.dst,
|
||||
)
|
||||
resolveRuntimeModule(specifier) {
|
||||
return resolveInRuntime(specifier).relativeTo(optionsFile.dst)
|
||||
},
|
||||
state: {
|
||||
parserlessModeEnabled,
|
||||
|
||||
@@ -616,7 +616,7 @@ interface GeneratorContext {
|
||||
* @param specifier Module import specifier.
|
||||
* @returns Path relative to the options file.
|
||||
*/
|
||||
resolve(specifier: string): Promise<string>
|
||||
resolve(specifier: string): string
|
||||
|
||||
/**
|
||||
* Analytical method that is called for every generated messages import.
|
||||
@@ -635,7 +635,7 @@ interface GeneratorContext {
|
||||
* @param specifier Module import specifier.
|
||||
* @returns Path relative to the optons file.
|
||||
*/
|
||||
resolveRuntimeModule(specifier: string): Promise<string>
|
||||
resolveRuntimeModule(specifier: string): string
|
||||
|
||||
/** Additional state to encode which is not included in the options. */
|
||||
state: {
|
||||
@@ -649,7 +649,7 @@ interface GeneratorContext {
|
||||
* then renders it to actual JavaScript code. The resulting code can be written
|
||||
* to a special file and read at runtime to retrieve the options.
|
||||
*/
|
||||
export async function generate(
|
||||
export function generate(
|
||||
opts: t.output<typeof moduleOptionsSchema>,
|
||||
{
|
||||
resolve,
|
||||
@@ -697,7 +697,7 @@ export async function generate(
|
||||
|
||||
imports.push(
|
||||
new ImportDeclaration(
|
||||
new Literal(await resolveRuntimeModule('./utils/locale-loader.js')),
|
||||
new Literal(resolveRuntimeModule('./utils/locale-loader.js')),
|
||||
)
|
||||
.addSpecifier(id$defineLocale)
|
||||
.addSpecifier(id$rawValue),
|
||||
@@ -780,7 +780,7 @@ export async function generate(
|
||||
|
||||
for (const messageFile of files) {
|
||||
const { from: importPath, name: importKey } = messageFile
|
||||
const resolvedPath = await resolve(messageFile.from)
|
||||
const resolvedPath = resolve(messageFile.from)
|
||||
registerMessagesFile(messageFile, resolvedPath)
|
||||
|
||||
if (isDefaultLocale) {
|
||||
@@ -830,7 +830,7 @@ export async function generate(
|
||||
|
||||
for (const import_ of locale.additionalImports ?? []) {
|
||||
const resolvedPath = import_.resolve
|
||||
? await resolve(import_.from)
|
||||
? resolve(import_.from)
|
||||
: import_.from
|
||||
|
||||
if (isDefaultLocale) {
|
||||
@@ -857,9 +857,7 @@ export async function generate(
|
||||
resolve: shouldResolve,
|
||||
} = dataImport
|
||||
|
||||
const resolvedPath = shouldResolve
|
||||
? await resolve(importPath)
|
||||
: importPath
|
||||
const resolvedPath = shouldResolve ? resolve(importPath) : importPath
|
||||
|
||||
if (isDefaultLocale) {
|
||||
// if import key is 'default' then:
|
||||
@@ -984,11 +982,11 @@ export async function generate(
|
||||
let storage = opts.storage
|
||||
|
||||
if (storage === 'localStorage') {
|
||||
storage = await resolveRuntimeModule('./storage/local-storage.js')
|
||||
storage = resolveRuntimeModule('./storage/local-storage.js')
|
||||
} else if (storage === 'cookie') {
|
||||
storage = await resolveRuntimeModule('./storage/cookie.js')
|
||||
storage = resolveRuntimeModule('./storage/cookie.js')
|
||||
} else {
|
||||
storage = await resolve(storage)
|
||||
storage = resolve(storage)
|
||||
}
|
||||
|
||||
exports.push(
|
||||
@@ -1022,8 +1020,8 @@ export async function generate(
|
||||
new ExportNamedDeclaration().setDeclaration(
|
||||
new VariableDeclaration('const', [
|
||||
new VariableDeclarator(
|
||||
new Identifier('hostLanguageParam'),
|
||||
new Literal(opts.hostLanguageParam),
|
||||
new Identifier('seo'),
|
||||
new Literal(null).setRaw(JSON.stringify(opts.seo)),
|
||||
),
|
||||
]),
|
||||
),
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useHead } from '#imports'
|
||||
import type { IntlController } from '@vintl/vintl/controller'
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'nuxt/app'
|
||||
import type { LocationQuery, useRouter as _useRouter$type } from 'vue-router'
|
||||
import { useRouter as _useRouter, useRequestURL } from 'nuxt/app'
|
||||
import { joinURL } from 'ufo'
|
||||
|
||||
type LocationQuery = ReturnType<
|
||||
typeof useRouter
|
||||
>['currentRoute']['value']['query']
|
||||
const useRouter = _useRouter as typeof _useRouter$type
|
||||
|
||||
// I wish there was a better way to do this T_T
|
||||
function getSeachParams(query: LocationQuery) {
|
||||
@@ -35,11 +35,32 @@ type LangHrefLink = {
|
||||
href: string
|
||||
}
|
||||
|
||||
export function initHead(controller: IntlController<any>, hlParam: string) {
|
||||
interface HeadOptions {
|
||||
hostLanguageParameter: string
|
||||
baseURL?: string
|
||||
}
|
||||
|
||||
export function initHead(
|
||||
controller: IntlController<any>,
|
||||
options: HeadOptions,
|
||||
) {
|
||||
const router = useRouter()
|
||||
|
||||
const currentRoute = computed(() => router.currentRoute.value)
|
||||
|
||||
const requestURL = useRequestURL()
|
||||
|
||||
const normalizeURL = (url: string) => {
|
||||
try {
|
||||
return options.baseURL == null
|
||||
? new URL(url, requestURL).toString()
|
||||
: joinURL(options.baseURL, url)
|
||||
} catch (err) {
|
||||
console.error(`[vintl] cannot normalize url: ${String(err)}`)
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
useHead({
|
||||
htmlAttrs: {
|
||||
lang: () => controller.$config.locale,
|
||||
@@ -55,12 +76,12 @@ export function initHead(controller: IntlController<any>, hlParam: string) {
|
||||
|
||||
{
|
||||
const sp = new URLSearchParams(query)
|
||||
sp.delete(hlParam)
|
||||
sp.delete(options.hostLanguageParameter)
|
||||
defaultEntry = {
|
||||
// key: `hreflang-default`,
|
||||
rel: 'alternate',
|
||||
hreflang: 'x-default',
|
||||
href: withQueryParams(path, sp.toString()),
|
||||
href: normalizeURL(withQueryParams(path, sp.toString())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,13 +92,13 @@ export function initHead(controller: IntlController<any>, hlParam: string) {
|
||||
if (hrefLangs.has(hrefLang)) continue
|
||||
|
||||
const sp = new URLSearchParams(query)
|
||||
sp.set(hlParam, locale.tag)
|
||||
sp.set(options.hostLanguageParameter, locale.tag)
|
||||
|
||||
hrefLangs.set(hrefLang, {
|
||||
// key: `hreflang-${locale.tag}`,
|
||||
rel: 'alternate',
|
||||
hreflang: hrefLang,
|
||||
href: withQueryParams(path, sp.toString()),
|
||||
href: normalizeURL(withQueryParams(path, sp.toString())),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import {
|
||||
localeDefinitions,
|
||||
storageAdapterFactory,
|
||||
broadcastLocaleChange,
|
||||
hostLanguageParam,
|
||||
parserless,
|
||||
seo as seoOptions,
|
||||
} from '@vintl/nuxt-runtime/options'
|
||||
import type { LocaleDescriptor, MessageValueType } from '@vintl/vintl'
|
||||
import type { IntlController } from '@vintl/vintl/controller'
|
||||
@@ -21,6 +21,7 @@ import { useAcceptLanguageHeader } from '@vintl/vintl/sources/header'
|
||||
import { defineNuxtPlugin } from 'nuxt/app'
|
||||
import { syncCaller } from './utils/hookable.js'
|
||||
import { initHead } from './head.js'
|
||||
import { match as matchLocales } from '@formatjs/intl-localematcher'
|
||||
|
||||
export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
const locales: LocaleDescriptor[] = Object.entries(localeDefinitions).map(
|
||||
@@ -41,8 +42,8 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (hostLanguageParam != null) {
|
||||
let hlLocale = nuxtApp._route.query[hostLanguageParam]
|
||||
if (seoOptions.enabled) {
|
||||
let hlLocale = nuxtApp._route.query[seoOptions.hostLanguageParameter]
|
||||
|
||||
if (Array.isArray(hlLocale)) {
|
||||
hlLocale = hlLocale[0]
|
||||
@@ -53,12 +54,23 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (locale != null) {
|
||||
const match = matchLocales(
|
||||
[locale],
|
||||
locales.map(({ tag }) => tag),
|
||||
'en-x-placeholder',
|
||||
)
|
||||
|
||||
locale = match == 'en-x-placeholder' ? undefined : match
|
||||
}
|
||||
|
||||
const plugin = createPlugin<MessageValueType>({
|
||||
injectInto: [nuxtApp],
|
||||
controllerOpts: {
|
||||
defaultLocale,
|
||||
locales,
|
||||
locale,
|
||||
usePreferredLocale: locale == null,
|
||||
listen: {
|
||||
error(event) {
|
||||
nuxtApp.hooks.callHookWith(syncCaller, 'i18n:error', {
|
||||
@@ -139,8 +151,8 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
setupBroadcasting(controller)
|
||||
}
|
||||
|
||||
if (hostLanguageParam != null) {
|
||||
nuxtApp.hook('vue:setup', () => initHead(controller, hostLanguageParam!))
|
||||
if (seoOptions.enabled) {
|
||||
nuxtApp.hook('vue:setup', () => initHead(controller, seoOptions))
|
||||
}
|
||||
|
||||
await nuxtApp.callHook('i18n:ready', controller)
|
||||
|
||||
@@ -68,7 +68,6 @@ export const localeDescriptorSchema = t
|
||||
.describe(
|
||||
'List of additional side-effect only imports (like polyfill data)',
|
||||
)
|
||||
.nonempty()
|
||||
.optional(),
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@ import { z as t } from 'zod'
|
||||
import { tSwitch } from '../utils/zod-utils.js'
|
||||
import { languageTagSchema } from './language-tag.js'
|
||||
import { localeDescriptorSchema } from './locales.js'
|
||||
import { seoOptions } from './seo.js'
|
||||
|
||||
const parselessModeEnumSchema = t.enum(['always', 'only-prod', 'never'])
|
||||
|
||||
@@ -167,6 +168,7 @@ export const moduleOptionsSchema = t
|
||||
* user language. `null` to disable. If this value is `null`, the SEO tags
|
||||
* generation will be disabled.
|
||||
*
|
||||
* @deprecated Use `seo` options instead.
|
||||
* @default 'hl' // For example, ?hl=en to use English locale (if defined).
|
||||
*/
|
||||
hostLanguageParam: t
|
||||
@@ -174,8 +176,10 @@ export const moduleOptionsSchema = t
|
||||
.describe(
|
||||
'Name of the host language URL parameter, used to override the default or user language.',
|
||||
)
|
||||
.nullable()
|
||||
.default('hl'),
|
||||
.optional()
|
||||
.nullable(),
|
||||
|
||||
seo: seoOptions.optional(),
|
||||
|
||||
/**
|
||||
* Configuration options for the parserless mode, a mode in which the parser
|
||||
@@ -197,6 +201,21 @@ export const moduleOptionsSchema = t
|
||||
}
|
||||
}).default('only-prod'),
|
||||
})
|
||||
.transform((from) => {
|
||||
if (from.seo === undefined) {
|
||||
let hostLanguageParam = from.hostLanguageParam
|
||||
if (hostLanguageParam === undefined) {
|
||||
hostLanguageParam = 'hl'
|
||||
}
|
||||
|
||||
from.seo = seoOptions.parse({
|
||||
enabled: hostLanguageParam != null,
|
||||
hostLanguageParameter: hostLanguageParam ?? undefined,
|
||||
})
|
||||
}
|
||||
|
||||
return from as typeof from & { seo: t.output<typeof seoOptions> }
|
||||
})
|
||||
.refine((value) => {
|
||||
return value.locales.some((locale) => locale.tag === value.defaultLocale)
|
||||
}, 'Default locale must be defined')
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { z as t } from 'zod'
|
||||
|
||||
export const seoOptions = t.object({
|
||||
/** Whether CEO features are enabled. */
|
||||
enabled: t.boolean().default(true),
|
||||
|
||||
/**
|
||||
* Name of the host language URL parameter, used to override the default or
|
||||
* user language.
|
||||
*
|
||||
* @default 'hl' // For example, ?hl=en to use English locale (if defined).
|
||||
*/
|
||||
hostLanguageParameter: t
|
||||
.string()
|
||||
.describe(
|
||||
'Name of the host language URL parameter, used to override the default or user language.',
|
||||
)
|
||||
.optional()
|
||||
.default('hl'),
|
||||
|
||||
/**
|
||||
* Base URL at which the site will be available. This is required to generate
|
||||
* absolute hreflang links. Without this, VIntl will try to guess the URL
|
||||
* based on the server request URL / current `window.location`.
|
||||
*/
|
||||
baseURL: t
|
||||
.string()
|
||||
.describe(
|
||||
'Base URL at which the site will be available. This is required to generate absolute hreflang links. ',
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
@@ -6,8 +6,8 @@ import slash from 'slash'
|
||||
export function createDirResolver(dir: string) {
|
||||
const pseudoParent = pathToFileURL(joinPaths(dir, '.resolve-root')).toString()
|
||||
|
||||
return async function resolve(specifier: string) {
|
||||
const resolved = await rawResolve(specifier, pseudoParent)
|
||||
return function resolve(specifier: string) {
|
||||
const resolved = rawResolve(specifier, pseudoParent)
|
||||
|
||||
return {
|
||||
/** A getter that returns resolved URL as is. */
|
||||
|
||||
+27
@@ -64,4 +64,31 @@ declare module '@vintl/nuxt-runtime/options' {
|
||||
* descriptor.
|
||||
*/
|
||||
export const parserless: boolean
|
||||
|
||||
export interface SEOOptions {
|
||||
/**
|
||||
* Whether SEO features are enabled.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
enabled: boolean
|
||||
|
||||
/**
|
||||
* Name of the host language URL parameter, used to override the default or
|
||||
* user language.
|
||||
*
|
||||
* @default 'hl' // For example, ?hl=en to use English locale (if defined).
|
||||
*/
|
||||
hostLanguageParameter: string
|
||||
|
||||
/**
|
||||
* Base URL at which the site will be available. This is required to generate
|
||||
* absolute hreflang links. Without this, VIntl must try to guess the URL
|
||||
* based on the server request URL / current `window.location`.
|
||||
*/
|
||||
baseURL?: string
|
||||
}
|
||||
|
||||
/** SEO options. */
|
||||
export const seo: SEOOptions
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
diff --git a/package.json b/package.json
|
||||
index 55da8ad891741382b793f105b328b77997fab1de..d714282fd3742d377fe05db58bc00460ae44cdb6 100644
|
||||
--- a/package.json
|
||||
+++ b/package.json
|
||||
@@ -6,6 +6,7 @@
|
||||
"module": "./dist/astring.mjs",
|
||||
"types": "./astring.d.ts",
|
||||
"exports": {
|
||||
+ "types": "./astring.d.ts",
|
||||
"import": "./dist/astring.mjs",
|
||||
"require": "./dist/astring.js",
|
||||
"browser": "./dist/astring.min.js"
|
||||
Generated
+1796
-1466
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user