@zachhandley/ez-i18n 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.js +385 -24
- package/dist/runtime/react-plugin.d.ts +29 -0
- package/dist/runtime/react-plugin.js +85 -0
- package/dist/runtime/vue-plugin.d.ts +1 -1
- package/dist/types-CHyDGt_C.d.ts +86 -0
- package/dist/utils/index.d.ts +59 -0
- package/dist/utils/index.js +190 -0
- package/package.json +112 -89
- package/src/components/EzI18nHead.astro +1 -1
- package/src/runtime/react-plugin.ts +78 -0
- package/src/types.ts +57 -12
- package/src/utils/index.ts +13 -0
- package/src/utils/translations.ts +311 -0
- package/src/vite-plugin.ts +329 -29
- package/dist/types-DwCG8sp8.d.ts +0 -48
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// src/runtime/react-plugin.ts
|
|
2
|
+
import { useStore } from "@nanostores/react";
|
|
3
|
+
|
|
4
|
+
// src/runtime/store.ts
|
|
5
|
+
import { atom, computed } from "nanostores";
|
|
6
|
+
import { persistentAtom } from "@nanostores/persistent";
|
|
7
|
+
var serverLocale = atom(null);
|
|
8
|
+
var localePreference = persistentAtom("ez-locale", "en", {
|
|
9
|
+
encode: (value) => value,
|
|
10
|
+
decode: (value) => value
|
|
11
|
+
});
|
|
12
|
+
var effectiveLocale = computed(
|
|
13
|
+
[serverLocale, localePreference],
|
|
14
|
+
(server, client) => server ?? client
|
|
15
|
+
);
|
|
16
|
+
var translations = atom({});
|
|
17
|
+
var localeLoading = atom(false);
|
|
18
|
+
async function setLocale(locale, options = {}) {
|
|
19
|
+
const opts = typeof options === "string" ? { cookieName: options } : options;
|
|
20
|
+
const { cookieName = "ez-locale", loadTranslations } = opts;
|
|
21
|
+
localeLoading.set(true);
|
|
22
|
+
try {
|
|
23
|
+
if (loadTranslations) {
|
|
24
|
+
const mod = await loadTranslations();
|
|
25
|
+
const trans = "default" in mod ? mod.default : mod;
|
|
26
|
+
translations.set(trans);
|
|
27
|
+
}
|
|
28
|
+
localePreference.set(locale);
|
|
29
|
+
serverLocale.set(locale);
|
|
30
|
+
if (typeof document !== "undefined") {
|
|
31
|
+
document.cookie = `${cookieName}=${locale}; path=/; max-age=31536000; samesite=lax`;
|
|
32
|
+
}
|
|
33
|
+
if (typeof document !== "undefined") {
|
|
34
|
+
document.dispatchEvent(
|
|
35
|
+
new CustomEvent("ez-i18n:locale-changed", {
|
|
36
|
+
detail: { locale },
|
|
37
|
+
bubbles: true
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
} finally {
|
|
42
|
+
localeLoading.set(false);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/runtime/react-plugin.ts
|
|
47
|
+
function getNestedValue(obj, path) {
|
|
48
|
+
const keys = path.split(".");
|
|
49
|
+
let value = obj;
|
|
50
|
+
for (const key of keys) {
|
|
51
|
+
if (value == null || typeof value !== "object") {
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
54
|
+
value = value[key];
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
function interpolate(str, params) {
|
|
59
|
+
if (!params) return str;
|
|
60
|
+
return str.replace(/\{(\w+)\}/g, (match, key) => {
|
|
61
|
+
return key in params ? String(params[key]) : match;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function useI18n() {
|
|
65
|
+
const locale = useStore(effectiveLocale);
|
|
66
|
+
const trans = useStore(translations);
|
|
67
|
+
const t = (key, params) => {
|
|
68
|
+
const value = getNestedValue(trans, key);
|
|
69
|
+
if (typeof value !== "string") {
|
|
70
|
+
if (import.meta.env?.DEV) {
|
|
71
|
+
console.warn("[ez-i18n] Missing translation:", key);
|
|
72
|
+
}
|
|
73
|
+
return key;
|
|
74
|
+
}
|
|
75
|
+
return interpolate(value, params);
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
t,
|
|
79
|
+
locale,
|
|
80
|
+
setLocale
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
useI18n
|
|
85
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation path for a single locale:
|
|
3
|
+
* - Single file: `./src/i18n/en.json`
|
|
4
|
+
* - Folder: `./src/i18n/en/` (auto-discover all JSONs inside)
|
|
5
|
+
* - Glob: `./src/i18n/en/**.json` (recursive)
|
|
6
|
+
* - Array: `['./common.json', './auth.json']`
|
|
7
|
+
*/
|
|
8
|
+
type LocaleTranslationPath = string | string[];
|
|
9
|
+
/**
|
|
10
|
+
* Translation config can be:
|
|
11
|
+
* - A base directory string (auto-discovers locale folders): './public/i18n/'
|
|
12
|
+
* - Per-locale mapping: { en: './src/i18n/en/', es: './src/i18n/es.json' }
|
|
13
|
+
*/
|
|
14
|
+
type TranslationsConfig = string | Record<string, LocaleTranslationPath>;
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for ez-i18n Astro integration
|
|
17
|
+
*/
|
|
18
|
+
interface EzI18nConfig {
|
|
19
|
+
/**
|
|
20
|
+
* List of supported locale codes (e.g., ['en', 'es', 'fr'])
|
|
21
|
+
* Optional if using directory-based auto-discovery - locales will be
|
|
22
|
+
* detected from folder names in the translations directory.
|
|
23
|
+
*/
|
|
24
|
+
locales?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Default locale to use when no preference is detected.
|
|
27
|
+
* Required - this tells us what to fall back to.
|
|
28
|
+
*/
|
|
29
|
+
defaultLocale: string;
|
|
30
|
+
/**
|
|
31
|
+
* Cookie name for storing locale preference
|
|
32
|
+
* @default 'ez-locale'
|
|
33
|
+
*/
|
|
34
|
+
cookieName?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Translation file paths configuration.
|
|
37
|
+
* Paths are relative to your project root.
|
|
38
|
+
*
|
|
39
|
+
* Can be:
|
|
40
|
+
* - A base directory (auto-discovers locale folders):
|
|
41
|
+
* translations: './public/i18n/'
|
|
42
|
+
* → Scans for en/, es/, fr/ folders and their JSON files
|
|
43
|
+
* → Auto-populates `locales` from discovered folders
|
|
44
|
+
*
|
|
45
|
+
* - Per-locale mapping with flexible path types:
|
|
46
|
+
* translations: {
|
|
47
|
+
* en: './src/i18n/en.json', // single file
|
|
48
|
+
* es: './src/i18n/es/', // folder (all JSONs)
|
|
49
|
+
* fr: './src/i18n/fr/**.json', // glob pattern
|
|
50
|
+
* de: ['./common.json', './auth.json'] // array of files
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* If not specified, auto-discovers from ./public/i18n/
|
|
54
|
+
*/
|
|
55
|
+
translations?: TranslationsConfig;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Cache file structure (.ez-i18n.json)
|
|
59
|
+
* Used to speed up subsequent builds by caching discovered translations
|
|
60
|
+
*/
|
|
61
|
+
interface TranslationCache {
|
|
62
|
+
version: number;
|
|
63
|
+
/** Discovered locale → file paths mapping */
|
|
64
|
+
discovered: Record<string, string[]>;
|
|
65
|
+
/** ISO timestamp of last scan */
|
|
66
|
+
lastScan: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Translation function type
|
|
70
|
+
*/
|
|
71
|
+
type TranslateFunction = (key: string, params?: Record<string, string | number>) => string;
|
|
72
|
+
/**
|
|
73
|
+
* Augment Astro's locals type
|
|
74
|
+
*/
|
|
75
|
+
declare global {
|
|
76
|
+
namespace App {
|
|
77
|
+
interface Locals {
|
|
78
|
+
/** Current locale code */
|
|
79
|
+
locale: string;
|
|
80
|
+
/** Loaded translations for the current locale */
|
|
81
|
+
translations: Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type { EzI18nConfig as E, LocaleTranslationPath as L, TranslateFunction as T, TranslationsConfig as a, TranslationCache as b };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { L as LocaleTranslationPath, a as TranslationsConfig, b as TranslationCache } from '../types-CHyDGt_C.js';
|
|
2
|
+
|
|
3
|
+
type PathType = 'file' | 'folder' | 'glob' | 'array';
|
|
4
|
+
/**
|
|
5
|
+
* Detect the type of translation path
|
|
6
|
+
*/
|
|
7
|
+
declare function detectPathType(input: string | string[]): PathType;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a single translation path to an array of absolute file paths.
|
|
10
|
+
* Results are sorted alphabetically for predictable merge order.
|
|
11
|
+
*/
|
|
12
|
+
declare function resolveTranslationPaths(input: LocaleTranslationPath, projectRoot: string): Promise<string[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Auto-discover translations from a base directory.
|
|
15
|
+
* Scans for locale folders (e.g., en/, es/, fr/) and their JSON files.
|
|
16
|
+
* Returns both discovered locales and their file mappings.
|
|
17
|
+
*/
|
|
18
|
+
declare function autoDiscoverTranslations(baseDir: string, projectRoot: string, configuredLocales?: string[]): Promise<{
|
|
19
|
+
locales: string[];
|
|
20
|
+
translations: Record<string, string[]>;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the full translations config to normalized form.
|
|
24
|
+
* Handles string (base dir), object (per-locale), or undefined (auto-discover).
|
|
25
|
+
*/
|
|
26
|
+
declare function resolveTranslationsConfig(config: TranslationsConfig | undefined, projectRoot: string, configuredLocales?: string[]): Promise<{
|
|
27
|
+
locales: string[];
|
|
28
|
+
translations: Record<string, string[]>;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Deep merge translation objects.
|
|
32
|
+
* - Objects are recursively merged
|
|
33
|
+
* - Arrays are REPLACED (not concatenated)
|
|
34
|
+
* - Primitives are overwritten by later values
|
|
35
|
+
* - Prototype pollution safe
|
|
36
|
+
*/
|
|
37
|
+
declare function deepMerge<T extends Record<string, unknown>>(target: T, ...sources: T[]): T;
|
|
38
|
+
/**
|
|
39
|
+
* Load cached translation discovery results
|
|
40
|
+
*/
|
|
41
|
+
declare function loadCache(projectRoot: string): TranslationCache | null;
|
|
42
|
+
/**
|
|
43
|
+
* Save translation discovery results to cache
|
|
44
|
+
*/
|
|
45
|
+
declare function saveCache(projectRoot: string, discovered: Record<string, string[]>): void;
|
|
46
|
+
/**
|
|
47
|
+
* Check if cache is still valid (files haven't changed)
|
|
48
|
+
*/
|
|
49
|
+
declare function isCacheValid(cache: TranslationCache, projectRoot: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Convert an absolute path to a relative import path for Vite
|
|
52
|
+
*/
|
|
53
|
+
declare function toRelativeImport(absolutePath: string, projectRoot: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Generate a glob pattern for import.meta.glob from a base directory
|
|
56
|
+
*/
|
|
57
|
+
declare function toGlobPattern(baseDir: string, projectRoot: string): string;
|
|
58
|
+
|
|
59
|
+
export { type PathType, autoDiscoverTranslations, deepMerge, detectPathType, isCacheValid, loadCache, resolveTranslationPaths, resolveTranslationsConfig, saveCache, toGlobPattern, toRelativeImport };
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// src/utils/translations.ts
|
|
2
|
+
import { glob } from "tinyglobby";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
var CACHE_FILE = ".ez-i18n.json";
|
|
6
|
+
var CACHE_VERSION = 1;
|
|
7
|
+
var DEFAULT_I18N_DIR = "./public/i18n";
|
|
8
|
+
function detectPathType(input) {
|
|
9
|
+
if (Array.isArray(input)) return "array";
|
|
10
|
+
if (input.includes("*")) return "glob";
|
|
11
|
+
if (input.endsWith("/") || input.endsWith(path.sep)) return "folder";
|
|
12
|
+
return "file";
|
|
13
|
+
}
|
|
14
|
+
function isDirectory(filePath) {
|
|
15
|
+
try {
|
|
16
|
+
return fs.statSync(filePath).isDirectory();
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function resolveTranslationPaths(input, projectRoot) {
|
|
22
|
+
const type = detectPathType(input);
|
|
23
|
+
let files = [];
|
|
24
|
+
switch (type) {
|
|
25
|
+
case "array":
|
|
26
|
+
for (const entry of input) {
|
|
27
|
+
const resolved = await resolveTranslationPaths(entry, projectRoot);
|
|
28
|
+
files.push(...resolved);
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
case "glob":
|
|
32
|
+
files = await glob(input, {
|
|
33
|
+
cwd: projectRoot,
|
|
34
|
+
absolute: true
|
|
35
|
+
});
|
|
36
|
+
break;
|
|
37
|
+
case "folder": {
|
|
38
|
+
const folderPath = path.resolve(projectRoot, input.replace(/\/$/, ""));
|
|
39
|
+
files = await glob("**/*.json", {
|
|
40
|
+
cwd: folderPath,
|
|
41
|
+
absolute: true
|
|
42
|
+
});
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case "file":
|
|
46
|
+
default: {
|
|
47
|
+
const filePath = path.resolve(projectRoot, input);
|
|
48
|
+
if (isDirectory(filePath)) {
|
|
49
|
+
files = await glob("**/*.json", {
|
|
50
|
+
cwd: filePath,
|
|
51
|
+
absolute: true
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
files = [filePath];
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return [...new Set(files)].sort((a, b) => a.localeCompare(b));
|
|
60
|
+
}
|
|
61
|
+
async function autoDiscoverTranslations(baseDir, projectRoot, configuredLocales) {
|
|
62
|
+
const absoluteBaseDir = path.resolve(projectRoot, baseDir.replace(/\/$/, ""));
|
|
63
|
+
if (!isDirectory(absoluteBaseDir)) {
|
|
64
|
+
console.warn(`[ez-i18n] Translation directory not found: ${absoluteBaseDir}`);
|
|
65
|
+
return { locales: configuredLocales || [], translations: {} };
|
|
66
|
+
}
|
|
67
|
+
const translations = {};
|
|
68
|
+
const discoveredLocales = [];
|
|
69
|
+
const entries = fs.readdirSync(absoluteBaseDir, { withFileTypes: true });
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
if (entry.isDirectory()) {
|
|
72
|
+
const locale = entry.name;
|
|
73
|
+
if (configuredLocales && configuredLocales.length > 0) {
|
|
74
|
+
if (!configuredLocales.includes(locale)) continue;
|
|
75
|
+
}
|
|
76
|
+
const localePath = path.join(absoluteBaseDir, locale);
|
|
77
|
+
const files = await glob("**/*.json", {
|
|
78
|
+
cwd: localePath,
|
|
79
|
+
absolute: true
|
|
80
|
+
});
|
|
81
|
+
if (files.length > 0) {
|
|
82
|
+
discoveredLocales.push(locale);
|
|
83
|
+
translations[locale] = files.sort((a, b) => a.localeCompare(b));
|
|
84
|
+
}
|
|
85
|
+
} else if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
86
|
+
const locale = path.basename(entry.name, ".json");
|
|
87
|
+
if (configuredLocales && configuredLocales.length > 0) {
|
|
88
|
+
if (!configuredLocales.includes(locale)) continue;
|
|
89
|
+
}
|
|
90
|
+
const filePath = path.join(absoluteBaseDir, entry.name);
|
|
91
|
+
if (!translations[locale]) {
|
|
92
|
+
discoveredLocales.push(locale);
|
|
93
|
+
translations[locale] = [];
|
|
94
|
+
}
|
|
95
|
+
translations[locale].push(filePath);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const sortedLocales = [...new Set(discoveredLocales)].sort();
|
|
99
|
+
return { locales: sortedLocales, translations };
|
|
100
|
+
}
|
|
101
|
+
async function resolveTranslationsConfig(config, projectRoot, configuredLocales) {
|
|
102
|
+
if (!config) {
|
|
103
|
+
return autoDiscoverTranslations(DEFAULT_I18N_DIR, projectRoot, configuredLocales);
|
|
104
|
+
}
|
|
105
|
+
if (typeof config === "string") {
|
|
106
|
+
return autoDiscoverTranslations(config, projectRoot, configuredLocales);
|
|
107
|
+
}
|
|
108
|
+
const translations = {};
|
|
109
|
+
const locales = Object.keys(config);
|
|
110
|
+
for (const [locale, localePath] of Object.entries(config)) {
|
|
111
|
+
translations[locale] = await resolveTranslationPaths(localePath, projectRoot);
|
|
112
|
+
}
|
|
113
|
+
return { locales, translations };
|
|
114
|
+
}
|
|
115
|
+
function deepMerge(target, ...sources) {
|
|
116
|
+
const FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
117
|
+
const result = { ...target };
|
|
118
|
+
for (const source of sources) {
|
|
119
|
+
if (!source || typeof source !== "object") continue;
|
|
120
|
+
for (const key of Object.keys(source)) {
|
|
121
|
+
if (FORBIDDEN_KEYS.has(key)) continue;
|
|
122
|
+
const targetVal = result[key];
|
|
123
|
+
const sourceVal = source[key];
|
|
124
|
+
if (sourceVal !== null && typeof sourceVal === "object" && !Array.isArray(sourceVal) && targetVal !== null && typeof targetVal === "object" && !Array.isArray(targetVal)) {
|
|
125
|
+
result[key] = deepMerge(
|
|
126
|
+
targetVal,
|
|
127
|
+
sourceVal
|
|
128
|
+
);
|
|
129
|
+
} else {
|
|
130
|
+
result[key] = sourceVal;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
function loadCache(projectRoot) {
|
|
137
|
+
const cachePath = path.join(projectRoot, CACHE_FILE);
|
|
138
|
+
try {
|
|
139
|
+
if (!fs.existsSync(cachePath)) return null;
|
|
140
|
+
const content = fs.readFileSync(cachePath, "utf-8");
|
|
141
|
+
const cache = JSON.parse(content);
|
|
142
|
+
if (cache.version !== CACHE_VERSION) return null;
|
|
143
|
+
return cache;
|
|
144
|
+
} catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function saveCache(projectRoot, discovered) {
|
|
149
|
+
const cachePath = path.join(projectRoot, CACHE_FILE);
|
|
150
|
+
const cache = {
|
|
151
|
+
version: CACHE_VERSION,
|
|
152
|
+
discovered,
|
|
153
|
+
lastScan: (/* @__PURE__ */ new Date()).toISOString()
|
|
154
|
+
};
|
|
155
|
+
try {
|
|
156
|
+
fs.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.warn("[ez-i18n] Failed to write cache file:", error);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function isCacheValid(cache, projectRoot) {
|
|
162
|
+
for (const files of Object.values(cache.discovered)) {
|
|
163
|
+
for (const file of files) {
|
|
164
|
+
if (!fs.existsSync(file)) return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
function toRelativeImport(absolutePath, projectRoot) {
|
|
170
|
+
const relativePath = path.relative(projectRoot, absolutePath);
|
|
171
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
172
|
+
return normalized.startsWith(".") ? normalized : "./" + normalized;
|
|
173
|
+
}
|
|
174
|
+
function toGlobPattern(baseDir, projectRoot) {
|
|
175
|
+
const relativePath = path.relative(projectRoot, baseDir).replace(/\\/g, "/");
|
|
176
|
+
const normalized = relativePath.startsWith(".") ? relativePath : "./" + relativePath;
|
|
177
|
+
return `${normalized}/**/*.json`;
|
|
178
|
+
}
|
|
179
|
+
export {
|
|
180
|
+
autoDiscoverTranslations,
|
|
181
|
+
deepMerge,
|
|
182
|
+
detectPathType,
|
|
183
|
+
isCacheValid,
|
|
184
|
+
loadCache,
|
|
185
|
+
resolveTranslationPaths,
|
|
186
|
+
resolveTranslationsConfig,
|
|
187
|
+
saveCache,
|
|
188
|
+
toGlobPattern,
|
|
189
|
+
toRelativeImport
|
|
190
|
+
};
|
package/package.json
CHANGED
|
@@ -1,89 +1,112 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@zachhandley/ez-i18n",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"publishConfig": {
|
|
5
|
-
"access": "public"
|
|
6
|
-
},
|
|
7
|
-
"description": "Cookie-based i18n for Astro + Vue. No URL prefixes, reactive language switching.",
|
|
8
|
-
"type": "module",
|
|
9
|
-
"main": "./dist/index.js",
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"import": "./dist/index.js"
|
|
15
|
-
},
|
|
16
|
-
"./vue": {
|
|
17
|
-
"types": "./dist/runtime/vue-plugin.d.ts",
|
|
18
|
-
"import": "./dist/runtime/vue-plugin.js"
|
|
19
|
-
},
|
|
20
|
-
"./middleware": {
|
|
21
|
-
"import": "./dist/middleware.js"
|
|
22
|
-
},
|
|
23
|
-
"./runtime": {
|
|
24
|
-
"types": "./dist/runtime/index.d.ts",
|
|
25
|
-
"import": "./dist/runtime/index.js"
|
|
26
|
-
},
|
|
27
|
-
"./astro": {
|
|
28
|
-
"import": "./src/components/EzI18nHead.astro"
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@zachhandley/ez-i18n",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "Cookie-based i18n for Astro + Vue + React. No URL prefixes, reactive language switching.",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./vue": {
|
|
17
|
+
"types": "./dist/runtime/vue-plugin.d.ts",
|
|
18
|
+
"import": "./dist/runtime/vue-plugin.js"
|
|
19
|
+
},
|
|
20
|
+
"./middleware": {
|
|
21
|
+
"import": "./dist/middleware.js"
|
|
22
|
+
},
|
|
23
|
+
"./runtime": {
|
|
24
|
+
"types": "./dist/runtime/index.d.ts",
|
|
25
|
+
"import": "./dist/runtime/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./astro": {
|
|
28
|
+
"import": "./src/components/EzI18nHead.astro"
|
|
29
|
+
},
|
|
30
|
+
"./react": {
|
|
31
|
+
"types": "./dist/runtime/react-plugin.d.ts",
|
|
32
|
+
"import": "./dist/runtime/react-plugin.js"
|
|
33
|
+
},
|
|
34
|
+
"./utils": {
|
|
35
|
+
"types": "./dist/utils/index.d.ts",
|
|
36
|
+
"import": "./dist/utils/index.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"src"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"dev": "tsup --watch",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"prepublishOnly": "pnpm build",
|
|
48
|
+
"release": "pnpm build && npm publish",
|
|
49
|
+
"release:dry": "pnpm build && npm publish --dry-run"
|
|
50
|
+
},
|
|
51
|
+
"keywords": [
|
|
52
|
+
"astro",
|
|
53
|
+
"astro-integration",
|
|
54
|
+
"i18n",
|
|
55
|
+
"internationalization",
|
|
56
|
+
"vue",
|
|
57
|
+
"react",
|
|
58
|
+
"cookie-based",
|
|
59
|
+
"no-url-prefix"
|
|
60
|
+
],
|
|
61
|
+
"author": "Zach Handley <zachhandley@gmail.com>",
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"homepage": "https://github.com/zachhandley/ez-i18n#readme",
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "git+https://github.com/zachhandley/ez-i18n.git"
|
|
67
|
+
},
|
|
68
|
+
"bugs": {
|
|
69
|
+
"url": "https://github.com/zachhandley/ez-i18n/issues"
|
|
70
|
+
},
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"tinyglobby": "^0.2.15"
|
|
73
|
+
},
|
|
74
|
+
"peerDependencies": {
|
|
75
|
+
"@nanostores/persistent": "^0.10.0",
|
|
76
|
+
"@nanostores/react": "^0.7.0 || ^0.8.0 || ^1.0.0",
|
|
77
|
+
"@nanostores/vue": "^0.10.0",
|
|
78
|
+
"astro": "^4.0.0 || ^5.0.0",
|
|
79
|
+
"nanostores": "^0.9.0 || ^0.10.0 || ^0.11.0",
|
|
80
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
81
|
+
"vue": "^3.4.0"
|
|
82
|
+
},
|
|
83
|
+
"peerDependenciesMeta": {
|
|
84
|
+
"vue": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"react": {
|
|
88
|
+
"optional": true
|
|
89
|
+
},
|
|
90
|
+
"@nanostores/vue": {
|
|
91
|
+
"optional": true
|
|
92
|
+
},
|
|
93
|
+
"@nanostores/react": {
|
|
94
|
+
"optional": true
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"devDependencies": {
|
|
98
|
+
"@nanostores/persistent": "^0.10.2",
|
|
99
|
+
"@nanostores/react": "^1.0.0",
|
|
100
|
+
"@nanostores/vue": "^0.10.0",
|
|
101
|
+
"@types/node": "^22.0.0",
|
|
102
|
+
"@types/react": "^19.2.7",
|
|
103
|
+
"astro": "^5.1.1",
|
|
104
|
+
"nanostores": "^0.11.3",
|
|
105
|
+
"react": "^19.2.1",
|
|
106
|
+
"tsup": "^8.3.5",
|
|
107
|
+
"typescript": "^5.7.2",
|
|
108
|
+
"vite": "^6.0.3",
|
|
109
|
+
"vue": "^3.5.13"
|
|
110
|
+
},
|
|
111
|
+
"packageManager": "pnpm@10.17.1+sha512.17c560fca4867ae9473a3899ad84a88334914f379be46d455cbf92e5cf4b39d34985d452d2583baf19967fa76cb5c17bc9e245529d0b98745721aa7200ecaf7a"
|
|
112
|
+
}
|