@maz-ui/translations 4.0.0-beta.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.
@@ -0,0 +1,202 @@
1
+ import * as vue from 'vue';
2
+ import { Ref, App } from 'vue';
3
+
4
+ type DeepKeyOf<T> = T extends object ? {
5
+ [K in keyof T]: K extends string ? T[K] extends object ? `${K}.${DeepKeyOf<T[K]>}` : K : never;
6
+ }[keyof T] : never;
7
+
8
+ type DeepPartial<T> = T extends object ? {
9
+ [P in keyof T]?: DeepPartial<T[P]>;
10
+ } : T;
11
+
12
+ type FlattenObjectKeys<T extends Record<string, any>, Prefix extends string = ''> = {
13
+ [K in keyof T]: T[K] extends Record<string, any> ? FlattenObjectKeys<T[K], `${Prefix}${K extends string ? K : ''}.`> : `${Prefix}${K extends string ? K : ''}`;
14
+ }[keyof T];
15
+
16
+ declare const _default: {
17
+ /**
18
+ * This is the translation for the input phone number component.
19
+ * The keys are:
20
+ * - countrySelect: The translation for the country select.
21
+ * - phoneInput: The translation for the phone input.
22
+ */
23
+ selectCountry: {
24
+ searchPlaceholder: string;
25
+ };
26
+ inputPhoneNumber: {
27
+ /**
28
+ * This is the translation for the country select component.
29
+ * The keys are:
30
+ * - placeholder: The translation for the placeholder text.
31
+ * - error: The translation for the error text.
32
+ * - searchPlaceholder: The translation for the search placeholder text.
33
+ */
34
+ countrySelect: {
35
+ placeholder: string;
36
+ error: string;
37
+ searchPlaceholder: string;
38
+ };
39
+ /**
40
+ * This is the translation for the phone input component.
41
+ * The keys are:
42
+ * - placeholder: The translation for the placeholder text.
43
+ * - example: The translation for the example text.
44
+ */
45
+ phoneInput: {
46
+ placeholder: string;
47
+ example: string;
48
+ };
49
+ };
50
+ /**
51
+ * This is the translation for the dropzone component.
52
+ * The keys are:
53
+ * - dragAndDrop: The translation for the drag and drop text.
54
+ * - selectFile: The translation for the select file button.
55
+ * - divider: The translation for the divider text.
56
+ * - fileMaxCount: The translation for the maximum number of files.
57
+ * - fileMaxSize: The translation for the maximum size of the files.
58
+ * - fileTypes: The translation for the allowed file types.
59
+ */
60
+ dropzone: {
61
+ dragAndDrop: string;
62
+ selectFile: string;
63
+ divider: string;
64
+ fileMaxCount: string;
65
+ fileMaxSize: string;
66
+ fileTypes: string;
67
+ };
68
+ /**
69
+ * This is the translation for the date picker component.
70
+ * The keys are:
71
+ * - shortcuts: The translation for the shortcuts.
72
+ */
73
+ datePicker: {
74
+ shortcuts: {
75
+ lastSevenDays: string;
76
+ lastThirtyDays: string;
77
+ thisWeek: string;
78
+ lastWeek: string;
79
+ thisMonth: string;
80
+ thisYear: string;
81
+ lastYear: string;
82
+ };
83
+ };
84
+ /**
85
+ * This is the translation for the dropdown component.
86
+ * The keys are:
87
+ * - screenReaderDescription: The translation for the screen reader description.
88
+ */
89
+ dropdown: {
90
+ screenReaderDescription: string;
91
+ };
92
+ /**
93
+ * This is the translation for the select component.
94
+ * The keys are:
95
+ * - searchPlaceholder: The translation for the search placeholder text.
96
+ */
97
+ select: {
98
+ searchPlaceholder: string;
99
+ };
100
+ /**
101
+ * This is the translation for the table component.
102
+ * The keys are:
103
+ * - noResults: The translation for the no results text.
104
+ * - actionColumnTitle: The translation for the action column title.
105
+ * - searchByInput: The translation for the search by input.
106
+ * - searchInput: The translation for the search input.
107
+ * - pagination: The translation for the pagination component.
108
+ */
109
+ table: {
110
+ noResults: string;
111
+ actionColumnTitle: string;
112
+ searchByInput: {
113
+ all: string;
114
+ placeholder: string;
115
+ };
116
+ searchInput: {
117
+ placeholder: string;
118
+ };
119
+ pagination: {
120
+ all: string;
121
+ rowsPerPage: string;
122
+ of: string;
123
+ };
124
+ };
125
+ /**
126
+ * This is the translation for the pagination component.
127
+ * The keys are:
128
+ * - navAriaLabel: The aria-label for the navigation (nav) element.
129
+ * - screenReader.firstPage: The translation for the first page button (screen reader).
130
+ * - screenReader.previousPage: The translation for the previous page button (screen reader).
131
+ * - screenReader.page: The translation for the current page button (screen reader).
132
+ * - screenReader.nextPage: The translation for the next page button (screen reader).
133
+ * - screenReader.lastPage: The translation for the last page button (screen reader).
134
+ */
135
+ pagination: {
136
+ navAriaLabel: string;
137
+ screenReader: {
138
+ firstPage: string;
139
+ previousPage: string;
140
+ page: string;
141
+ nextPage: string;
142
+ lastPage: string;
143
+ };
144
+ };
145
+ carousel: {
146
+ ariaLabel: {
147
+ previousButton: string;
148
+ nextButton: string;
149
+ };
150
+ };
151
+ checklist: {
152
+ noResultsFound: string;
153
+ searchInput: {
154
+ placeholder: string;
155
+ };
156
+ };
157
+ };
158
+
159
+ type TranslationKey = NonNullable<DeepKeyOf<MazTranslationsSchema>>;
160
+ interface MazTranslationsOptions {
161
+ locale?: string;
162
+ fallbackLocale?: string;
163
+ preloadFallback?: boolean;
164
+ messages?: Record<string, MazTranslationsSchema | (() => Promise<MazTranslationsSchema>)>;
165
+ }
166
+ interface MazTranslationsInstance {
167
+ locale: Ref<string>;
168
+ t: (key: TranslationKey, variables?: Record<string, any>) => string;
169
+ setLocale: (locale: string) => Promise<void>;
170
+ }
171
+ type MazTranslationsFlattenSchema = Record<FlattenObjectKeys<typeof _default>, string>;
172
+ type MazTranslationsNestedSchema = typeof _default;
173
+ type MazTranslationsSchema = DeepPartial<MazTranslationsFlattenSchema | MazTranslationsNestedSchema>;
174
+
175
+ declare function createMazTranslations(options?: MazTranslationsOptions): Promise<{
176
+ locale: vue.Ref<string, string>;
177
+ t: (key: TranslationKey, variables?: Record<string, any>) => string;
178
+ setLocale: (newLocale: string) => Promise<void>;
179
+ }>;
180
+ declare function useMazTranslations(): Promise<MazTranslationsInstance>;
181
+ declare function setGlobalMazTranslations(instance: MazTranslationsInstance): void;
182
+
183
+ declare const MazTranslations: {
184
+ install(app: App, options?: MazTranslationsOptions): Promise<{
185
+ locale: vue.Ref<string, string>;
186
+ t: (key: TranslationKey, variables?: Record<string, any>) => string;
187
+ setLocale: (newLocale: string) => Promise<void>;
188
+ }>;
189
+ };
190
+ declare module '@vue/runtime-core' {
191
+ interface ComponentCustomProperties {
192
+ /**
193
+ * Maz translations instance
194
+ */
195
+ $mazTranslations: MazTranslationsInstance;
196
+ }
197
+ }
198
+
199
+ declare function useTranslations(): MazTranslationsInstance;
200
+
201
+ export { MazTranslations, createMazTranslations, setGlobalMazTranslations, useMazTranslations, useTranslations };
202
+ export type { MazTranslationsInstance, MazTranslationsOptions, MazTranslationsSchema };
package/dist/index.mjs ADDED
@@ -0,0 +1,184 @@
1
+ import { ref, inject } from 'vue';
2
+
3
+ let globalInstance = null;
4
+ const defaultLocaleLoaders = {
5
+ "en": () => import('./chunks/en.mjs'),
6
+ "fr": () => import('./chunks/fr.mjs'),
7
+ "es": () => import('./chunks/es.mjs'),
8
+ "de": () => import('./chunks/de.mjs'),
9
+ "it": () => import('./chunks/it.mjs'),
10
+ "pt": () => import('./chunks/pt.mjs'),
11
+ "zh-CN": () => import('./chunks/zh-CN.mjs'),
12
+ "ja": () => import('./chunks/ja.mjs')
13
+ };
14
+ function get(obj, path) {
15
+ return path.split(".").reduce((current, key) => current?.[key], obj);
16
+ }
17
+ function set(obj, path, value) {
18
+ const keys = path.split(".");
19
+ const lastKey = keys.pop();
20
+ const target = keys.reduce((current, key) => {
21
+ if (!current[key] || typeof current[key] !== "object") {
22
+ current[key] = {};
23
+ }
24
+ return current[key];
25
+ }, obj);
26
+ target[lastKey] = value;
27
+ }
28
+ function isFlattened(obj) {
29
+ if (!obj || typeof obj !== "object")
30
+ return false;
31
+ return Object.keys(obj).some((key) => key.includes("."));
32
+ }
33
+ function flattenToNested(flatObj) {
34
+ if (!isFlattened(flatObj)) {
35
+ return flatObj;
36
+ }
37
+ const nested = {};
38
+ for (const [key, value] of Object.entries(flatObj)) {
39
+ if (key.includes(".")) {
40
+ set(nested, key, value);
41
+ } else {
42
+ nested[key] = value;
43
+ }
44
+ }
45
+ return nested;
46
+ }
47
+ function merge(target, source) {
48
+ const normalizedSource = flattenToNested(source);
49
+ const normalizedTarget = flattenToNested(target);
50
+ const result = { ...normalizedTarget };
51
+ for (const key in normalizedSource) {
52
+ if (normalizedSource[key] && typeof normalizedSource[key] === "object") {
53
+ result[key] = merge(result[key] || {}, normalizedSource[key]);
54
+ } else {
55
+ result[key] = normalizedSource[key];
56
+ }
57
+ }
58
+ return result;
59
+ }
60
+ function interpolate(message, variables) {
61
+ if (!variables)
62
+ return message;
63
+ return message.replace(/\{(\w+)\}/g, (match, key) => {
64
+ return variables[key] !== void 0 ? String(variables[key]) : match;
65
+ });
66
+ }
67
+ async function createMazTranslations(options = {}) {
68
+ const {
69
+ locale: initialLocale = "en",
70
+ fallbackLocale = "en",
71
+ preloadFallback = true,
72
+ messages = {}
73
+ } = options;
74
+ const locale = ref(initialLocale);
75
+ const messagesRef = ref({});
76
+ const loadedLocales = ref(/* @__PURE__ */ new Set());
77
+ const loadingPromises = ref(/* @__PURE__ */ new Map());
78
+ const userMessageLoaders = ref({});
79
+ for (const [loc, msgs] of Object.entries(messages)) {
80
+ userMessageLoaders.value[loc] = typeof msgs === "function" ? msgs : () => Promise.resolve(msgs);
81
+ }
82
+ function loadLocaleMessages(targetLocale) {
83
+ if (loadedLocales.value.has(targetLocale)) {
84
+ return;
85
+ }
86
+ if (loadingPromises.value.has(targetLocale)) {
87
+ return loadingPromises.value.get(targetLocale);
88
+ }
89
+ const loadingPromise = (async () => {
90
+ try {
91
+ let defaultMessages = {};
92
+ let userMessages = {};
93
+ if (defaultLocaleLoaders[targetLocale]) {
94
+ const defaultModule = await defaultLocaleLoaders[targetLocale]();
95
+ defaultMessages = defaultModule.default;
96
+ }
97
+ const userLoader = userMessageLoaders.value[targetLocale];
98
+ if (userLoader) {
99
+ if (typeof userLoader === "function") {
100
+ userMessages = await userLoader();
101
+ } else {
102
+ userMessages = userLoader;
103
+ }
104
+ }
105
+ messagesRef.value[targetLocale] = merge(defaultMessages, userMessages);
106
+ loadedLocales.value.add(targetLocale);
107
+ } catch (error) {
108
+ console.error(`Failed to load translations for locale "${targetLocale}":`, error);
109
+ messagesRef.value[targetLocale] = {};
110
+ loadedLocales.value.add(targetLocale);
111
+ } finally {
112
+ loadingPromises.value.delete(targetLocale);
113
+ }
114
+ })();
115
+ loadingPromises.value.set(targetLocale, loadingPromise);
116
+ return loadingPromise;
117
+ }
118
+ const localePromises = [];
119
+ localePromises.push(loadLocaleMessages(initialLocale));
120
+ if (preloadFallback && fallbackLocale !== initialLocale) {
121
+ localePromises.push(loadLocaleMessages(fallbackLocale));
122
+ }
123
+ await Promise.all(localePromises);
124
+ const t = (key, variables) => {
125
+ let message = get(messagesRef.value[locale.value], key);
126
+ if (!message && locale.value !== fallbackLocale) {
127
+ if (!loadedLocales.value.has(fallbackLocale)) {
128
+ loadLocaleMessages(fallbackLocale)?.catch(console.error);
129
+ console.warn(`Fallback locale "${fallbackLocale}" not loaded yet for key "${key}", loading...`);
130
+ return key;
131
+ }
132
+ message = get(messagesRef.value[fallbackLocale], key);
133
+ }
134
+ if (!message && fallbackLocale !== "en" && locale.value !== "en") {
135
+ if (!loadedLocales.value.has("en")) {
136
+ loadLocaleMessages("en")?.catch(console.error);
137
+ console.warn(`English fallback not loaded yet for key "${key}", loading...`);
138
+ return key;
139
+ }
140
+ message = get(messagesRef.value.en, key);
141
+ }
142
+ if (!message) {
143
+ console.warn(`Translation key "${key}" not found for locale "${locale.value}"`);
144
+ return key;
145
+ }
146
+ return interpolate(String(message), variables);
147
+ };
148
+ const setLocale = async (newLocale) => {
149
+ if (!loadedLocales.value.has(newLocale)) {
150
+ await loadLocaleMessages(newLocale);
151
+ }
152
+ locale.value = newLocale;
153
+ };
154
+ return { locale, t, setLocale };
155
+ }
156
+ async function useMazTranslations() {
157
+ if (!globalInstance) {
158
+ globalInstance = await createMazTranslations();
159
+ }
160
+ return globalInstance;
161
+ }
162
+ function setGlobalMazTranslations(instance) {
163
+ globalInstance = instance;
164
+ }
165
+
166
+ const MazTranslations = {
167
+ async install(app, options = {}) {
168
+ const i18n = await createMazTranslations(options);
169
+ setGlobalMazTranslations(i18n);
170
+ app.config.globalProperties.$mazTranslations = i18n;
171
+ app.provide("mazTranslations", i18n);
172
+ return i18n;
173
+ }
174
+ };
175
+
176
+ function useTranslations() {
177
+ const injected = inject("mazTranslations");
178
+ if (!injected) {
179
+ throw new Error("MazTranslations plugin or MazUi plugin not installed. Please install the plugin first.");
180
+ }
181
+ return injected;
182
+ }
183
+
184
+ export { MazTranslations, createMazTranslations, setGlobalMazTranslations, useMazTranslations, useTranslations };
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@maz-ui/translations",
3
+ "type": "module",
4
+ "version": "4.0.0-beta.0",
5
+ "description": "Translations for Maz-UI library",
6
+ "author": "Louis Mazel <me@loicmazuel.com>",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/LouisMazel/maz-ui.git"
11
+ },
12
+ "bugs": "https://github.com/LouisMazel/maz-ui/issues",
13
+ "keywords": [
14
+ "translations",
15
+ "i18n",
16
+ "internationalization",
17
+ "localization",
18
+ "maz-ui",
19
+ "vue",
20
+ "nuxt"
21
+ ],
22
+ "sideEffects": false,
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.mjs"
30
+ },
31
+ "./*": "./*"
32
+ },
33
+ "main": "./dist/index.mjs",
34
+ "types": "./dist/index.d.ts",
35
+ "files": [
36
+ "LICENSE",
37
+ "README.md",
38
+ "dist"
39
+ ],
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "scripts": {
44
+ "build": "unbuild",
45
+ "dev": "unbuild --stub",
46
+ "typecheck": "tsc --noEmit --skipLibCheck",
47
+ "lint": "eslint .",
48
+ "lint:fix": "eslint . --fix",
49
+ "pre-commit": "lint-staged"
50
+ },
51
+ "peerDependencies": {
52
+ "vue": "^3.5.0"
53
+ },
54
+ "devDependencies": {
55
+ "@maz-ui/utils": "4.0.0-beta.0",
56
+ "typescript": "^5.8.3",
57
+ "unbuild": "^3.5.0",
58
+ "vue": "catalog:"
59
+ },
60
+ "lint-staged": {
61
+ "*.{js,jsx,ts,tsx,mjs,mts,cjs,md}": [
62
+ "eslint --fix"
63
+ ]
64
+ },
65
+ "gitHead": "9ef7beb4feeee0b0cb44e7df8af7115d5d5ef334"
66
+ }