@comvi/vue 0.2.0 → 0.3.0
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 +1 -1
- package/dist/VueI18n.d.ts +50 -12
- package/dist/VueI18n.d.ts.map +1 -1
- package/dist/composables/useI18n.d.ts +41 -17
- package/dist/composables/useI18n.d.ts.map +1 -1
- package/dist/comvi-vue.js +507 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +7 -6
- package/dist/comvi-vue.cjs +0 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Comvi i18n is a modern, framework-agnostic internationalization library built on
|
|
|
32
32
|
- **Rich text without XSS.** Embed components inside translation strings (`Click <link>here</link>`) — translators see clean markup, you decide what each tag renders to. No raw HTML, no unsafe DOM injection, no splitting a sentence across template fragments.
|
|
33
33
|
- **Real ICU MessageFormat.** Plurals, ordinals, and select all follow locale-correct grammar via `Intl.PluralRules` — Polish, Ukrainian, Arabic, Welsh, and the rest. Same syntax every major TMS (Crowdin, Lokalise, Phrase) already speaks.
|
|
34
34
|
- **Locale-aware formatters built in.** `formatNumber`, `formatDate`, `formatCurrency`, and `formatRelativeTime` follow the active locale via native `Intl`, with reactive updates in every framework binding.
|
|
35
|
-
- **~8 kB gzipped, zero runtime dependencies.** No `eval` or `new Function` anywhere — runs under a strict CSP without `unsafe-eval`. Safe for Chrome extensions, Cloudflare Workers, and locked-down enterprise apps.
|
|
35
|
+
- **~8 kB minified + gzipped (as bundled by your app), zero runtime dependencies.** No `eval` or `new Function` anywhere — runs under a strict CSP without `unsafe-eval`. Safe for Chrome extensions, Cloudflare Workers, and locked-down enterprise apps.
|
|
36
36
|
- **Pluggable, not monolithic.** Translation loading (CDN/API), locale detection, and in-context editing are opt-in plugins via `@comvi/plugin-fetch-loader`, `@comvi/plugin-locale-detector`, and `@comvi/plugin-in-context-editor`. You only ship what you use.
|
|
37
37
|
- **Same API across 6 frameworks.** `useI18n()` and `<T>` look the same in [Vue](https://www.npmjs.com/package/@comvi/vue), [React](https://www.npmjs.com/package/@comvi/react), [SolidJS](https://www.npmjs.com/package/@comvi/solid), [Svelte](https://www.npmjs.com/package/@comvi/svelte), [Next.js](https://www.npmjs.com/package/@comvi/next), and [Nuxt](https://www.npmjs.com/package/@comvi/nuxt) — switch frameworks without relearning your i18n layer.
|
|
38
38
|
|
package/dist/VueI18n.d.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { I18n, I18nOptions, FlattenedTranslations, TranslationParams, TranslationResult, TranslationValue, I18nPlugin, I18nEvent, I18nEventData } from '@comvi/core';
|
|
2
|
-
import { Ref, App } from 'vue';
|
|
2
|
+
import { Ref, ComputedRef, App } from 'vue';
|
|
3
3
|
/**
|
|
4
4
|
* Vue-specific i18n options extending core options
|
|
5
5
|
*/
|
|
6
6
|
export interface VueI18nOptions extends I18nOptions {
|
|
7
|
-
/** @deprecated Use locale. */
|
|
8
|
-
language?: string;
|
|
9
7
|
/**
|
|
10
8
|
* Initial locale for SSR hydration.
|
|
11
9
|
* Use this to prevent hydration mismatches when server renders with a different
|
|
12
10
|
* locale than what the client would detect.
|
|
13
11
|
*/
|
|
14
|
-
|
|
12
|
+
ssrLocale?: string;
|
|
15
13
|
}
|
|
16
14
|
/**
|
|
17
15
|
* Vue-specific wrapper around the core I18n using composition
|
|
@@ -24,7 +22,8 @@ export declare class VueI18n {
|
|
|
24
22
|
private _isLoading;
|
|
25
23
|
private _isInitializing;
|
|
26
24
|
private _cacheRevision;
|
|
27
|
-
private
|
|
25
|
+
private _configRevision;
|
|
26
|
+
private _translationCacheComputed?;
|
|
28
27
|
private _unsubscribers;
|
|
29
28
|
private _requestedLocale;
|
|
30
29
|
private _localeQueue;
|
|
@@ -40,13 +39,8 @@ export declare class VueI18n {
|
|
|
40
39
|
onMissingKey: (callback: (key: string, locale: string, namespace: string) => TranslationResult | void) => () => void;
|
|
41
40
|
onLoadError: (callback: (locale: string, namespace: string, error: Error) => void) => () => void;
|
|
42
41
|
on: <E extends I18nEvent>(event: E, callback: (payload: I18nEventData[E]) => void) => () => void;
|
|
43
|
-
hasLocale: (locale: string, namespace?: string) => boolean;
|
|
44
|
-
hasTranslation: (key: string, locale?: string, namespace?: string, checkFallbacks?: boolean) => boolean;
|
|
45
|
-
getLoadedLocales: () => string[];
|
|
46
42
|
setFallbackLocale: (locales: string | string[]) => void;
|
|
47
|
-
getDefaultNamespace: () => string;
|
|
48
43
|
reportError: (error: unknown, context?: Parameters<I18n["reportError"]>[1]) => void;
|
|
49
|
-
getActiveNamespaces: () => string[];
|
|
50
44
|
formatNumber: I18n["formatNumber"];
|
|
51
45
|
formatDate: I18n["formatDate"];
|
|
52
46
|
formatCurrency: I18n["formatCurrency"];
|
|
@@ -56,9 +50,40 @@ export declare class VueI18n {
|
|
|
56
50
|
set locale(value: string);
|
|
57
51
|
private _dirComputed?;
|
|
58
52
|
/** Text direction for the current locale, as a reactive computed ref */
|
|
59
|
-
get dir():
|
|
53
|
+
get dir(): ComputedRef<"ltr" | "rtl">;
|
|
54
|
+
private _loadedLocalesComputed?;
|
|
55
|
+
get loadedLocales(): ComputedRef<string[]>;
|
|
56
|
+
private _activeNamespacesComputed?;
|
|
57
|
+
get activeNamespaces(): ComputedRef<string[]>;
|
|
58
|
+
private _defaultNamespaceComputed?;
|
|
59
|
+
/** Current default namespace as a reactive ComputedRef */
|
|
60
|
+
get defaultNamespace(): ComputedRef<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Reactive check for translation existence. Returns a ComputedRef that
|
|
63
|
+
* re-evaluates when locale, cache, or config changes. Call inside component setup
|
|
64
|
+
* (or an effectScope) — the underlying `computed()` registers with the
|
|
65
|
+
* active scope and disposes automatically.
|
|
66
|
+
*/
|
|
67
|
+
hasTranslation(key: string, opts?: {
|
|
68
|
+
locale?: string;
|
|
69
|
+
namespace?: string;
|
|
70
|
+
checkFallbacks?: boolean;
|
|
71
|
+
}): ComputedRef<boolean>;
|
|
72
|
+
/**
|
|
73
|
+
* Reactive check for locale availability. Returns a ComputedRef that
|
|
74
|
+
* re-evaluates when the translation cache changes.
|
|
75
|
+
*/
|
|
76
|
+
hasLocale(locale: string, namespace?: string): ComputedRef<boolean>;
|
|
77
|
+
/** Imperative (non-reactive) translation-existence check — plain boolean, for use outside a reactive scope. */
|
|
78
|
+
hasTranslationNow(key: string, opts?: {
|
|
79
|
+
locale?: string;
|
|
80
|
+
namespace?: string;
|
|
81
|
+
checkFallbacks?: boolean;
|
|
82
|
+
}): boolean;
|
|
83
|
+
/** Imperative (non-reactive) locale-availability check — plain boolean, for use outside a reactive scope. */
|
|
84
|
+
hasLocaleNow(locale: string, namespace?: string): boolean;
|
|
60
85
|
setLocale(locale: string): Promise<void>;
|
|
61
|
-
get translationCache():
|
|
86
|
+
get translationCache(): ComputedRef<ReadonlyMap<string, FlattenedTranslations>>;
|
|
62
87
|
get isLoading(): Readonly<Ref<boolean>>;
|
|
63
88
|
get isInitializing(): Readonly<Ref<boolean>>;
|
|
64
89
|
/** Raw translation result for rich text renderers and advanced integrations. */
|
|
@@ -83,6 +108,19 @@ export declare class VueI18n {
|
|
|
83
108
|
use(plugin: I18nPlugin, options?: Parameters<I18n["use"]>[1]): this;
|
|
84
109
|
destroy(): void;
|
|
85
110
|
private _installedApps;
|
|
111
|
+
/**
|
|
112
|
+
* Install the i18n plugin into a Vue app.
|
|
113
|
+
*
|
|
114
|
+
* Side effects:
|
|
115
|
+
* - Provides the i18n instance via `I18N_INJECTION_KEY` so `useI18n()` works.
|
|
116
|
+
* - Registers `$t`, `$tRaw`, `$i18n` global properties for Options API + templates.
|
|
117
|
+
* - If the core isn't initialized yet, kicks off `init()` asynchronously (fire-and-forget).
|
|
118
|
+
*
|
|
119
|
+
* SSR note: on server-side rendering, call `await i18n.init()` BEFORE
|
|
120
|
+
* `renderToString(app)`. The fire-and-forget `init()` here is for client-side
|
|
121
|
+
* convenience only — on the server, rendering races against translation loading
|
|
122
|
+
* and you may serialize stale/empty caches.
|
|
123
|
+
*/
|
|
86
124
|
install(app: App): void;
|
|
87
125
|
}
|
|
88
126
|
export declare function createI18n(options: VueI18nOptions): VueI18n;
|
package/dist/VueI18n.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VueI18n.d.ts","sourceRoot":"","sources":["../src/VueI18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,EACV,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,aAAa,EACd,MAAM,aAAa,CAAC;AACrB,OAAO,
|
|
1
|
+
{"version":3,"file":"VueI18n.d.ts","sourceRoot":"","sources":["../src/VueI18n.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ref } from 'vue';
|
|
1
|
+
import { Ref, ComputedRef } from 'vue';
|
|
2
2
|
import { TranslationParams, TranslationResult, FlattenedTranslations, TranslationValue, I18nEvent, I18nEventData, I18n } from '@comvi/core';
|
|
3
3
|
export interface UseI18nReturn {
|
|
4
4
|
/** Translation function - namespaced keys (when ns is provided). Always returns plain text. */
|
|
@@ -17,8 +17,8 @@ export interface UseI18nReturn {
|
|
|
17
17
|
locale: Ref<string>;
|
|
18
18
|
/** Set locale asynchronously */
|
|
19
19
|
setLocale: (locale: string) => Promise<void>;
|
|
20
|
-
/** Translation cache
|
|
21
|
-
translationCache:
|
|
20
|
+
/** Translation cache as a reactive ComputedRef (stable identity, re-evaluates on cache mutation) */
|
|
21
|
+
translationCache: ComputedRef<ReadonlyMap<string, FlattenedTranslations>>;
|
|
22
22
|
/** Loading state (readonly reactive Vue Ref) */
|
|
23
23
|
isLoading: Readonly<Ref<boolean>>;
|
|
24
24
|
/** Initializing state (readonly reactive Vue Ref) */
|
|
@@ -37,16 +37,35 @@ export interface UseI18nReturn {
|
|
|
37
37
|
clearTranslations: (locale?: string, namespace?: string) => void;
|
|
38
38
|
/** Force reload translations from loader */
|
|
39
39
|
reloadTranslations: (locale?: string, namespace?: string) => Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
/** Reactive list of all loaded locale codes */
|
|
41
|
+
loadedLocales: ComputedRef<string[]>;
|
|
42
|
+
/** Reactive list of active namespaces */
|
|
43
|
+
activeNamespaces: ComputedRef<string[]>;
|
|
44
|
+
/** Reactive default namespace */
|
|
45
|
+
defaultNamespace: ComputedRef<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Reactive check for translation existence. Returns a ComputedRef<boolean>
|
|
48
|
+
* that re-evaluates when locale or cache changes. Call inside `setup()`
|
|
49
|
+
* (or an `effectScope`) so the underlying `computed()` disposes with the scope.
|
|
50
|
+
*/
|
|
51
|
+
hasTranslation: (key: string, opts?: {
|
|
52
|
+
locale?: string;
|
|
53
|
+
namespace?: string;
|
|
54
|
+
checkFallbacks?: boolean;
|
|
55
|
+
}) => ComputedRef<boolean>;
|
|
56
|
+
/**
|
|
57
|
+
* Reactive check for locale availability. Returns a ComputedRef<boolean>
|
|
58
|
+
* that re-evaluates when the translation cache changes.
|
|
59
|
+
*/
|
|
60
|
+
hasLocale: (locale: string, namespace?: string) => ComputedRef<boolean>;
|
|
61
|
+
/** Imperative (non-reactive) translation-existence check — plain boolean, for use outside a reactive scope. */
|
|
62
|
+
hasTranslationNow: (key: string, opts?: {
|
|
63
|
+
locale?: string;
|
|
64
|
+
namespace?: string;
|
|
65
|
+
checkFallbacks?: boolean;
|
|
66
|
+
}) => boolean;
|
|
67
|
+
/** Imperative (non-reactive) locale-availability check — returns a plain `boolean`. */
|
|
68
|
+
hasLocaleNow: (locale: string, namespace?: string) => boolean;
|
|
50
69
|
/** Subscribe to i18n events */
|
|
51
70
|
on: <E extends I18nEvent>(event: E, callback: (payload: I18nEventData[E]) => void) => () => void;
|
|
52
71
|
/** Report an error to the configured onError handler */
|
|
@@ -60,15 +79,20 @@ export interface UseI18nReturn {
|
|
|
60
79
|
/** Format a relative time ("2 hours ago", "in 3 days") using the current language locale */
|
|
61
80
|
formatRelativeTime: I18n["formatRelativeTime"];
|
|
62
81
|
/** Text direction for the current language, as a reactive computed ref */
|
|
63
|
-
dir:
|
|
82
|
+
dir: ComputedRef<"ltr" | "rtl">;
|
|
64
83
|
/** Cleanup resources (call when i18n instance is no longer needed) */
|
|
65
84
|
destroy: () => void;
|
|
66
85
|
}
|
|
67
86
|
/**
|
|
68
|
-
* Vue composable to access the i18n instance
|
|
69
|
-
* Must be
|
|
87
|
+
* Vue composable to access the i18n instance.
|
|
88
|
+
* Must be called within a component that has access to the i18n plugin
|
|
89
|
+
* (i.e. after `app.use(i18n)`).
|
|
70
90
|
*
|
|
71
|
-
* @param ns - Optional namespace to scope
|
|
91
|
+
* @param ns - Optional namespace to scope the returned `t` / `tRaw` functions to.
|
|
92
|
+
* When provided, key lookups default to this namespace instead of the
|
|
93
|
+
* configured `defaultNs`. Other returned methods (e.g. `hasTranslation`,
|
|
94
|
+
* `addActiveNamespace`) are NOT scoped — they accept explicit `namespace`
|
|
95
|
+
* arguments where applicable.
|
|
72
96
|
* @returns Object with translation function, reactive state, and i18n methods
|
|
73
97
|
*/
|
|
74
98
|
export declare function useI18n(ns?: string): UseI18nReturn;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useI18n.d.ts","sourceRoot":"","sources":["../../src/composables/useI18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"useI18n.d.ts","sourceRoot":"","sources":["../../src/composables/useI18n.ts"],"names":[],"mappings":"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"}
|
package/dist/comvi-vue.js
CHANGED
|
@@ -1 +1,507 @@
|
|
|
1
|
-
import{I18n
|
|
1
|
+
import { I18n, createBoundTranslation, createElement } from "@comvi/core";
|
|
2
|
+
import { Fragment, computed, defineComponent, h, inject, readonly, shallowRef } from "vue";
|
|
3
|
+
export * from "@comvi/core";
|
|
4
|
+
//#region src/keys.ts
|
|
5
|
+
/**
|
|
6
|
+
* Injection key for Vue's provide/inject pattern
|
|
7
|
+
* Used to inject the i18n instance into Vue components
|
|
8
|
+
*/
|
|
9
|
+
var I18N_INJECTION_KEY = Symbol("i18n");
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/utils.ts
|
|
12
|
+
function virtualNodeToText(node) {
|
|
13
|
+
if (node.type === "text") return node.text;
|
|
14
|
+
let text = "";
|
|
15
|
+
for (const child of node.children) text += typeof child === "string" ? child : virtualNodeToText(child);
|
|
16
|
+
return text;
|
|
17
|
+
}
|
|
18
|
+
function translationResultToString(result) {
|
|
19
|
+
if (typeof result === "string") return result;
|
|
20
|
+
let text = "";
|
|
21
|
+
for (const part of result) text += typeof part === "string" ? part : virtualNodeToText(part);
|
|
22
|
+
return text;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/VueI18n.ts
|
|
26
|
+
/**
|
|
27
|
+
* Vue-specific wrapper around the core I18n using composition
|
|
28
|
+
* Provides Vue reactivity integration and plugin installation
|
|
29
|
+
*/
|
|
30
|
+
var VueI18n = class {
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this._unsubscribers = [];
|
|
33
|
+
this._localeQueue = Promise.resolve();
|
|
34
|
+
this._isLocaleQueueIdle = true;
|
|
35
|
+
this._isDestroyed = false;
|
|
36
|
+
this._installedApps = /* @__PURE__ */ new WeakSet();
|
|
37
|
+
const initialLocale = options.ssrLocale ?? options.locale;
|
|
38
|
+
this._core = new I18n({
|
|
39
|
+
...options,
|
|
40
|
+
locale: initialLocale
|
|
41
|
+
});
|
|
42
|
+
this._locale = shallowRef(initialLocale);
|
|
43
|
+
this._requestedLocale = initialLocale;
|
|
44
|
+
this._isLoading = shallowRef(this._core.isLoading);
|
|
45
|
+
this._isInitializing = shallowRef(this._core.isInitializing);
|
|
46
|
+
this._cacheRevision = shallowRef(this._core.translationCache.getRevision());
|
|
47
|
+
this._configRevision = shallowRef(0);
|
|
48
|
+
const syncCache = () => {
|
|
49
|
+
this._cacheRevision.value = this._core.translationCache.getRevision();
|
|
50
|
+
};
|
|
51
|
+
this._unsubscribers.push(this._core.on("localeChanged", ({ to }) => {
|
|
52
|
+
this._locale.value = to;
|
|
53
|
+
this._requestedLocale = to;
|
|
54
|
+
}), this._core.on("namespaceLoaded", syncCache), this._core.on("loadingStateChanged", ({ isLoading, isInitializing }) => {
|
|
55
|
+
this._isLoading.value = isLoading;
|
|
56
|
+
this._isInitializing.value = isInitializing;
|
|
57
|
+
}), this._core.on("initialized", () => {
|
|
58
|
+
this._locale.value = this._core.locale;
|
|
59
|
+
syncCache();
|
|
60
|
+
this._isLoading.value = this._core.isLoading;
|
|
61
|
+
this._isInitializing.value = this._core.isInitializing;
|
|
62
|
+
}), this._core.on("translationsCleared", syncCache), this._core.on("defaultNamespaceChanged", () => {
|
|
63
|
+
syncCache();
|
|
64
|
+
this._configRevision.value++;
|
|
65
|
+
}), this._core.on("configChanged", () => {
|
|
66
|
+
this._configRevision.value++;
|
|
67
|
+
}));
|
|
68
|
+
const core = this._core;
|
|
69
|
+
this.addTranslations = core.addTranslations.bind(core);
|
|
70
|
+
this.addActiveNamespace = core.addActiveNamespace.bind(core);
|
|
71
|
+
this.clearTranslations = core.clearTranslations.bind(core);
|
|
72
|
+
this.reloadTranslations = core.reloadTranslations.bind(core);
|
|
73
|
+
this.registerLoader = core.registerLoader.bind(core);
|
|
74
|
+
this.registerPostProcessor = core.registerPostProcessor.bind(core);
|
|
75
|
+
this.onMissingKey = core.onMissingKey.bind(core);
|
|
76
|
+
this.onLoadError = core.onLoadError.bind(core);
|
|
77
|
+
this.on = core.on.bind(core);
|
|
78
|
+
this.setFallbackLocale = core.setFallbackLocale.bind(core);
|
|
79
|
+
this.reportError = core.reportError.bind(core);
|
|
80
|
+
this.formatNumber = core.formatNumber.bind(core);
|
|
81
|
+
this.formatDate = core.formatDate.bind(core);
|
|
82
|
+
this.formatCurrency = core.formatCurrency.bind(core);
|
|
83
|
+
this.formatRelativeTime = core.formatRelativeTime.bind(core);
|
|
84
|
+
this.registerLocaleDetector = core.registerLocaleDetector.bind(core);
|
|
85
|
+
this.t = this.t.bind(this);
|
|
86
|
+
this.tRaw = this.tRaw.bind(this);
|
|
87
|
+
this.setLocale = this.setLocale.bind(this);
|
|
88
|
+
this.destroy = this.destroy.bind(this);
|
|
89
|
+
this.hasTranslation = this.hasTranslation.bind(this);
|
|
90
|
+
this.hasLocale = this.hasLocale.bind(this);
|
|
91
|
+
this.hasTranslationNow = this.hasTranslationNow.bind(this);
|
|
92
|
+
this.hasLocaleNow = this.hasLocaleNow.bind(this);
|
|
93
|
+
}
|
|
94
|
+
get locale() {
|
|
95
|
+
if (!this._localeComputed) this._localeComputed = computed({
|
|
96
|
+
get: () => this._locale.value,
|
|
97
|
+
set: (newLocale) => {
|
|
98
|
+
if (this._requestedLocale !== newLocale) this.setLocale(newLocale).catch((error) => {
|
|
99
|
+
this._core.reportError(error, { source: "setLocale" });
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return this._localeComputed;
|
|
104
|
+
}
|
|
105
|
+
set locale(value) {
|
|
106
|
+
this.setLocale(value).catch((error) => {
|
|
107
|
+
this._core.reportError(error, { source: "setLocale" });
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/** Text direction for the current locale, as a reactive computed ref */
|
|
111
|
+
get dir() {
|
|
112
|
+
if (!this._dirComputed) this._dirComputed = computed(() => {
|
|
113
|
+
this._locale.value;
|
|
114
|
+
return this._core.dir;
|
|
115
|
+
});
|
|
116
|
+
return this._dirComputed;
|
|
117
|
+
}
|
|
118
|
+
get loadedLocales() {
|
|
119
|
+
if (!this._loadedLocalesComputed) this._loadedLocalesComputed = computed(() => {
|
|
120
|
+
this._cacheRevision.value;
|
|
121
|
+
return this._core.getLoadedLocales();
|
|
122
|
+
});
|
|
123
|
+
return this._loadedLocalesComputed;
|
|
124
|
+
}
|
|
125
|
+
get activeNamespaces() {
|
|
126
|
+
if (!this._activeNamespacesComputed) this._activeNamespacesComputed = computed(() => {
|
|
127
|
+
this._cacheRevision.value;
|
|
128
|
+
this._configRevision.value;
|
|
129
|
+
return this._core.getActiveNamespaces();
|
|
130
|
+
});
|
|
131
|
+
return this._activeNamespacesComputed;
|
|
132
|
+
}
|
|
133
|
+
/** Current default namespace as a reactive ComputedRef */
|
|
134
|
+
get defaultNamespace() {
|
|
135
|
+
if (!this._defaultNamespaceComputed) this._defaultNamespaceComputed = computed(() => {
|
|
136
|
+
this._cacheRevision.value;
|
|
137
|
+
this._configRevision.value;
|
|
138
|
+
return this._core.getDefaultNamespace();
|
|
139
|
+
});
|
|
140
|
+
return this._defaultNamespaceComputed;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Reactive check for translation existence. Returns a ComputedRef that
|
|
144
|
+
* re-evaluates when locale, cache, or config changes. Call inside component setup
|
|
145
|
+
* (or an effectScope) — the underlying `computed()` registers with the
|
|
146
|
+
* active scope and disposes automatically.
|
|
147
|
+
*/
|
|
148
|
+
hasTranslation(key, opts) {
|
|
149
|
+
return computed(() => {
|
|
150
|
+
this._locale.value;
|
|
151
|
+
this._cacheRevision.value;
|
|
152
|
+
this._configRevision.value;
|
|
153
|
+
return this._core.hasTranslation(key, opts?.locale, opts?.namespace, opts?.checkFallbacks);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Reactive check for locale availability. Returns a ComputedRef that
|
|
158
|
+
* re-evaluates when the translation cache changes.
|
|
159
|
+
*/
|
|
160
|
+
hasLocale(locale, namespace) {
|
|
161
|
+
return computed(() => {
|
|
162
|
+
this._cacheRevision.value;
|
|
163
|
+
return this._core.hasLocale(locale, namespace);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/** Imperative (non-reactive) translation-existence check — plain boolean, for use outside a reactive scope. */
|
|
167
|
+
hasTranslationNow(key, opts) {
|
|
168
|
+
return this._core.hasTranslation(key, opts?.locale, opts?.namespace, opts?.checkFallbacks);
|
|
169
|
+
}
|
|
170
|
+
/** Imperative (non-reactive) locale-availability check — plain boolean, for use outside a reactive scope. */
|
|
171
|
+
hasLocaleNow(locale, namespace) {
|
|
172
|
+
return this._core.hasLocale(locale, namespace);
|
|
173
|
+
}
|
|
174
|
+
async setLocale(locale) {
|
|
175
|
+
const target = locale;
|
|
176
|
+
this._requestedLocale = target;
|
|
177
|
+
const run = async () => {
|
|
178
|
+
if (this._core.locale !== target) await this._core.setLocaleAsync(target);
|
|
179
|
+
};
|
|
180
|
+
const task = this._isLocaleQueueIdle ? run() : this._localeQueue.then(run, run);
|
|
181
|
+
this._isLocaleQueueIdle = false;
|
|
182
|
+
const tail = task.catch(() => {});
|
|
183
|
+
this._localeQueue = tail;
|
|
184
|
+
tail.finally(() => {
|
|
185
|
+
if (this._localeQueue === tail) this._isLocaleQueueIdle = true;
|
|
186
|
+
});
|
|
187
|
+
try {
|
|
188
|
+
await task;
|
|
189
|
+
} catch (error) {
|
|
190
|
+
if (this._requestedLocale === target) this._requestedLocale = this._core.locale;
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
get translationCache() {
|
|
195
|
+
if (!this._translationCacheComputed) this._translationCacheComputed = computed(() => {
|
|
196
|
+
this._cacheRevision.value;
|
|
197
|
+
return this._core.translationCache.getInternalMap();
|
|
198
|
+
});
|
|
199
|
+
return this._translationCacheComputed;
|
|
200
|
+
}
|
|
201
|
+
get isLoading() {
|
|
202
|
+
return readonly(this._isLoading);
|
|
203
|
+
}
|
|
204
|
+
get isInitializing() {
|
|
205
|
+
return readonly(this._isInitializing);
|
|
206
|
+
}
|
|
207
|
+
tRaw(key, ...params) {
|
|
208
|
+
this._locale.value;
|
|
209
|
+
this._cacheRevision.value;
|
|
210
|
+
this._configRevision.value;
|
|
211
|
+
return this._core.tRaw(key, ...params);
|
|
212
|
+
}
|
|
213
|
+
t(key, ...params) {
|
|
214
|
+
return translationResultToString(this.tRaw(key, ...params));
|
|
215
|
+
}
|
|
216
|
+
async init() {
|
|
217
|
+
await this._core.init();
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
220
|
+
use(plugin, options) {
|
|
221
|
+
this._core.use(plugin, options);
|
|
222
|
+
return this;
|
|
223
|
+
}
|
|
224
|
+
destroy() {
|
|
225
|
+
if (this._isDestroyed) return;
|
|
226
|
+
this._isDestroyed = true;
|
|
227
|
+
this._unsubscribers.slice().reverse().forEach((unsub) => unsub());
|
|
228
|
+
this._unsubscribers.length = 0;
|
|
229
|
+
this._core.destroy().catch((error) => {
|
|
230
|
+
this._core.reportError(error, { source: "plugin-cleanup" });
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Install the i18n plugin into a Vue app.
|
|
235
|
+
*
|
|
236
|
+
* Side effects:
|
|
237
|
+
* - Provides the i18n instance via `I18N_INJECTION_KEY` so `useI18n()` works.
|
|
238
|
+
* - Registers `$t`, `$tRaw`, `$i18n` global properties for Options API + templates.
|
|
239
|
+
* - If the core isn't initialized yet, kicks off `init()` asynchronously (fire-and-forget).
|
|
240
|
+
*
|
|
241
|
+
* SSR note: on server-side rendering, call `await i18n.init()` BEFORE
|
|
242
|
+
* `renderToString(app)`. The fire-and-forget `init()` here is for client-side
|
|
243
|
+
* convenience only — on the server, rendering races against translation loading
|
|
244
|
+
* and you may serialize stale/empty caches.
|
|
245
|
+
*/
|
|
246
|
+
install(app) {
|
|
247
|
+
if (this._installedApps.has(app)) return;
|
|
248
|
+
this._installedApps.add(app);
|
|
249
|
+
if (!this._core.isInitialized && !this._core.isInitializing) this.init().catch((error) => {
|
|
250
|
+
this._core.reportError(error instanceof Error ? error : new Error(String(error)), { source: "init" });
|
|
251
|
+
});
|
|
252
|
+
app.provide(I18N_INJECTION_KEY, this);
|
|
253
|
+
app.config.globalProperties.$i18n = this;
|
|
254
|
+
app.config.globalProperties.$t = this.t;
|
|
255
|
+
app.config.globalProperties.$tRaw = this.tRaw;
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
function createI18n(options) {
|
|
259
|
+
return new VueI18n(options);
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/composables/useI18n.ts
|
|
263
|
+
/** Keys copied from the i18n instance as direct references */
|
|
264
|
+
var PASSTHROUGH_KEYS = [
|
|
265
|
+
"locale",
|
|
266
|
+
"setLocale",
|
|
267
|
+
"translationCache",
|
|
268
|
+
"isLoading",
|
|
269
|
+
"isInitializing",
|
|
270
|
+
"addTranslations",
|
|
271
|
+
"addActiveNamespace",
|
|
272
|
+
"setFallbackLocale",
|
|
273
|
+
"onMissingKey",
|
|
274
|
+
"onLoadError",
|
|
275
|
+
"clearTranslations",
|
|
276
|
+
"reloadTranslations",
|
|
277
|
+
"hasLocale",
|
|
278
|
+
"hasTranslation",
|
|
279
|
+
"hasLocaleNow",
|
|
280
|
+
"hasTranslationNow",
|
|
281
|
+
"loadedLocales",
|
|
282
|
+
"activeNamespaces",
|
|
283
|
+
"defaultNamespace",
|
|
284
|
+
"on",
|
|
285
|
+
"reportError",
|
|
286
|
+
"formatNumber",
|
|
287
|
+
"formatDate",
|
|
288
|
+
"formatCurrency",
|
|
289
|
+
"formatRelativeTime",
|
|
290
|
+
"dir",
|
|
291
|
+
"destroy"
|
|
292
|
+
];
|
|
293
|
+
/**
|
|
294
|
+
* Vue composable to access the i18n instance.
|
|
295
|
+
* Must be called within a component that has access to the i18n plugin
|
|
296
|
+
* (i.e. after `app.use(i18n)`).
|
|
297
|
+
*
|
|
298
|
+
* @param ns - Optional namespace to scope the returned `t` / `tRaw` functions to.
|
|
299
|
+
* When provided, key lookups default to this namespace instead of the
|
|
300
|
+
* configured `defaultNs`. Other returned methods (e.g. `hasTranslation`,
|
|
301
|
+
* `addActiveNamespace`) are NOT scoped — they accept explicit `namespace`
|
|
302
|
+
* arguments where applicable.
|
|
303
|
+
* @returns Object with translation function, reactive state, and i18n methods
|
|
304
|
+
*/
|
|
305
|
+
function useI18n(ns) {
|
|
306
|
+
const i18n = inject(I18N_INJECTION_KEY);
|
|
307
|
+
if (!i18n) throw new Error("[i18n] useI18n must be used within a Vue app with i18n plugin installed. Make sure you called app.use(i18n) before using this composable.");
|
|
308
|
+
const tRaw = createBoundTranslation(i18n, ns);
|
|
309
|
+
const t = ((key, params) => translationResultToString(tRaw(key, params)));
|
|
310
|
+
const result = {
|
|
311
|
+
t,
|
|
312
|
+
tRaw
|
|
313
|
+
};
|
|
314
|
+
for (const k of PASSTHROUGH_KEYS) result[k] = i18n[k];
|
|
315
|
+
return result;
|
|
316
|
+
}
|
|
317
|
+
//#endregion
|
|
318
|
+
//#region src/components/T.ts
|
|
319
|
+
/**
|
|
320
|
+
* Marker prefix for Vue component/slot handling in tag interpolation
|
|
321
|
+
* Used to identify VirtualNodes that should be converted to Vue-specific elements
|
|
322
|
+
*/
|
|
323
|
+
var MARKER_PREFIX = "__vue_handler_";
|
|
324
|
+
var MARKER_SUFFIX = "__";
|
|
325
|
+
/**
|
|
326
|
+
* Convert TranslationResult children to format suitable for slot/component
|
|
327
|
+
*/
|
|
328
|
+
function childrenToArray(children) {
|
|
329
|
+
if (typeof children === "string") return children ? [children] : [];
|
|
330
|
+
return children;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Translation component for Vue
|
|
334
|
+
* Renders translated content with support for slots and components prop as tag handlers
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* ```vue
|
|
338
|
+
* <!-- Simple usage -->
|
|
339
|
+
* <T i18nKey="greeting" />
|
|
340
|
+
*
|
|
341
|
+
* <!-- With parameters -->
|
|
342
|
+
* <T i18nKey="welcome" :params="{ name: 'John' }" />
|
|
343
|
+
*
|
|
344
|
+
* <!-- With tag interpolation using slots -->
|
|
345
|
+
* <T i18nKey="welcome_link">
|
|
346
|
+
* <template #link="{ children }">
|
|
347
|
+
* <a href="/help">{{ children }}</a>
|
|
348
|
+
* </template>
|
|
349
|
+
* </T>
|
|
350
|
+
*
|
|
351
|
+
* <!-- With tag interpolation using components prop -->
|
|
352
|
+
* <T
|
|
353
|
+
* i18nKey="welcome_link"
|
|
354
|
+
* :components="{
|
|
355
|
+
* link: { component: 'a', props: { href: '/help' } },
|
|
356
|
+
* bold: 'strong'
|
|
357
|
+
* }"
|
|
358
|
+
* />
|
|
359
|
+
*
|
|
360
|
+
* <!-- With specific namespace -->
|
|
361
|
+
* <T i18nKey="button.submit" ns="forms" />
|
|
362
|
+
*
|
|
363
|
+
* <!-- With specific locale -->
|
|
364
|
+
* <T i18nKey="greeting" locale="fr" />
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
var T = defineComponent({
|
|
368
|
+
name: "T",
|
|
369
|
+
props: {
|
|
370
|
+
/**
|
|
371
|
+
* Translation key to look up
|
|
372
|
+
*/
|
|
373
|
+
i18nKey: {
|
|
374
|
+
type: String,
|
|
375
|
+
required: true
|
|
376
|
+
},
|
|
377
|
+
/**
|
|
378
|
+
* Parameters for interpolation
|
|
379
|
+
* These will be merged with slot content
|
|
380
|
+
*/
|
|
381
|
+
params: {
|
|
382
|
+
type: Object,
|
|
383
|
+
default: () => ({})
|
|
384
|
+
},
|
|
385
|
+
/**
|
|
386
|
+
* Namespace to use (optional)
|
|
387
|
+
* If not specified, uses the default namespace
|
|
388
|
+
*/
|
|
389
|
+
ns: {
|
|
390
|
+
type: String,
|
|
391
|
+
default: void 0
|
|
392
|
+
},
|
|
393
|
+
/**
|
|
394
|
+
* Specific locale to use (optional)
|
|
395
|
+
* If not specified, uses the current locale
|
|
396
|
+
*/
|
|
397
|
+
locale: {
|
|
398
|
+
type: String,
|
|
399
|
+
default: void 0
|
|
400
|
+
},
|
|
401
|
+
/**
|
|
402
|
+
* Fallback text to display if translation is missing (optional)
|
|
403
|
+
* If not specified, returns the key itself
|
|
404
|
+
*/
|
|
405
|
+
fallback: {
|
|
406
|
+
type: String,
|
|
407
|
+
default: void 0
|
|
408
|
+
},
|
|
409
|
+
/**
|
|
410
|
+
* Skip post-processing (optional)
|
|
411
|
+
* When true, prevents post-processors like IncontextEditor from adding invisible marker characters
|
|
412
|
+
*/
|
|
413
|
+
raw: {
|
|
414
|
+
type: Boolean,
|
|
415
|
+
default: void 0
|
|
416
|
+
},
|
|
417
|
+
/**
|
|
418
|
+
* Components map for tag interpolation (optional)
|
|
419
|
+
* Maps tag names to their handlers (string tag name, component, or config object)
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* {
|
|
423
|
+
* bold: 'strong', // HTML tag name
|
|
424
|
+
* link: { component: 'a', props: { href: '#' } }, // With props
|
|
425
|
+
* btn: MyButton // Vue component
|
|
426
|
+
* }
|
|
427
|
+
*/
|
|
428
|
+
components: {
|
|
429
|
+
type: Object,
|
|
430
|
+
default: void 0
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
setup(props, { slots }) {
|
|
434
|
+
const i18n = inject(I18N_INJECTION_KEY);
|
|
435
|
+
if (!i18n) throw new Error("[i18n] <T> component must be used within a Vue app with i18n plugin installed");
|
|
436
|
+
return () => {
|
|
437
|
+
const key = props.i18nKey;
|
|
438
|
+
const vueHandlers = /* @__PURE__ */ new Map();
|
|
439
|
+
const tagHandlers = {};
|
|
440
|
+
const registerVueHandler = (tagName, vueHandler) => {
|
|
441
|
+
vueHandlers.set(tagName, (children) => {
|
|
442
|
+
try {
|
|
443
|
+
return vueHandler(children);
|
|
444
|
+
} catch (error) {
|
|
445
|
+
i18n.reportError(error, {
|
|
446
|
+
source: "translation",
|
|
447
|
+
tagName
|
|
448
|
+
});
|
|
449
|
+
return h("span", {}, children);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
tagHandlers[tagName] = ({ children }) => createElement(`${MARKER_PREFIX}${tagName}${MARKER_SUFFIX}`, {}, childrenToArray(children));
|
|
453
|
+
};
|
|
454
|
+
const flattenChildren = (children) => children.length === 1 && typeof children[0] === "string" ? children[0] : children;
|
|
455
|
+
if (props.components) for (const [tagName, handler] of Object.entries(props.components)) if (typeof handler === "string") tagHandlers[tagName] = ({ children }) => createElement(handler, {}, childrenToArray(children));
|
|
456
|
+
else if (typeof handler === "object" && handler !== null && "component" in handler) {
|
|
457
|
+
const component = handler.component;
|
|
458
|
+
const componentProps = handler.props || {};
|
|
459
|
+
if (typeof component === "string") tagHandlers[tagName] = ({ children }) => createElement(component, componentProps, childrenToArray(children));
|
|
460
|
+
else registerVueHandler(tagName, (children) => h(component, componentProps, { default: () => flattenChildren(children) }));
|
|
461
|
+
} else registerVueHandler(tagName, (children) => h(handler, {}, { default: () => flattenChildren(children) }));
|
|
462
|
+
for (const [slotName, slot] of Object.entries(slots)) if (slot && !(slotName in tagHandlers)) registerVueHandler(slotName, (children) => {
|
|
463
|
+
const rendered = slot({ children: flattenChildren(children) });
|
|
464
|
+
const nodes = Array.isArray(rendered) ? rendered : [rendered];
|
|
465
|
+
if (nodes.length <= 1) return nodes.length === 0 ? h(Fragment, {}, []) : nodes[0];
|
|
466
|
+
return h(Fragment, {}, nodes);
|
|
467
|
+
});
|
|
468
|
+
const translationParams = {
|
|
469
|
+
...props.params,
|
|
470
|
+
...tagHandlers
|
|
471
|
+
};
|
|
472
|
+
if (props.ns !== void 0) translationParams.ns = props.ns;
|
|
473
|
+
if (props.locale !== void 0) translationParams.locale = props.locale;
|
|
474
|
+
if (props.fallback !== void 0) translationParams.fallback = props.fallback;
|
|
475
|
+
if (props.raw !== void 0) translationParams.raw = props.raw;
|
|
476
|
+
const content = i18n.tRaw(key, translationParams);
|
|
477
|
+
if (typeof content === "string") return content;
|
|
478
|
+
const convertChildren = (childResult) => {
|
|
479
|
+
if (typeof childResult === "string") return childResult ? [childResult] : [];
|
|
480
|
+
return childResult.map((child) => typeof child === "string" ? child : convertNode(child));
|
|
481
|
+
};
|
|
482
|
+
const convertNode = (node) => {
|
|
483
|
+
if (node.type === "text") return node.text;
|
|
484
|
+
if (node.type === "fragment") return h(Fragment, { key: node.key }, convertChildren(node.children));
|
|
485
|
+
const tag = node.tag;
|
|
486
|
+
const convertedChildren = convertChildren(node.children);
|
|
487
|
+
if (tag.startsWith(MARKER_PREFIX) && tag.endsWith(MARKER_SUFFIX)) {
|
|
488
|
+
const handlerName = tag.slice(14, -2);
|
|
489
|
+
const handler = vueHandlers.get(handlerName);
|
|
490
|
+
if (handler) try {
|
|
491
|
+
return handler(convertedChildren);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
i18n.reportError(error, {
|
|
494
|
+
source: "translation",
|
|
495
|
+
tagName: handlerName
|
|
496
|
+
});
|
|
497
|
+
return h("span", {}, convertedChildren);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return h(tag, node.props, convertedChildren);
|
|
501
|
+
};
|
|
502
|
+
return content.map((item) => typeof item === "string" ? item : convertNode(item));
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
//#endregion
|
|
507
|
+
export { I18N_INJECTION_KEY, T, VueI18n, createI18n, useI18n };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from '@comvi/core';
|
|
2
2
|
export { VueI18n, createI18n } from './VueI18n';
|
|
3
3
|
export { useI18n } from './composables/useI18n';
|
|
4
|
+
export type { UseI18nReturn } from './composables/useI18n';
|
|
4
5
|
export { T } from './components/T';
|
|
5
6
|
export { I18N_INJECTION_KEY } from './keys';
|
|
6
7
|
export type { VueI18n as I18nInstance, VueI18nOptions } from './VueI18n';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAG5B,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,gBAAgB,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAG5C,YAAY,EAAE,OAAO,IAAI,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAG5B,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,CAAC,EAAE,MAAM,gBAAgB,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAG5C,YAAY,EAAE,OAAO,IAAI,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comvi/vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vue 3 integration for Comvi — composables, components, and type-safe translations",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Comvi <hello@comvi.io> (https://comvi.io)",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/comvi-io/comvi-js.git",
|
|
10
|
+
"url": "git+https://github.com/comvi-io/comvi-js.git",
|
|
11
11
|
"directory": "packages/vue"
|
|
12
12
|
},
|
|
13
13
|
"homepage": "https://comvi.io",
|
|
@@ -33,19 +33,20 @@
|
|
|
33
33
|
"files": [
|
|
34
34
|
"dist"
|
|
35
35
|
],
|
|
36
|
-
"main": "./dist/comvi-vue.cjs",
|
|
37
36
|
"module": "./dist/comvi-vue.js",
|
|
38
37
|
"types": "./dist/index.d.ts",
|
|
39
38
|
"exports": {
|
|
40
39
|
".": {
|
|
41
40
|
"types": "./dist/index.d.ts",
|
|
42
|
-
"
|
|
43
|
-
"require": "./dist/comvi-vue.cjs"
|
|
41
|
+
"default": "./dist/comvi-vue.js"
|
|
44
42
|
}
|
|
45
43
|
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
},
|
|
46
47
|
"sideEffects": false,
|
|
47
48
|
"dependencies": {
|
|
48
|
-
"@comvi/core": "0.
|
|
49
|
+
"@comvi/core": "0.3.0"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
51
52
|
"vue": "^3.0.0"
|
package/dist/comvi-vue.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@comvi/core`),t=require(`vue`);var n=Symbol(`i18n`);function r(e){if(e.type===`text`)return e.text;let t=``;for(let n of e.children)t+=typeof n==`string`?n:r(n);return t}function i(e){if(typeof e==`string`)return e;let t=``;for(let n of e)t+=typeof n==`string`?n:r(n);return t}var a=[`addTranslations`,`addActiveNamespace`,`clearTranslations`,`reloadTranslations`,`registerLoader`,`registerPostProcessor`,`onMissingKey`,`onLoadError`,`on`,`hasLocale`,`hasTranslation`,`setFallbackLocale`,`getDefaultNamespace`,`reportError`,`getActiveNamespaces`,`formatNumber`,`formatDate`,`formatCurrency`,`formatRelativeTime`],o=class{constructor(n){this._unsubscribers=[],this._localeQueue=Promise.resolve(),this._isLocaleQueueIdle=!0,this._isDestroyed=!1,this._installedApps=new WeakSet;let r=n.ssrLanguage??n.locale??n.language;this._core=new e.I18n({...n,locale:r}),this._locale=(0,t.shallowRef)(r),this._requestedLocale=r,this._isLoading=(0,t.shallowRef)(this._core.isLoading),this._isInitializing=(0,t.shallowRef)(this._core.isInitializing),this._cacheRevision=(0,t.shallowRef)(this._core.translationCache.getRevision()),this._translationCacheRef=(0,t.shallowRef)(this._core.translationCache.getInternalMap());let i=()=>{this._cacheRevision.value=this._core.translationCache.getRevision(),this._translationCacheRef.value=this._core.translationCache.getInternalMap(),(0,t.triggerRef)(this._translationCacheRef)};this._unsubscribers.push(this._core.on(`localeChanged`,({to:e})=>{this._locale.value=e,this._requestedLocale=e}),this._core.on(`namespaceLoaded`,i),this._core.on(`loadingStateChanged`,({isLoading:e,isInitializing:t})=>{this._isLoading.value=e,this._isInitializing.value=t}),this._core.on(`initialized`,()=>{this._locale.value=this._core.locale,i(),this._isLoading.value=this._core.isLoading,this._isInitializing.value=this._core.isInitializing}),this._core.on(`translationsCleared`,i));let o=this._core;for(let e of a)this[e]=(...t)=>o[e](...t);this.registerLocaleDetector=e=>o.registerLocaleDetector(e),this.getLoadedLocales=()=>o.getLoadedLocales(),this.t=this.t.bind(this),this.tRaw=this.tRaw.bind(this),this.setLocale=this.setLocale.bind(this),this.destroy=this.destroy.bind(this)}get locale(){return this._localeComputed||(this._localeComputed=(0,t.computed)({get:()=>this._locale.value,set:e=>{this._requestedLocale!==e&&this.setLocale(e).catch(e=>{})}})),this._localeComputed}set locale(e){this.setLocale(e).catch(e=>{})}get dir(){return this._dirComputed||(this._dirComputed=(0,t.computed)(()=>this._core.dir)),this._dirComputed}async setLocale(e){let t=e;this._requestedLocale=t;let n=async()=>{this._core.locale!==t&&await this._core.setLocaleAsync(t)},r=this._isLocaleQueueIdle?n():this._localeQueue.then(n,n);this._isLocaleQueueIdle=!1;let i=r.catch(()=>{});this._localeQueue=i,i.finally(()=>{this._localeQueue===i&&(this._isLocaleQueueIdle=!0)});try{await r}catch(e){throw this._requestedLocale===t&&(this._requestedLocale=this._core.locale),e}}get translationCache(){return this._translationCacheRef}get isLoading(){return(0,t.readonly)(this._isLoading)}get isInitializing(){return(0,t.readonly)(this._isInitializing)}tRaw(e,...t){return this._core.tRaw(e,...t)}t(e,...t){return i(this.tRaw(e,...t))}async init(){return await this._core.init(),this}use(e,t){return this._core.use(e,t),this}destroy(){this._isDestroyed||(this._isDestroyed=!0,this._unsubscribers.reverse().forEach(e=>e()),this._unsubscribers.length=0,this._core.destroy().catch(e=>{this._core.reportError(e,{source:`plugin-cleanup`})}))}install(e){this._installedApps.has(e)||(this._installedApps.add(e),!this._core.isInitialized&&!this._core.isInitializing&&this.init().catch(e=>{this._core.reportError(e instanceof Error?e:Error(String(e)),{source:`init`})}),e.provide(n,this),e.config.globalProperties.$i18n=this,e.config.globalProperties.$t=this.t,e.config.globalProperties.$tRaw=this.tRaw)}};function s(e){return new o(e)}var c=[`locale`,`setLocale`,`translationCache`,`isLoading`,`isInitializing`,`addTranslations`,`addActiveNamespace`,`setFallbackLocale`,`onMissingKey`,`onLoadError`,`clearTranslations`,`reloadTranslations`,`hasLocale`,`hasTranslation`,`getLoadedLocales`,`getActiveNamespaces`,`getDefaultNamespace`,`on`,`reportError`,`formatNumber`,`formatDate`,`formatCurrency`,`formatRelativeTime`,`dir`,`destroy`];function l(r){let a=(0,t.inject)(n);if(!a)throw Error(`[i18n] useI18n must be used within a Vue app with i18n plugin installed. Make sure you called app.use(i18n) before using this composable.`);let o=(0,e.createBoundTranslation)(a,r),s={t:((e,t)=>i(o(e,t))),tRaw:o};for(let e of c)s[e]=a[e];return s}var u=`__vue_handler_`,d=`__`;function f(e){return typeof e==`string`?e?[e]:[]:e}var p=(0,t.defineComponent)({name:`T`,props:{i18nKey:{type:String,required:!0},params:{type:Object,default:()=>({})},ns:{type:String,default:void 0},locale:{type:String,default:void 0},fallback:{type:String,default:void 0},raw:{type:Boolean,default:void 0},components:{type:Object,default:void 0}},setup(r,{slots:i}){let a=(0,t.inject)(n);if(!a)throw Error(`[i18n] <T> component must be used within a Vue app with i18n plugin installed`);return()=>{let n=r.i18nKey,o=new Map,s={},c=(n,r)=>{o.set(n,e=>{try{return r(e)}catch(r){return a.reportError(r,{source:`translation`,tagName:n}),(0,t.h)(`span`,{},e)}}),s[n]=({children:t})=>(0,e.createElement)(`${u}${n}${d}`,{},f(t))},l=e=>e.length===1&&typeof e[0]==`string`?e[0]:e;if(r.components)for(let[n,i]of Object.entries(r.components))if(typeof i==`string`)s[n]=({children:t})=>(0,e.createElement)(i,{},f(t));else if(typeof i==`object`&&i&&`component`in i){let r=i.component,a=i.props||{};typeof r==`string`?s[n]=({children:t})=>(0,e.createElement)(r,a,f(t)):c(n,e=>(0,t.h)(r,a,{default:()=>l(e)}))}else c(n,e=>(0,t.h)(i,{},{default:()=>l(e)}));for(let[e,n]of Object.entries(i))n&&!(e in s)&&c(e,e=>{let r=n({children:l(e)}),i=Array.isArray(r)?r:[r];return i.length<=1?i.length===0?(0,t.h)(t.Fragment,{},[]):i[0]:(0,t.h)(t.Fragment,{},i)});let p={...r.params,...s};r.ns!==void 0&&(p.ns=r.ns),r.locale!==void 0&&(p.locale=r.locale),r.fallback!==void 0&&(p.fallback=r.fallback),r.raw!==void 0&&(p.raw=r.raw);let m=a.tRaw(n,p);if(typeof m==`string`)return m;let h=e=>typeof e==`string`?e?[e]:[]:e.map(e=>typeof e==`string`?e:g(e)),g=e=>{if(e.type===`text`)return e.text;if(e.type===`fragment`)return(0,t.h)(t.Fragment,{key:e.key},h(e.children));let n=e.tag,r=h(e.children);if(n.startsWith(u)&&n.endsWith(d)){let e=n.slice(14,-2),i=o.get(e);if(i)try{return i(r)}catch(n){return a.reportError(n,{source:`translation`,tagName:e}),(0,t.h)(`span`,{},r)}}return(0,t.h)(n,e.props,r)};return m.map(e=>typeof e==`string`?e:g(e))}}});exports.I18N_INJECTION_KEY=n,exports.T=p,exports.VueI18n=o,exports.createI18n=s,exports.useI18n=l,Object.keys(e).forEach(function(t){t!==`default`&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})});
|