@humandialog/forms.svelte 1.5.1 → 1.6.1

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.
@@ -25,19 +25,19 @@ declare const __propDef: {
25
25
  run?: ((onStop?: undefined) => void) | undefined;
26
26
  getFormattingOperations?: ((withCaptions?: boolean) => any[]) | undefined;
27
27
  getMarksOperations?: ((tbr?: string) => {
28
- caption: string;
28
+ caption: any;
29
29
  operations: any[];
30
30
  preAction: (f: any) => void;
31
31
  tbr: string;
32
32
  }) | undefined;
33
33
  getStylesOperations?: ((tbr?: string) => {
34
- caption: string;
34
+ caption: any;
35
35
  operations: any[];
36
36
  preAction: (f: any) => void;
37
37
  tbr: string;
38
38
  }) | undefined;
39
39
  getInsertOperations?: ((tbr?: string) => {
40
- caption: string;
40
+ caption: any;
41
41
  operations: any[];
42
42
  preAction: (f: any) => void;
43
43
  tbr: string;
@@ -98,19 +98,19 @@ export default class Editor extends SvelteComponentTyped<EditorProps, EditorEven
98
98
  get run(): (onStop?: undefined) => void;
99
99
  get getFormattingOperations(): (withCaptions?: boolean) => any[];
100
100
  get getMarksOperations(): (tbr?: string) => {
101
- caption: string;
101
+ caption: any;
102
102
  operations: any[];
103
103
  preAction: (f: any) => void;
104
104
  tbr: string;
105
105
  };
106
106
  get getStylesOperations(): (tbr?: string) => {
107
- caption: string;
107
+ caption: any;
108
108
  operations: any[];
109
109
  preAction: (f: any) => void;
110
110
  tbr: string;
111
111
  };
112
112
  get getInsertOperations(): (tbr?: string) => {
113
- caption: string;
113
+ caption: any;
114
114
  operations: any[];
115
115
  preAction: (f: any) => void;
116
116
  tbr: string;
@@ -1,5 +1,9 @@
1
1
  import Floating_container from './Floating_container.svelte';
2
- export declare function showMenu(around: DOMRect | DOMPoint, operations: any): void;
2
+ export declare const SHOW_MENU_BELOW = 0;
3
+ export declare const SHOW_MENU_ABOVE = 1;
4
+ export declare const SHOW_MENU_RIGHT = 2;
5
+ export declare const SHOW_MENU_LEFT = 3;
6
+ export declare function showMenu(around: DOMRect | DOMPoint, operations: any, preference?: number): void;
3
7
  export declare function hideWholeContextMenu(): void;
4
8
  export declare function showFloatingToolbar(around: DOMRect | DOMPoint, toolbar: any, props?: {}): Floating_container | null;
5
9
  export declare function hideFloatingToolbar(): void;
@@ -3,7 +3,11 @@ import Floating_container from './Floating_container.svelte';
3
3
  import Grid from './Grid.menu.svelte';
4
4
  let menu_comopnent = null;
5
5
  let toolbar_component = null;
6
- export function showMenu(around, operations) {
6
+ export const SHOW_MENU_BELOW = 0;
7
+ export const SHOW_MENU_ABOVE = 1;
8
+ export const SHOW_MENU_RIGHT = 2;
9
+ export const SHOW_MENU_LEFT = 3;
10
+ export function showMenu(around, operations, preference = SHOW_MENU_BELOW) {
7
11
  let menu_element = document.getElementById("__hd_svelte_contextmenu");
8
12
  if (!menu_element) {
9
13
  let app_div = document.getElementById("__hd_svelte_layout_root");
@@ -13,13 +17,13 @@ export function showMenu(around, operations) {
13
17
  target: app_div,
14
18
  props: {}
15
19
  });
16
- menu_comopnent.show(around, operations);
20
+ menu_comopnent.show(around, operations, preference);
17
21
  }
18
22
  else if (menu_comopnent) {
19
23
  if (menu_comopnent.isVisible())
20
24
  menu_comopnent.hide();
21
25
  else
22
- menu_comopnent.show(around, operations);
26
+ menu_comopnent.show(around, operations, preference);
23
27
  }
24
28
  else
25
29
  console.error('what now?');
@@ -1,5 +1,7 @@
1
1
  <script>
2
2
 
3
+ import {i18n} from '../i18n.js'
4
+
3
5
  export let pageNo
4
6
  export let allPagesNo
5
7
  export let onPage
@@ -67,7 +69,9 @@
67
69
  <li>
68
70
  <button on:click={onPrevPage}
69
71
  class="flex items-center justify-center px-3 h-8 ms-0 leading-tight text-stone-500 bg-white border border-e-0 border-stone-300 rounded-s-lg hover:bg-stone-100 hover:text-stone-700 dark:bg-stone-800 dark:border-stone-700 dark:text-stone-400 dark:hover:bg-stone-700 dark:hover:text-white">
70
- <span class="sr-only">Previous</span>
72
+ <span class="sr-only">
73
+ { i18n({en: 'Previous', es: 'Anterior', pl: 'Wcześniejsze'}) }
74
+ </span>
71
75
  <svg class="w-2.5 h-2.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
72
76
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 1 1 5l4 4"/>
73
77
  </svg>
@@ -94,7 +98,11 @@
94
98
  <!--a href="#" aria-current="page" class="">3</a-->
95
99
  <li>
96
100
  <button on:click={onNextPage} class="flex items-center justify-center px-3 h-8 leading-tight text-stone-500 bg-white border border-stone-300 rounded-e-lg hover:bg-stone-100 hover:text-stone-700 dark:bg-stone-800 dark:border-stone-700 dark:text-stone-400 dark:hover:bg-stone-700 dark:hover:text-white">
97
- <span class="sr-only">Next</span>
101
+ <span class="sr-only">
102
+
103
+ { i18n({en: 'Next', es: 'Siguiente', pl: 'Następne'}) }
104
+
105
+ </span>
98
106
  <svg class="w-2.5 h-2.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
99
107
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
100
108
  </svg>
@@ -1,8 +1,9 @@
1
1
  <script>import { getContext, tick } from "svelte";
2
2
  import Icon from "../icon.svelte";
3
- import { contextItemsStore, auto_hide_sidebar, contextToolbarOperations } from "../../stores";
3
+ import { contextItemsStore, contextToolbarOperations } from "../../stores";
4
4
  import { FaBars, FaEllipsisV } from "svelte-icons/fa";
5
5
  import { link, push } from "svelte-spa-router";
6
+ import { i18n } from "../../i18n";
6
7
  import {
7
8
  selectable as _selectable,
8
9
  isSelected,
@@ -11,8 +12,7 @@ import {
11
12
  activateItem,
12
13
  startEditing,
13
14
  getActive,
14
- isOnNavigationPage,
15
- UI
15
+ navAutoHide
16
16
  } from "../../utils";
17
17
  import { showMenu } from "../menu";
18
18
  export let href;
@@ -126,7 +126,7 @@ function on_link_clicked(e) {
126
126
  redirect_to(href2);
127
127
  }
128
128
  } else {
129
- auto_hide_sidebar();
129
+ navAutoHide();
130
130
  redirect_to(href2);
131
131
  }
132
132
  }
@@ -185,7 +185,7 @@ function activateRow(e) {
185
185
  opver: 1,
186
186
  operations: [
187
187
  {
188
- caption: "View",
188
+ caption: i18n({ en: "View", es: "Ver", pl: "Widok" }),
189
189
  operations: [
190
190
  {
191
191
  icon: FaEllipsisV,
@@ -4,6 +4,7 @@
4
4
  import TagColorsPalette from './tag.colors.svelte'
5
5
  import { tick } from 'svelte';
6
6
  import { isDeviceSmallerThan } from '../utils';
7
+ import {i18n} from '../i18n'
7
8
 
8
9
  export let usedTags = []
9
10
  export let allTags = []
@@ -194,9 +195,13 @@
194
195
  onCustomClick={(e) => onTagSelected(tag)}/>
195
196
  {/each}
196
197
  {:else if allowNewTags}
197
- <p>Create tag:</p>
198
+ <p>
199
+ { i18n({en: 'Create tag:', es: 'Crear etiqueta:', pl: 'Utwrórz etykietę:'}) }
200
+ </p>
198
201
  {:else}
199
- <p>No tags</p>
202
+ <p>
203
+ { i18n({en: 'No tags', es: 'Sin etiquetas', pl: 'Żadnych etykiet'}) }
204
+ </p>
200
205
  {/if}
201
206
 
202
207
  {/key}
@@ -211,7 +216,7 @@
211
216
  on:input={onTextInput}
212
217
  on:blur={onTextBlur}
213
218
  on:keydown={onKeyDown}
214
- placeholder="Type to filter or create tag">
219
+ placeholder={i18n({en: 'Type to filter or create tag', es: 'Escriba para filtrar o crear una etiqueta', pl: 'Wpisz, aby filtrować lub utworzyć tag'})}>
215
220
  {#if allowNewTags}
216
221
  <button class="block w-5 h-5 mt-0.5 ml-auto mr-2
217
222
  text-stone-600 hover:text-stone-800 hover:bg-stone-200 active:bg-stone-200 border-stone-200
package/desk.svelte CHANGED
@@ -9,7 +9,6 @@
9
9
  import {main_sidebar_visible_store,
10
10
  tools_visible_store,
11
11
  bottom_bar_visible_store,
12
- auto_hide_sidebar,
13
12
  hasSelectedItem,
14
13
  dark_mode_store,
15
14
  data_tick_store,
@@ -20,7 +19,7 @@
20
19
  alerts, removeAlert, showFABAlways} from './stores.js'
21
20
 
22
21
  //import { AuthorizedView} from '@humandialog/auth.svelte'
23
- import { handleSelect, isDeviceSmallerThan, isOnNavigationPage, isOnScreenKeyboardVisible, removeAt, UI } from './utils'
22
+ import { handleSelect, isDeviceSmallerThan, isOnScreenKeyboardVisible, navGetMode, removeAt, UI, NAV_MODE_SIDEBAR, navAutoHide, navIsVisible } from './utils'
24
23
  import { afterUpdate, onMount } from 'svelte';
25
24
  import {location} from 'svelte-spa-router'
26
25
  import {FaCopy, FaTimes} from 'svelte-icons/fa'
@@ -76,8 +75,8 @@
76
75
  //let autoRedirectToSignIn = layout.autoRedirectToSignIn ?? true
77
76
 
78
77
  $: { visible_sidebar = $main_sidebar_visible_store
79
-
80
- if(!is_small)
78
+ const navMode = navGetMode()
79
+ if(navMode == NAV_MODE_SIDEBAR)
81
80
  {
82
81
  if(visible_sidebar == "*")
83
82
  {
@@ -190,10 +189,11 @@
190
189
  }
191
190
 
192
191
 
193
- $: navigationPageVisible = navigationPageSetup($location);
192
+ $: navigationPageSetup($location);
194
193
  function navigationPageSetup(...args)
195
194
  {
196
- if(!is_small)
195
+ const navMode = navGetMode()
196
+ if(navMode == NAV_MODE_SIDEBAR)
197
197
  {
198
198
  vertical_toolbar_visibility = "hidden sm:block"
199
199
  content_left = "left-0 sm:left-[40px]";
@@ -202,7 +202,7 @@
202
202
  }
203
203
  else
204
204
  {
205
- if(isOnNavigationPage())
205
+ if(navIsVisible())
206
206
  {
207
207
  vertical_toolbar_visibility = "block"
208
208
  content_left = "left-[50px]";
@@ -254,7 +254,7 @@
254
254
 
255
255
  function on_resize()
256
256
  {
257
- auto_hide_sidebar();
257
+ navAutoHide()
258
258
  }
259
259
 
260
260
  let minViewportHeight = 0;
@@ -278,6 +278,7 @@
278
278
 
279
279
  function onViewportResize(e)
280
280
  {
281
+ console.log('onViewportResize')
281
282
  const vp = window.visualViewport;
282
283
  setViewportHeight(vp)
283
284
 
@@ -411,7 +412,7 @@
411
412
  behaviour is the content expand vertically, and only vertical scrollbar can be visible.
412
413
  When content on the main page needs to be expanded horizontally (like kanban chart for example) then
413
414
  that component should define overflow-x-* itself -->
414
- <section on:click|capture={() => { if(!navigationPageVisible) auto_hide_sidebar()} } class="">
415
+ <section on:click|capture={() => navAutoHide() } class="">
415
416
 
416
417
  <!--###########################################################-->
417
418
  <!--## HORIZONTAL TOOLS ######################-->
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import {FaUsers, FaCog, FaSignInAlt, FaSignOutAlt, FaBars, FaToggleOn, FaToggleOff} from 'svelte-icons/fa/'
2
+ import {FaUsers, FaCog, FaSignInAlt, FaSignOutAlt, FaBars, FaToggleOn, FaToggleOff, FaLanguage} from 'svelte-icons/fa/'
3
3
  //import GoPrimitiveDot from 'svelte-icons/go/GoPrimitiveDot.svelte'
4
4
  import {showMenu} from './components/menu'
5
5
  import {push, pop, location} from 'svelte-spa-router'
@@ -8,13 +8,8 @@
8
8
 
9
9
  import {
10
10
  dark_mode_store,
11
- toggle_sidebar,
12
- show_sidebar,
13
- hide_sidebar,
14
11
  tools_visible_store,
15
12
  bottom_bar_visible_store,
16
- previously_visible_sidebar,
17
- main_sidebar_visible_store,
18
13
  sidebar_left_pos,
19
14
  page_title,
20
15
  nav_titles,
@@ -24,8 +19,8 @@
24
19
  import {session, signInHRef, signOutHRef} from '@humandialog/auth.svelte'
25
20
 
26
21
  import VerticalToolbar from './vertical.toolbar.svelte'
27
- import { isDeviceSmallerThan, isOnNavigationPage, pushNavigationPage, popNavigationPage } from './utils.js';
28
-
22
+ import { isDeviceSmallerThan, navIsVisible, navGetKey, navToggle, navShow, navHide, navPrevVisibleKey } from './utils.js';
23
+ import {setCurrentLanguage, getLanguages, i18n, getCurrentLanguage} from './i18n.js'
29
24
 
30
25
  export let appConfig = undefined;
31
26
  export let clearsContext = 'sel props'
@@ -35,7 +30,7 @@
35
30
 
36
31
  let config = null;
37
32
  let has_selection_details = false;
38
- let selection_details_caption = 'Properties'
33
+ let selection_details_caption = i18n({en: 'Properties', es: 'Propiedades', pl: 'Właściwości'});
39
34
 
40
35
  let show_sign_in_out_icons = false;
41
36
  let is_logged_in = false;
@@ -53,7 +48,13 @@
53
48
  config = appConfig.mainToolbar;
54
49
  has_selection_details = appConfig.selectionDetails;
55
50
  if(has_selection_details)
56
- selection_details_caption = appConfig.selectionDetails.caption ?? 'Properties';
51
+ {
52
+ if(appConfig.selectionDetails.captionFunc)
53
+ selection_details_caption = appConfig.selectionDetails.captionFunc()
54
+ else if(appConfig.selectionDetails.caption)
55
+ selection_details_caption = appConfig.selectionDetails.caption
56
+
57
+ }
57
58
  }
58
59
  else
59
60
  {
@@ -86,11 +87,12 @@
86
87
 
87
88
  let title = ''
88
89
  $:{
89
- if($main_sidebar_visible_store == '*')
90
+ if(!navIsVisible())
90
91
  title = $page_title;
91
92
  else
92
93
  {
93
- let nav_title = $nav_titles[$main_sidebar_visible_store];
94
+ const navKey = navGetKey()
95
+ let nav_title = $nav_titles[navKey];
94
96
  if(nav_title != undefined)
95
97
  title = nav_title
96
98
  else
@@ -100,59 +102,25 @@
100
102
 
101
103
  function toggle_navigator(e)
102
104
  {
103
- if(isDeviceSmallerThan('sm'))
105
+ if(tabs.length == 1)
104
106
  {
105
- if(isOnNavigationPage())
106
- {
107
- popNavigationPage();
108
- }
109
- else
110
- {
111
- if(tabs.length == 1)
112
- {
113
- $sidebar_left_pos = 0;
114
- show_sidebar(tabs[0]);
115
- }
116
- else
117
- {
118
- let sidebar = $main_sidebar_visible_store;
119
- if(sidebar == "*")
120
- {
121
- if((!previously_visible_sidebar) || previously_visible_sidebar === '*')
122
- sidebar = Object.keys(appConfig.sidebar)[0];
123
- else
124
- sidebar = previously_visible_sidebar;
125
- }
126
-
127
- $sidebar_left_pos = 40;
128
- show_sidebar(sidebar)
129
- }
130
-
131
- pushNavigationPage();
132
- }
107
+ $sidebar_left_pos = 0;
108
+ navToggle(tabs[0])
133
109
  }
134
110
  else
135
111
  {
112
+ $sidebar_left_pos = 40;
136
113
 
137
- if(tabs.length == 1)
114
+ if(!navIsVisible())
138
115
  {
139
- $sidebar_left_pos = 0;
140
- toggle_sidebar(tabs[0]);
116
+ let navKey = navPrevVisibleKey()
117
+ if(!navKey)
118
+ navKey = Object.keys(appConfig.sidebar)[0]
119
+
120
+ navShow(navKey);
141
121
  }
142
122
  else
143
- {
144
- let sidebar = $main_sidebar_visible_store;
145
- if(sidebar == "*")
146
- {
147
- if((!previously_visible_sidebar) || previously_visible_sidebar === '*')
148
- sidebar = Object.keys(appConfig.sidebar)[0];
149
- else
150
- sidebar = previously_visible_sidebar;
151
- }
152
-
153
- $sidebar_left_pos = 40;
154
- toggle_sidebar(sidebar)
155
- }
123
+ navHide()
156
124
  }
157
125
  }
158
126
 
@@ -177,8 +145,14 @@
177
145
 
178
146
  if(add)
179
147
  {
148
+ let caption = ''
149
+ if(o.captionFunc)
150
+ caption = o.captionFunc()
151
+ else if(o.caption)
152
+ caption = o.caption
153
+
180
154
  options.push({
181
- caption: o.caption,
155
+ caption: caption,
182
156
  icon: o.icon,
183
157
  action: o.action
184
158
  })
@@ -191,7 +165,7 @@
191
165
  if(!is_logged_in)
192
166
  {
193
167
  options.push({
194
- caption: 'Sign in',
168
+ caption: i18n( { en: 'Sign in', es: 'Iniciar sesión', pl: 'Zaloguj'}),
195
169
  icon: FaSignInAlt,
196
170
  action: (focused) => { push(sign_in_href) }
197
171
  });
@@ -199,7 +173,7 @@
199
173
  else
200
174
  {
201
175
  options.push({
202
- caption: 'Sign out',
176
+ caption: i18n({en: 'Sign out', es: 'Cerrar sesión', pl: 'Wyloguj' }) ,
203
177
  icon: FaSignOutAlt,
204
178
  action: (focused) => { push(sign_out_href) }
205
179
  });
@@ -211,10 +185,11 @@
211
185
 
212
186
  if(!config || config.darkMode)
213
187
  {
188
+ const capt = i18n({en: 'Dark mode', es: 'Modo oscuro', pl: 'Tryb ciemny'})
214
189
  if($dark_mode_store == '')
215
190
  {
216
191
  options.push( {
217
- caption: 'Dark mode',
192
+ caption: capt,
218
193
  icon: FaToggleOff,
219
194
  action: (focused) => { $dark_mode_store = 'dark'; }
220
195
  });
@@ -222,24 +197,41 @@
222
197
  else
223
198
  {
224
199
  options.push( {
225
- caption: 'Dark mode',
200
+ caption: capt,
226
201
  icon: FaToggleOn,
227
202
  action: (focused) => { $dark_mode_store = ''; }
228
203
  });
229
204
  }
230
205
  }
231
206
 
207
+ const langs = getLanguages()
208
+ if(langs && langs.length > 1)
209
+ {
210
+ const langMenu = langs.map( l => ({
211
+ caption: l.name,
212
+ img: l.flag,
213
+ action: (b) => {setCurrentLanguage(l); reloadWholeApp()},
214
+ disabled: getCurrentLanguage() == l
215
+ }))
216
+
217
+ options.push( {
218
+ caption: i18n({en: 'Language', es:'Idioma', pl:'Język'}),
219
+ menu: langMenu,
220
+ icon: FaLanguage
221
+ })
222
+ }
223
+
232
224
  if(config && config.operations)
233
225
  {
234
226
  options.push( {
235
- caption: 'Toolbar',
227
+ caption: i18n({en:'Toolbar', es:'Barra de herramientas', pl:'Pasek narzędzi'}),
236
228
  icon: $tools_visible_store ? FaToggleOn : FaToggleOff,
237
229
  action: (focused) => { $tools_visible_store = !$tools_visible_store; }
238
230
  });
239
231
  }
240
232
 
241
233
  options.push({
242
- caption: 'Left-handed floating actions',
234
+ caption: i18n({en: 'Left-handed mode', es: 'Modo para zurdos', pl: 'Tryb dla leworęcznych'}),
243
235
  icon: $leftHandedFAB ? FaToggleOn : FaToggleOff,
244
236
  action: (f) => { $leftHandedFAB = !$leftHandedFAB; }
245
237
  })
@@ -344,7 +336,7 @@
344
336
 
345
337
  </div>
346
338
 
347
- {#if false && tabs.length > 1 && $main_sidebar_visible_store != "*"}
339
+ {#if false && tabs.length > 1 && navIsVisible()}
348
340
  <div class="no-print flex-none block fixed left-0 top-[40px] w-[40px] h-screen z-20 inset-0 overflow-hidden">
349
341
  <div class="sticky top-0 flex h-full w-10 bg-stone-900 flex-col items-center text-stone-100 shadow">
350
342
  <VerticalToolbar {appConfig} mobile={true}/>
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Zamienia:
3
+ * _; EN;ES ; PL
4
+ * "_; EN;ES ; PL"
5
+ * '_; Foo ; Bar;Baz'
6
+ * `_; A; B ; C`
7
+ * na:
8
+ * i18n(["EN", "ES", "PL"]) // znormalizowane odstępy: "; "
9
+ *
10
+ * Dwie fazy:
11
+ * 1) quoted: podmienia CAŁE literały stringów (", ', `)
12
+ * 2) unquoted: podmienia goły tekst (np. w markupie)
13
+ */
14
+ export function i18nPreprocess({ dryRun }?: {
15
+ dryRun?: boolean | undefined;
16
+ }): {
17
+ name: string;
18
+ markup({ content, filename }: {
19
+ content: any;
20
+ filename: any;
21
+ }): {
22
+ code: any;
23
+ };
24
+ script({ content, attributes, filename }: {
25
+ content: any;
26
+ attributes: any;
27
+ filename: any;
28
+ }): {
29
+ code: any;
30
+ attributes: any;
31
+ };
32
+ style({ content, attributes }: {
33
+ content: any;
34
+ attributes: any;
35
+ }): {
36
+ code: any;
37
+ attributes: any;
38
+ };
39
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Zamienia:
3
+ * _; EN;ES ; PL
4
+ * "_; EN;ES ; PL"
5
+ * '_; Foo ; Bar;Baz'
6
+ * `_; A; B ; C`
7
+ * na:
8
+ * i18n(["EN", "ES", "PL"]) // znormalizowane odstępy: "; "
9
+ *
10
+ * Dwie fazy:
11
+ * 1) quoted: podmienia CAŁE literały stringów (", ', `)
12
+ * 2) unquoted: podmienia goły tekst (np. w markupie)
13
+ */
14
+
15
+ export function i18nPreprocess({ dryRun = false } = {}) {
16
+ const lit = (s) => JSON.stringify(s);
17
+ const toArrayExpr = (list) =>
18
+ `[${list
19
+ .split(/\s*;\s*/g) // zachowuje puste między ';;'
20
+ .map((s) => s.trim()) // przytnij brzegi
21
+ .map(lit) // JSON.stringify
22
+ .join(', ')}]`;
23
+
24
+ // 1) W <script> zamieniamy CAŁE literały "_; ...; ..." -> i18n([ ... ])
25
+ // Uwaga: dla prostoty nie dopuszczamy cudzysłowów/backticków wewnątrz placeholderów
26
+ const QUOTED_IN_SCRIPT =
27
+ /(['"`])\s*_;\s*((?:[^'"`;\r\n]*)(?:\s*;\s*[^'"`;\r\n]*)*)\s*\1/g;
28
+
29
+
30
+ // 2) W markup – TYLKO surowy tekst między tagami (nie dotykamy atrybutów)
31
+ const UNQUOTED_TEXT_IN_MARKUP =
32
+ /(^|>)(\s*)_;\s*((?:[^;<>]*)(?:\s*;\s*[^;<>]*)*)/g;
33
+
34
+ // ATRYBUTY: name="_; A; ; C" -> name={i18n(["A", "", "C"])}
35
+ const ATTR_QUOTED =
36
+ /(\s[0-9A-Za-z_:@#.-]+)\s*=\s*(["'])\s*_;\s*((?:[^"'<>]*)(?:\s*;\s*[^"'<>]*)*)\s*\2/g;
37
+
38
+ // Wytnij i przywróć bloki, żeby w fazie markup nie ruszać <script>/<style>
39
+ const extractBlocks = (content, tag) => {
40
+ const re = new RegExp(`<${tag}\\b[\\s\\S]*?>[\\s\\S]*?<\\/${tag}>`, 'gi');
41
+ const blocks = [];
42
+ const placeholders = [];
43
+ let i = 0;
44
+ content = content.replace(re, (m) => {
45
+ const key = `<<<${tag.toUpperCase()}_BLOCK_${i++}>>>`;
46
+ blocks.push(m);
47
+ placeholders.push(key);
48
+ return key;
49
+ });
50
+ return { content, blocks, placeholders };
51
+ };
52
+
53
+ // UWAGA: używamy funkcji jako replacera, by nie zepsuć `$$props` -> `$props`
54
+ const restoreBlocks = (content, placeholders, blocks) => {
55
+ placeholders.forEach((key, idx) => {
56
+ content = content.replace(key, () => blocks[idx]);
57
+ });
58
+ return content;
59
+ };
60
+
61
+ return {
62
+ name: 'i18n-preprocess',
63
+
64
+ markup({ content, filename }) {
65
+ const s = extractBlocks(content, 'script');
66
+ const ss = extractBlocks(s.content, 'style');
67
+
68
+ let body = ss.content;
69
+ let count = 0;
70
+
71
+ body = body.replace(UNQUOTED_TEXT_IN_MARKUP, (m, before, pre, list) => {
72
+ count++;
73
+ return `${before}${pre}{i18n(${toArrayExpr(list)})}`;
74
+ });
75
+
76
+ if (count) console.log(`[i18n-preprocess][markup] ${filename} -> ${count} replace(s)`);
77
+
78
+ body = restoreBlocks(body, ss.placeholders, ss.blocks);
79
+ body = restoreBlocks(body, s.placeholders, s.blocks);
80
+
81
+ if (dryRun) return { code: content };
82
+ return { code: body };
83
+ },
84
+
85
+ script({ content, attributes, filename }) {
86
+ let count = 0;
87
+ const code = content.replace(QUOTED_IN_SCRIPT, (_m, _q, list) => {
88
+ count++;
89
+ return `i18n(${toArrayExpr(list)})`;
90
+ });
91
+ // if (count) console.log(`[i18n-preprocess][script] ${filename} -> ${count} replace(s)`);
92
+ if (dryRun) return { code: content, attributes };
93
+ return { code, attributes };
94
+ },
95
+
96
+ style({ content, attributes }) {
97
+ return { code: content, attributes };
98
+ }
99
+ };
100
+ }
package/i18n.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ export function setLanguages(langs: any): void;
2
+ export function getLanguages(): ({
3
+ key: string;
4
+ name: string;
5
+ flag: string;
6
+ default: boolean;
7
+ } | {
8
+ key: string;
9
+ name: string;
10
+ flag: string;
11
+ default?: undefined;
12
+ })[];
13
+ export function setCurrentLanguage(sel: any): void;
14
+ export function getCurrentLanguage(): {
15
+ key: string;
16
+ name: string;
17
+ flag: string;
18
+ default: boolean;
19
+ } | {
20
+ key: string;
21
+ name: string;
22
+ flag: string;
23
+ default?: undefined;
24
+ };
25
+ export function getCurrentLanguageIdx(): number;
26
+ export function getCurrentLanguageKey(): string;
27
+ /**
28
+ * i18n("EN; ES; PL") => "EN" albo "ES" albo "PL"
29
+ */
30
+ export function i18n(list: any): any;
31
+ export function extractTranslated(str: any): any;
32
+ export function ext(str: any): any;