@selvajs/ui 4.7.1 → 4.9.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/dist/components/compute/AppLayout.svelte +8 -4
- package/dist/components/compute/CollapsedPanelStrip.svelte +8 -1
- package/dist/components/compute/ComputeApp.svelte +19 -2
- package/dist/components/compute/ComputeApp.svelte.d.ts +8 -0
- package/dist/components/preview/TabContent.svelte +5 -1
- package/dist/components/primitives/CalculateButton.svelte +8 -4
- package/dist/components/primitives/SolvingIndicator.svelte +7 -2
- package/dist/components/viewer/MeshMetadataDialog.svelte +6 -2
- package/dist/components/viewer/SceneManager.svelte +15 -9
- package/dist/components/viewer/Viewer.svelte +44 -23
- package/dist/components/viewer/Viewer.svelte.d.ts +8 -0
- package/dist/i18n/localeContext.svelte.d.ts +18 -0
- package/dist/i18n/localeContext.svelte.js +50 -0
- package/dist/i18n/messages.d.ts +54 -0
- package/dist/i18n/messages.js +112 -0
- package/dist/public.d.ts +3 -0
- package/dist/public.js +4 -1
- package/package.json +1 -1
- package/src/lib/components/compute/AppLayout.svelte +8 -4
- package/src/lib/components/compute/CollapsedPanelStrip.svelte +8 -1
- package/src/lib/components/compute/ComputeApp.svelte +19 -2
- package/src/lib/components/preview/TabContent.svelte +5 -1
- package/src/lib/components/primitives/CalculateButton.svelte +8 -4
- package/src/lib/components/primitives/SolvingIndicator.svelte +7 -2
- package/src/lib/components/viewer/MeshMetadataDialog.svelte +6 -2
- package/src/lib/components/viewer/SceneManager.svelte +15 -9
- package/src/lib/components/viewer/Viewer.svelte +44 -23
- package/src/lib/i18n/localeContext.svelte.ts +63 -0
- package/src/lib/i18n/messages.ts +190 -0
- package/src/lib/public.ts +14 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { type Locale, type ViewerMessages, messagesFor, DEFAULT_LOCALE } from './messages';
|
|
3
|
+
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Viewer locale context
|
|
6
|
+
// ============================================================================
|
|
7
|
+
//
|
|
8
|
+
// Carries the current UI locale down to the viewer and its panels without
|
|
9
|
+
// threading a `lang` prop through every layer. The value is a getter so the
|
|
10
|
+
// host can back it with reactive state — flip the language and the viewer
|
|
11
|
+
// re-renders live.
|
|
12
|
+
//
|
|
13
|
+
// Resolution order for any consuming component:
|
|
14
|
+
// explicit `lang` prop → nearest locale context → English default
|
|
15
|
+
//
|
|
16
|
+
// Two ways to provide it:
|
|
17
|
+
// - Standalone: <Viewer lang="de" /> — Viewer provides the context itself.
|
|
18
|
+
// - In an app: call setLocaleContext(() => app.locale) once at the root; the
|
|
19
|
+
// viewer (and anything else) reads it. selva later wires its Paraglide
|
|
20
|
+
// locale in here.
|
|
21
|
+
|
|
22
|
+
const LOCALE_CONTEXT_KEY = Symbol('viewer-locale-context');
|
|
23
|
+
|
|
24
|
+
export interface LocaleContext {
|
|
25
|
+
/** Current locale. Called reactively — return reactive state to enable live switching. */
|
|
26
|
+
readonly locale: Locale;
|
|
27
|
+
/** Resolved message catalog for the current locale. */
|
|
28
|
+
readonly messages: ViewerMessages;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Provide the locale to descendants. Pass a getter so a reactive source (a
|
|
33
|
+
* `$state`, a store, the app's Paraglide locale) keeps consumers in sync.
|
|
34
|
+
*/
|
|
35
|
+
export function setLocaleContext(getLocale: () => Locale | undefined): void {
|
|
36
|
+
const ctx: LocaleContext = {
|
|
37
|
+
get locale() {
|
|
38
|
+
return getLocale() ?? DEFAULT_LOCALE;
|
|
39
|
+
},
|
|
40
|
+
get messages() {
|
|
41
|
+
return messagesFor(getLocale());
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
setContext(LOCALE_CONTEXT_KEY, ctx);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Read the locale context. Falls back to an English-only context when no
|
|
49
|
+
* provider exists (e.g. a primitive used in isolation), so consumers never
|
|
50
|
+
* need a null check.
|
|
51
|
+
*/
|
|
52
|
+
export function getLocaleContext(): LocaleContext {
|
|
53
|
+
return (
|
|
54
|
+
getContext<LocaleContext | undefined>(LOCALE_CONTEXT_KEY) ?? {
|
|
55
|
+
get locale() {
|
|
56
|
+
return DEFAULT_LOCALE;
|
|
57
|
+
},
|
|
58
|
+
get messages() {
|
|
59
|
+
return messagesFor(DEFAULT_LOCALE);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Viewer message catalog (library-owned strings)
|
|
3
|
+
// ============================================================================
|
|
4
|
+
//
|
|
5
|
+
// These are the strings @selvajs/ui renders itself in the 3D viewer and its
|
|
6
|
+
// panels — tool menu, view presets, scene manager, metadata dialog. They are
|
|
7
|
+
// NOT the strings that come from a Grasshopper definition (mesh/layer/metadata
|
|
8
|
+
// names): those live in the user's .gh file and can't be translated here.
|
|
9
|
+
//
|
|
10
|
+
// The library ships English + German. A host app can switch locale at runtime
|
|
11
|
+
// via the locale context (see ./localeContext.svelte.ts) — e.g. selva feeds its
|
|
12
|
+
// own Paraglide locale in. With no provider, components fall back to English.
|
|
13
|
+
|
|
14
|
+
export type Locale = 'en' | 'de';
|
|
15
|
+
|
|
16
|
+
export interface ViewerMessages {
|
|
17
|
+
// Tools menu
|
|
18
|
+
toolsMenu: string;
|
|
19
|
+
switchTo2D: string;
|
|
20
|
+
switchTo3D: string;
|
|
21
|
+
fitToView: string;
|
|
22
|
+
views: string;
|
|
23
|
+
measure: string;
|
|
24
|
+
grid: string;
|
|
25
|
+
sceneManager: string;
|
|
26
|
+
screenshot: string;
|
|
27
|
+
fullscreen: string;
|
|
28
|
+
exitFullscreen: string;
|
|
29
|
+
|
|
30
|
+
// View presets
|
|
31
|
+
viewTop: string;
|
|
32
|
+
viewFront: string;
|
|
33
|
+
viewRight: string;
|
|
34
|
+
viewBack: string;
|
|
35
|
+
viewLeft: string;
|
|
36
|
+
viewBottom: string;
|
|
37
|
+
viewIso: string;
|
|
38
|
+
|
|
39
|
+
// Scene manager
|
|
40
|
+
searchObjects: string;
|
|
41
|
+
clearSearch: string;
|
|
42
|
+
expandLayer: string;
|
|
43
|
+
collapseLayer: string;
|
|
44
|
+
showLayer: string;
|
|
45
|
+
hideLayer: string;
|
|
46
|
+
showObject: string;
|
|
47
|
+
hideObject: string;
|
|
48
|
+
noObjects: string;
|
|
49
|
+
/** `{query}` is replaced with the current search text. */
|
|
50
|
+
noResultsFor: string;
|
|
51
|
+
|
|
52
|
+
// Metadata dialog
|
|
53
|
+
objectFallbackName: string;
|
|
54
|
+
noMetadata: string;
|
|
55
|
+
|
|
56
|
+
// App layout / compute shell
|
|
57
|
+
loadingSchema: string;
|
|
58
|
+
parametersTab: string;
|
|
59
|
+
moreTab: string;
|
|
60
|
+
expandPanel: string;
|
|
61
|
+
collapsePanel: string;
|
|
62
|
+
/** `{side}` is replaced with `panelSideLeft` / `panelSideRight`. */
|
|
63
|
+
expandSidePanel: string;
|
|
64
|
+
panelSideLeft: string;
|
|
65
|
+
panelSideRight: string;
|
|
66
|
+
tabNoGroups: string;
|
|
67
|
+
|
|
68
|
+
// Solve controls
|
|
69
|
+
solving: string;
|
|
70
|
+
solvingEllipsis: string;
|
|
71
|
+
solvingSubtitle: string;
|
|
72
|
+
pressToCalculate: string;
|
|
73
|
+
calculate: string;
|
|
74
|
+
upToDate: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const en: ViewerMessages = {
|
|
78
|
+
toolsMenu: 'Viewer tools',
|
|
79
|
+
switchTo2D: 'Switch to 2D',
|
|
80
|
+
switchTo3D: 'Switch to 3D',
|
|
81
|
+
fitToView: 'Fit to view',
|
|
82
|
+
views: 'Views',
|
|
83
|
+
measure: 'Measure',
|
|
84
|
+
grid: 'Grid',
|
|
85
|
+
sceneManager: 'Scene manager',
|
|
86
|
+
screenshot: 'Screenshot',
|
|
87
|
+
fullscreen: 'Fullscreen',
|
|
88
|
+
exitFullscreen: 'Exit fullscreen',
|
|
89
|
+
|
|
90
|
+
viewTop: 'Top',
|
|
91
|
+
viewFront: 'Front',
|
|
92
|
+
viewRight: 'Right',
|
|
93
|
+
viewBack: 'Back',
|
|
94
|
+
viewLeft: 'Left',
|
|
95
|
+
viewBottom: 'Bottom',
|
|
96
|
+
viewIso: 'Isometric',
|
|
97
|
+
|
|
98
|
+
searchObjects: 'Search objects...',
|
|
99
|
+
clearSearch: 'Clear search',
|
|
100
|
+
expandLayer: 'Expand layer',
|
|
101
|
+
collapseLayer: 'Collapse layer',
|
|
102
|
+
showLayer: 'Show layer',
|
|
103
|
+
hideLayer: 'Hide layer',
|
|
104
|
+
showObject: 'Show object',
|
|
105
|
+
hideObject: 'Hide object',
|
|
106
|
+
noObjects: 'No objects',
|
|
107
|
+
noResultsFor: 'No results for "{query}"',
|
|
108
|
+
|
|
109
|
+
objectFallbackName: 'Object',
|
|
110
|
+
noMetadata: 'No metadata',
|
|
111
|
+
|
|
112
|
+
loadingSchema: 'Loading schema...',
|
|
113
|
+
parametersTab: 'Parameters',
|
|
114
|
+
moreTab: 'More',
|
|
115
|
+
expandPanel: 'Expand panel',
|
|
116
|
+
collapsePanel: 'Collapse panel',
|
|
117
|
+
expandSidePanel: 'Expand {side} panel',
|
|
118
|
+
panelSideLeft: 'left',
|
|
119
|
+
panelSideRight: 'right',
|
|
120
|
+
tabNoGroups: 'This tab has no groups configured.',
|
|
121
|
+
|
|
122
|
+
solving: 'Solving',
|
|
123
|
+
solvingEllipsis: 'Solving...',
|
|
124
|
+
solvingSubtitle: 'Grasshopper is calculating...',
|
|
125
|
+
pressToCalculate: 'Press to calculate',
|
|
126
|
+
calculate: 'Calculate',
|
|
127
|
+
upToDate: 'Up to date'
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const de: ViewerMessages = {
|
|
131
|
+
toolsMenu: 'Viewer-Werkzeuge',
|
|
132
|
+
switchTo2D: 'Zu 2D wechseln',
|
|
133
|
+
switchTo3D: 'Zu 3D wechseln',
|
|
134
|
+
fitToView: 'Ansicht anpassen',
|
|
135
|
+
views: 'Ansichten',
|
|
136
|
+
measure: 'Messen',
|
|
137
|
+
grid: 'Raster',
|
|
138
|
+
sceneManager: 'Szenen-Manager',
|
|
139
|
+
screenshot: 'Screenshot',
|
|
140
|
+
fullscreen: 'Vollbild',
|
|
141
|
+
exitFullscreen: 'Vollbild beenden',
|
|
142
|
+
|
|
143
|
+
viewTop: 'Oben',
|
|
144
|
+
viewFront: 'Vorne',
|
|
145
|
+
viewRight: 'Rechts',
|
|
146
|
+
viewBack: 'Hinten',
|
|
147
|
+
viewLeft: 'Links',
|
|
148
|
+
viewBottom: 'Unten',
|
|
149
|
+
viewIso: 'Isometrisch',
|
|
150
|
+
|
|
151
|
+
searchObjects: 'Objekte suchen...',
|
|
152
|
+
clearSearch: 'Suche löschen',
|
|
153
|
+
expandLayer: 'Ebene aufklappen',
|
|
154
|
+
collapseLayer: 'Ebene zuklappen',
|
|
155
|
+
showLayer: 'Ebene einblenden',
|
|
156
|
+
hideLayer: 'Ebene ausblenden',
|
|
157
|
+
showObject: 'Objekt einblenden',
|
|
158
|
+
hideObject: 'Objekt ausblenden',
|
|
159
|
+
noObjects: 'Keine Objekte',
|
|
160
|
+
noResultsFor: 'Keine Ergebnisse für „{query}“',
|
|
161
|
+
|
|
162
|
+
objectFallbackName: 'Objekt',
|
|
163
|
+
noMetadata: 'Keine Metadaten',
|
|
164
|
+
|
|
165
|
+
loadingSchema: 'Schema wird geladen...',
|
|
166
|
+
parametersTab: 'Parameter',
|
|
167
|
+
moreTab: 'Mehr',
|
|
168
|
+
expandPanel: 'Bereich aufklappen',
|
|
169
|
+
collapsePanel: 'Bereich zuklappen',
|
|
170
|
+
expandSidePanel: '{side} Bereich aufklappen',
|
|
171
|
+
panelSideLeft: 'Linken',
|
|
172
|
+
panelSideRight: 'Rechten',
|
|
173
|
+
tabNoGroups: 'Für diesen Tab sind keine Gruppen konfiguriert.',
|
|
174
|
+
|
|
175
|
+
solving: 'Berechnung läuft',
|
|
176
|
+
solvingEllipsis: 'Berechnung läuft...',
|
|
177
|
+
solvingSubtitle: 'Grasshopper berechnet...',
|
|
178
|
+
pressToCalculate: 'Zum Berechnen klicken',
|
|
179
|
+
calculate: 'Berechnen',
|
|
180
|
+
upToDate: 'Aktuell'
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const VIEWER_MESSAGES: Record<Locale, ViewerMessages> = { en, de };
|
|
184
|
+
|
|
185
|
+
export const DEFAULT_LOCALE: Locale = 'en';
|
|
186
|
+
|
|
187
|
+
/** Resolve a catalog for a locale, falling back to English for unknown locales. */
|
|
188
|
+
export function messagesFor(locale: Locale | undefined): ViewerMessages {
|
|
189
|
+
return VIEWER_MESSAGES[locale ?? DEFAULT_LOCALE] ?? VIEWER_MESSAGES[DEFAULT_LOCALE];
|
|
190
|
+
}
|
package/src/lib/public.ts
CHANGED
|
@@ -24,9 +24,22 @@ export { default as ComputeApp } from './components/compute/ComputeApp.svelte';
|
|
|
24
24
|
|
|
25
25
|
// Standalone 3D viewer. Render Grasshopper meshes on their own, outside a
|
|
26
26
|
// ComputeApp host — external apps drive it directly with a `meshes` array and
|
|
27
|
-
// an optional `viewerConfig`.
|
|
27
|
+
// an optional `viewerConfig`. Pass `lang` to localize its chrome, or provide a
|
|
28
|
+
// locale context (setLocaleContext) at the host root to drive it app-wide.
|
|
28
29
|
export { default as Viewer, type ViewerConfig } from './components/viewer/Viewer.svelte';
|
|
29
30
|
|
|
31
|
+
// Viewer localization. The library renders English + German chrome; switch at
|
|
32
|
+
// runtime by passing `lang` to <Viewer> or by setting a reactive locale context
|
|
33
|
+
// once at the host root (e.g. feed in an app-wide Paraglide locale). Does not
|
|
34
|
+
// translate Grasshopper-sourced names/metadata.
|
|
35
|
+
export type { Locale, ViewerMessages } from './i18n/messages';
|
|
36
|
+
export { VIEWER_MESSAGES, DEFAULT_LOCALE, messagesFor } from './i18n/messages';
|
|
37
|
+
export {
|
|
38
|
+
setLocaleContext,
|
|
39
|
+
getLocaleContext,
|
|
40
|
+
type LocaleContext
|
|
41
|
+
} from './i18n/localeContext.svelte';
|
|
42
|
+
|
|
30
43
|
// Full-screen states a host app renders
|
|
31
44
|
export { default as ErrorScreen } from './components/ErrorScreen.svelte';
|
|
32
45
|
|