@zachhandley/ez-i18n 0.2.1 → 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.
@@ -1,78 +0,0 @@
1
- import { useStore } from '@nanostores/react';
2
- import { effectiveLocale, translations, setLocale } from './store';
3
- import type { TranslateFunction } from '../types';
4
-
5
- /**
6
- * Get nested value from object using dot notation
7
- */
8
- function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
9
- const keys = path.split('.');
10
- let value: unknown = obj;
11
-
12
- for (const key of keys) {
13
- if (value == null || typeof value !== 'object') {
14
- return undefined;
15
- }
16
- value = (value as Record<string, unknown>)[key];
17
- }
18
-
19
- return value;
20
- }
21
-
22
- /**
23
- * Interpolate params into string
24
- */
25
- function interpolate(
26
- str: string,
27
- params?: Record<string, string | number>
28
- ): string {
29
- if (!params) return str;
30
- return str.replace(/\{(\w+)\}/g, (match, key) => {
31
- return key in params ? String(params[key]) : match;
32
- });
33
- }
34
-
35
- /**
36
- * React hook for i18n
37
- *
38
- * @example
39
- * import { useI18n } from '@zachhandley/ez-i18n/react';
40
- *
41
- * function MyComponent() {
42
- * const { t, locale, setLocale } = useI18n();
43
- *
44
- * return (
45
- * <div>
46
- * <h1>{t('common.welcome')}</h1>
47
- * <p>{t('greeting', { name: 'World' })}</p>
48
- * <button onClick={() => setLocale('es')}>Español</button>
49
- * </div>
50
- * );
51
- * }
52
- */
53
- export function useI18n() {
54
- const locale = useStore(effectiveLocale);
55
- const trans = useStore(translations);
56
-
57
- const t: TranslateFunction = (
58
- key: string,
59
- params?: Record<string, string | number>
60
- ): string => {
61
- const value = getNestedValue(trans, key);
62
-
63
- if (typeof value !== 'string') {
64
- if (import.meta.env?.DEV) {
65
- console.warn('[ez-i18n] Missing translation:', key);
66
- }
67
- return key;
68
- }
69
-
70
- return interpolate(value, params);
71
- };
72
-
73
- return {
74
- t,
75
- locale,
76
- setLocale,
77
- };
78
- }
@@ -1,137 +0,0 @@
1
- import type { App, Plugin, ComputedRef } from 'vue';
2
- import { computed } from 'vue';
3
- import { useStore } from '@nanostores/vue';
4
- import { effectiveLocale, translations, setLocale } from './store';
5
- import type { TranslateFunction } from '../types';
6
-
7
- /**
8
- * Get nested value from object using dot notation
9
- */
10
- function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
11
- const keys = path.split('.');
12
- let value: unknown = obj;
13
-
14
- for (const key of keys) {
15
- if (value == null || typeof value !== 'object') {
16
- return undefined;
17
- }
18
- value = (value as Record<string, unknown>)[key];
19
- }
20
-
21
- return value;
22
- }
23
-
24
- /**
25
- * Interpolate params into string
26
- */
27
- function interpolate(
28
- str: string,
29
- params?: Record<string, string | number>
30
- ): string {
31
- if (!params) return str;
32
- return str.replace(/\{(\w+)\}/g, (match, key) => {
33
- return key in params ? String(params[key]) : match;
34
- });
35
- }
36
-
37
- /**
38
- * Create a translation function bound to a translations object
39
- */
40
- function createTranslateFunction(
41
- translationsRef: ComputedRef<Record<string, unknown>>
42
- ): TranslateFunction {
43
- return (key: string, params?: Record<string, string | number>): string => {
44
- const trans = translationsRef.value;
45
- const value = getNestedValue(trans, key);
46
-
47
- if (typeof value !== 'string') {
48
- if (import.meta.env?.DEV) {
49
- console.warn('[ez-i18n] Missing translation:', key);
50
- }
51
- return key;
52
- }
53
-
54
- return interpolate(value, params);
55
- };
56
- }
57
-
58
- /**
59
- * Vue plugin that provides global $t(), $locale, and $setLocale
60
- *
61
- * @example
62
- * // In _vueEntrypoint.ts or main.ts
63
- * import { ezI18nVue } from '@zachhandley/ez-i18n/vue';
64
- *
65
- * export default (app) => {
66
- * app.use(ezI18nVue);
67
- * };
68
- *
69
- * @example
70
- * // In Vue components
71
- * <template>
72
- * <h1>{{ $t('welcome.title') }}</h1>
73
- * <p>{{ $t('welcome.message', { name: userName }) }}</p>
74
- * <button @click="$setLocale('es')">Español</button>
75
- * </template>
76
- */
77
- export const ezI18nVue: Plugin = {
78
- install(app: App) {
79
- // Get reactive store values
80
- const locale = useStore(effectiveLocale);
81
- const trans = useStore(translations);
82
-
83
- // Create reactive computed for translations
84
- const transComputed = computed(() => trans.value);
85
-
86
- // Create translate function
87
- const t = createTranslateFunction(transComputed);
88
-
89
- // Add global properties
90
- app.config.globalProperties.$t = t;
91
- app.config.globalProperties.$locale = locale;
92
- app.config.globalProperties.$setLocale = setLocale;
93
-
94
- // Also provide for composition API usage
95
- app.provide('ez-i18n', {
96
- t,
97
- locale,
98
- setLocale,
99
- });
100
- },
101
- };
102
-
103
- /**
104
- * Composable for using i18n in Vue components with Composition API
105
- *
106
- * @example
107
- * <script setup>
108
- * import { useI18n } from '@zachhandley/ez-i18n/vue';
109
- *
110
- * const { t, locale, setLocale } = useI18n();
111
- * const greeting = t('welcome.greeting');
112
- * </script>
113
- */
114
- export function useI18n() {
115
- const locale = useStore(effectiveLocale);
116
- const trans = useStore(translations);
117
- const transComputed = computed(() => trans.value);
118
- const t = createTranslateFunction(transComputed);
119
-
120
- return {
121
- t,
122
- locale,
123
- setLocale,
124
- };
125
- }
126
-
127
- // Type augmentation for Vue global properties
128
- declare module 'vue' {
129
- interface ComponentCustomProperties {
130
- $t: TranslateFunction;
131
- /** Current locale (reactive ref from nanostore) */
132
- $locale: Readonly<import('vue').Ref<string>>;
133
- $setLocale: typeof setLocale;
134
- }
135
- }
136
-
137
- export default ezI18nVue;