@linguanahq/solid 0.1.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/package.json +29 -0
- package/src/compiler-runtime.tsx +19 -0
- package/src/index.tsx +112 -0
- package/src/styles.css +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@linguanahq/solid",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.tsx",
|
|
10
|
+
"./compiler-runtime": "./src/compiler-runtime.tsx",
|
|
11
|
+
"./styles.css": "./src/styles.css"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"check-types": "tsc --noEmit",
|
|
15
|
+
"test": "bun test"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@linguanahq/core": "0.1.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@linguana/config": "0.0.0",
|
|
22
|
+
"@linguanahq/catalog": "0.1.0",
|
|
23
|
+
"typescript": "^6",
|
|
24
|
+
"solid-js": "^1.9.10"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"solid-js": ">=1.9"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { T as LinguanaMessage, T as default } from ".";
|
|
2
|
+
|
|
3
|
+
import type { JSX } from "solid-js";
|
|
4
|
+
import { useTranslation } from ".";
|
|
5
|
+
|
|
6
|
+
export function LinguanaAttributes(props: {
|
|
7
|
+
descriptors: Array<{ name: string; id: string; defaultMessage: string }>;
|
|
8
|
+
children: (values: Record<string, string>) => JSX.Element;
|
|
9
|
+
}) {
|
|
10
|
+
const runtime = useTranslation();
|
|
11
|
+
return props.children(
|
|
12
|
+
Object.fromEntries(
|
|
13
|
+
props.descriptors.map((item) => [
|
|
14
|
+
item.name,
|
|
15
|
+
String(runtime.translate(item.id, item.defaultMessage)),
|
|
16
|
+
]),
|
|
17
|
+
),
|
|
18
|
+
);
|
|
19
|
+
}
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLinguanaClient,
|
|
3
|
+
type LinguanaClient,
|
|
4
|
+
type LinguanaClientOptions,
|
|
5
|
+
} from "@linguanahq/core";
|
|
6
|
+
import {
|
|
7
|
+
createContext,
|
|
8
|
+
createMemo,
|
|
9
|
+
createSignal,
|
|
10
|
+
For,
|
|
11
|
+
type JSX,
|
|
12
|
+
onCleanup,
|
|
13
|
+
onMount,
|
|
14
|
+
type ParentProps,
|
|
15
|
+
useContext,
|
|
16
|
+
} from "solid-js";
|
|
17
|
+
|
|
18
|
+
const LinguanaContext = createContext<LinguanaClient>();
|
|
19
|
+
|
|
20
|
+
export function LinguanaProvider(props: ParentProps<LinguanaClientOptions>) {
|
|
21
|
+
const client = createLinguanaClient(props);
|
|
22
|
+
onMount(() => void client.loadRuntimeConfig());
|
|
23
|
+
onCleanup(() => client.dispose());
|
|
24
|
+
return (
|
|
25
|
+
<LinguanaContext.Provider value={client}>
|
|
26
|
+
{props.children}
|
|
27
|
+
</LinguanaContext.Provider>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function useTranslation() {
|
|
32
|
+
const client = useContext(LinguanaContext);
|
|
33
|
+
if (!client)
|
|
34
|
+
throw new Error("useTranslation must be used within LinguanaProvider");
|
|
35
|
+
const [snapshot, setSnapshot] = createSignal(client.getSnapshot());
|
|
36
|
+
const unsubscribe = client.subscribe(() => setSnapshot(client.getSnapshot()));
|
|
37
|
+
onCleanup(unsubscribe);
|
|
38
|
+
return {
|
|
39
|
+
snapshot,
|
|
40
|
+
locale: () => snapshot().locale,
|
|
41
|
+
ready: () => snapshot().ready,
|
|
42
|
+
availableLocales: () => snapshot().availableLocales,
|
|
43
|
+
setLocale: client.setLocale,
|
|
44
|
+
t: client.t,
|
|
45
|
+
translate: client.translate,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function useLocaleOptions(query = () => "") {
|
|
50
|
+
const runtime = useTranslation();
|
|
51
|
+
const options = createMemo(() => {
|
|
52
|
+
const normalized = query().trim().toLocaleLowerCase();
|
|
53
|
+
return runtime
|
|
54
|
+
.availableLocales()
|
|
55
|
+
.filter(
|
|
56
|
+
(item) =>
|
|
57
|
+
!normalized ||
|
|
58
|
+
`${item.code} ${item.displayName} ${item.nativeName}`
|
|
59
|
+
.toLocaleLowerCase()
|
|
60
|
+
.includes(normalized),
|
|
61
|
+
)
|
|
62
|
+
.sort((a, b) => a.displayName.localeCompare(b.displayName));
|
|
63
|
+
});
|
|
64
|
+
return { ...runtime, options };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function T(props: {
|
|
68
|
+
id: string;
|
|
69
|
+
defaultMessage: string;
|
|
70
|
+
values?: Record<string, unknown>;
|
|
71
|
+
}) {
|
|
72
|
+
return useTranslation().translate(
|
|
73
|
+
props.id,
|
|
74
|
+
props.defaultMessage,
|
|
75
|
+
props.values,
|
|
76
|
+
) as JSX.Element;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function LanguageSelector(props: { label?: string; class?: string }) {
|
|
80
|
+
const [query, setQuery] = createSignal("");
|
|
81
|
+
const runtime = useLocaleOptions(query);
|
|
82
|
+
return (
|
|
83
|
+
<div class={props.class} data-linguana-language-selector="">
|
|
84
|
+
<label>
|
|
85
|
+
<span>{props.label ?? "Language"}</span>
|
|
86
|
+
<input
|
|
87
|
+
type="search"
|
|
88
|
+
value={query()}
|
|
89
|
+
onInput={(event) => setQuery(event.currentTarget.value)}
|
|
90
|
+
placeholder="Search languages"
|
|
91
|
+
/>
|
|
92
|
+
</label>
|
|
93
|
+
<select
|
|
94
|
+
aria-label={props.label ?? "Language"}
|
|
95
|
+
value={runtime.locale()}
|
|
96
|
+
disabled={!runtime.ready()}
|
|
97
|
+
onChange={(event) => void runtime.setLocale(event.currentTarget.value)}
|
|
98
|
+
>
|
|
99
|
+
<For each={runtime.options()}>
|
|
100
|
+
{(item) => (
|
|
101
|
+
<option value={item.code}>
|
|
102
|
+
{item.nativeName} — {item.displayName}
|
|
103
|
+
{item.tier === "PREVIEW" ? " (Preview)" : ""}
|
|
104
|
+
</option>
|
|
105
|
+
)}
|
|
106
|
+
</For>
|
|
107
|
+
</select>
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export type { LinguanaClient, LinguanaClientOptions } from "@linguanahq/core";
|
package/src/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "@linguanahq/core/styles.css";
|