@huliiiiii/lingui-solid 6.0.0-next.3

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/README.md ADDED
@@ -0,0 +1,25 @@
1
+ [![License][badge-license]][license]
2
+ [![Version][badge-version]][package]
3
+ [![Downloads][badge-downloads]][package]
4
+
5
+ # @huliiiiii/lingui-solid
6
+
7
+ > SolidJS components for internationalization
8
+
9
+ `@huliiiiii/lingui-solid` is part of [LinguiJS][linguijs]. See the [documentation][documentation] for all information, tutorials and examples.
10
+
11
+ ## Installation & Usage
12
+
13
+ See the [documentation][documentation].
14
+
15
+ ## License
16
+
17
+ [MIT][license]
18
+
19
+ [license]: https://github.com/lingui/js-lingui/blob/main/LICENSE
20
+ [linguijs]: https://github.com/lingui/js-lingui
21
+ [documentation]: https://lingui.dev
22
+ [package]: https://www.npmjs.com/package/@huliiiiii/lingui-solid
23
+ [badge-downloads]: https://img.shields.io/npm/dw/@huliiiiii/lingui-solid.svg
24
+ [badge-version]: https://img.shields.io/npm/v/@huliiiiii/lingui-solid.svg
25
+ [badge-license]: https://img.shields.io/npm/l/@huliiiiii/lingui-solid.svg
@@ -0,0 +1,6 @@
1
+ import { LinguiConfig } from '@lingui/conf';
2
+ export { LinguiConfig } from '@lingui/conf';
3
+
4
+ declare function defineConfig(config: LinguiConfig): LinguiConfig;
5
+
6
+ export { defineConfig };
@@ -0,0 +1,31 @@
1
+ import { defineConfig as defineConfig$1 } from '@lingui/conf';
2
+
3
+ const solidRuntimeModules = {
4
+ Trans: ["@huliiiiii/lingui-solid", "Trans"],
5
+ useLingui: ["@huliiiiii/lingui-solid", "useLingui"]
6
+ };
7
+ function defineConfig(config) {
8
+ const {
9
+ runtimeConfigModule,
10
+ macro,
11
+ ...rest
12
+ } = config;
13
+ const runtimeConfig = Array.isArray(runtimeConfigModule) ? {
14
+ i18n: runtimeConfigModule
15
+ } : runtimeConfigModule;
16
+ const jsxPackage = macro?.jsxPackage ? Array.from([...macro.jsxPackage, "@huliiiiii/lingui-solid/macro"]) : ["@huliiiiii/lingui-solid/macro"];
17
+ return defineConfig$1({
18
+ ...rest,
19
+ macro: {
20
+ ...macro,
21
+ jsxPackage,
22
+ jsxRuntime: macro?.jsxRuntime ?? "solid"
23
+ },
24
+ runtimeConfigModule: {
25
+ ...solidRuntimeModules,
26
+ ...runtimeConfig
27
+ }
28
+ });
29
+ }
30
+
31
+ export { defineConfig };
@@ -0,0 +1,43 @@
1
+ import * as solid_js from 'solid-js';
2
+ import { JSXElement, ParentComponent, Component, Accessor, ParentProps } from 'solid-js';
3
+ import { MessageOptions, I18n } from '@lingui/core';
4
+
5
+ type TransRenderProps = {
6
+ id: string;
7
+ translation: JSXElement;
8
+ children: JSXElement;
9
+ message?: string | null;
10
+ };
11
+ type TransRenderCallbackOrComponent = {
12
+ component?: never;
13
+ render?: ((props: TransRenderProps) => JSXElement) | null;
14
+ } | {
15
+ component?: Component<TransRenderProps> | null;
16
+ render?: never;
17
+ };
18
+ type TransProps = {
19
+ id: string;
20
+ message?: string;
21
+ values?: Record<string, unknown>;
22
+ components?: Record<string, ParentComponent>;
23
+ formats?: MessageOptions["formats"];
24
+ comment?: string;
25
+ } & TransRenderCallbackOrComponent;
26
+
27
+ type I18nContext = {
28
+ i18n: Accessor<I18n>;
29
+ _: I18n["_"];
30
+ defaultComponent?: Accessor<Component<TransRenderProps> | undefined>;
31
+ };
32
+ type I18nProviderProps = ParentProps<{
33
+ i18n: I18n;
34
+ defaultComponent?: Component<TransRenderProps>;
35
+ }>;
36
+ declare const LinguiContext: solid_js.Context<I18nContext | null>;
37
+ declare function useLingui(): I18nContext;
38
+ declare function I18nProvider(props: I18nProviderProps): JSXElement;
39
+
40
+ declare function Trans(props: TransProps): JSXElement;
41
+
42
+ export { I18nProvider, LinguiContext, Trans, useLingui };
43
+ export type { I18nContext, I18nProviderProps, TransProps, TransRenderCallbackOrComponent, TransRenderProps };
package/dist/index.mjs ADDED
@@ -0,0 +1,214 @@
1
+ import { createComponent, memo, mergeProps } from 'solid-js/web';
2
+ import { createContext, createSignal, createMemo, createEffect, on, onCleanup, Show, useContext, createComponent as createComponent$1 } from 'solid-js';
3
+
4
+ const LinguiContext = createContext(null);
5
+ const useLinguiInternal = devErrorMessage => {
6
+ const context = useContext(LinguiContext);
7
+ if (process.env.NODE_ENV !== "production" && context == null) {
8
+ throw new Error(devErrorMessage ?? "useLingui hook was used without I18nProvider.");
9
+ }
10
+ return context;
11
+ };
12
+ function useLingui() {
13
+ return useLinguiInternal();
14
+ }
15
+ function I18nProvider(props) {
16
+ const [latestKnownLocale, setLatestKnownLocale] = createSignal(props.i18n.locale || null);
17
+ const [i18nSignal, setI18nSignal] = createSignal(props.i18n, {
18
+ equals: false
19
+ });
20
+ const defaultComponent = createMemo(() => props.defaultComponent);
21
+ const translate = (...args) => {
22
+ const i18n = i18nSignal();
23
+ return i18n.t(...args);
24
+ };
25
+ const context = {
26
+ i18n: i18nSignal,
27
+ _: translate,
28
+ defaultComponent
29
+ };
30
+ createEffect(on(() => props.i18n, (i18n, previousI18n) => {
31
+ const previousKnownI18n = previousI18n ?? i18n;
32
+ const contextNeedsUpdate = () => previousKnownI18n !== i18n || latestKnownLocale() !== i18n.locale;
33
+ const updateContext = () => {
34
+ setLatestKnownLocale(i18n.locale || null);
35
+ setI18nSignal(() => i18n);
36
+ };
37
+ const unsubscribe = i18n.on("change", updateContext);
38
+ if (contextNeedsUpdate()) {
39
+ updateContext();
40
+ }
41
+ onCleanup(unsubscribe);
42
+ }));
43
+ const RenderFallback = () => {
44
+ if (process.env.NODE_ENV === "development") {
45
+ console.log("I18nProvider rendered `null`. A call to `i18n.activate` needs to happen in order for translations to be activated and for the I18nProvider to render.This is not an error but an informational message logged only in development.");
46
+ }
47
+ return null;
48
+ };
49
+ return createComponent(Show, {
50
+ get when() {
51
+ return latestKnownLocale() !== null;
52
+ },
53
+ get fallback() {
54
+ return createComponent(RenderFallback, {});
55
+ },
56
+ get children() {
57
+ return createComponent(LinguiContext.Provider, {
58
+ value: context,
59
+ get children() {
60
+ return props.children;
61
+ }
62
+ });
63
+ }
64
+ });
65
+ }
66
+
67
+ const tagRe = /<([a-zA-Z0-9]+)>([\s\S]*?)<\/\1>|<([a-zA-Z0-9]+)\/>/;
68
+ function formatElements(value, elements = {}) {
69
+ const parts = value.split(tagRe);
70
+ if (parts.length === 1) return value;
71
+ const tree = [];
72
+ const before = parts.shift();
73
+ if (before) tree.push(before);
74
+ for (const [index, children, after] of getElements(parts)) {
75
+ const element = index === void 0 ? void 0 : elements[index];
76
+ const formattedChildren = children ? formatElements(children, elements) : void 0;
77
+ if (!element) {
78
+ console.error(`Can't use element at index '${index}' as it is not declared in the original translation`);
79
+ if (formattedChildren !== void 0) {
80
+ tree.push(formattedChildren);
81
+ }
82
+ } else {
83
+ tree.push(createComponent$1(element, {
84
+ children: formattedChildren
85
+ }));
86
+ }
87
+ if (after) tree.push(after);
88
+ }
89
+ return tree.length === 1 ? tree[0] : tree;
90
+ }
91
+ function getElements(parts) {
92
+ if (!parts.length) return [];
93
+ const [paired, children, unpaired, after] = parts.slice(0, 4);
94
+ const triple = [paired || unpaired, children || "", after];
95
+ return [triple].concat(getElements(parts.slice(4, parts.length)));
96
+ }
97
+
98
+ function TransNoContext(props) {
99
+ const translation = createMemo(() => {
100
+ const {
101
+ values,
102
+ components
103
+ } = getInterpolationValuesAndComponents(props);
104
+ const i18n = props.lingui.i18n();
105
+ const _translation = i18n != null && typeof i18n._ === "function" ? i18n._(props.id, values, {
106
+ message: props.message,
107
+ formats: props.formats
108
+ }) : props.id;
109
+ const translation2 = _translation ? formatElements(_translation, components) : null;
110
+ return translation2;
111
+ });
112
+ const FallbackComponent = createMemo(() => {
113
+ return props.lingui.defaultComponent?.() || RenderChildren;
114
+ });
115
+ const i18nProps = {
116
+ get id() {
117
+ return props.id;
118
+ },
119
+ get message() {
120
+ return props.message;
121
+ },
122
+ get translation() {
123
+ return translation();
124
+ },
125
+ get children() {
126
+ return translation();
127
+ }
128
+ };
129
+ createEffect(() => {
130
+ const render = props.render;
131
+ const component = props.component;
132
+ if (render && component) {
133
+ console.error("You can't use both `component` and `render` prop at the same time. `component` is ignored.");
134
+ } else if (render && typeof render !== "function") {
135
+ console.error(`Invalid value supplied to prop \`render\`. It must be a function, provided ${render}`);
136
+ } else if (component && typeof component !== "function") {
137
+ console.error(`Invalid value supplied to prop \`component\`. It must be a Solid component, provided ${component}`);
138
+ }
139
+ });
140
+ const renderPropOutput = createMemo(() => {
141
+ if (typeof props.render === "function") {
142
+ return props.render(i18nProps);
143
+ }
144
+ return null;
145
+ });
146
+ const Component = createMemo(() => {
147
+ if (props.component && typeof props.component !== "function") {
148
+ return FallbackComponent();
149
+ }
150
+ return props.component || FallbackComponent();
151
+ });
152
+ const content = createMemo(() => {
153
+ if (props.render === null || props.component === null) {
154
+ return translation();
155
+ }
156
+ if (typeof props.render === "function") {
157
+ return renderPropOutput();
158
+ }
159
+ return createComponent$1(Component(), i18nProps);
160
+ });
161
+ return memo(content);
162
+ }
163
+ const RenderChildren = props => {
164
+ return memo(() => props.children);
165
+ };
166
+ const getInterpolationValuesAndComponents = props => {
167
+ if (!props.values) {
168
+ return {
169
+ values: void 0,
170
+ components: props.components
171
+ };
172
+ }
173
+ const values = {
174
+ ...props.values
175
+ };
176
+ const components = {
177
+ ...props.components
178
+ };
179
+ Object.entries(props.values).forEach(([key, valueForKey]) => {
180
+ if (typeof valueForKey === "string" || typeof valueForKey === "number") {
181
+ return;
182
+ }
183
+ if (valueForKey == null || typeof valueForKey === "boolean") {
184
+ values[key] = "";
185
+ return;
186
+ }
187
+ const index = Object.keys(components).length;
188
+ components[index] = () => valueForKey;
189
+ values[key] = `<${index}/>`;
190
+ });
191
+ return {
192
+ values,
193
+ components
194
+ };
195
+ };
196
+
197
+ function Trans(props) {
198
+ let errMessage = void 0;
199
+ if (process.env.NODE_ENV !== "production") {
200
+ errMessage = `Trans component was rendered without I18nProvider.
201
+ Attempted to render message: ${props.message} id: ${props.id}. Make sure this component is rendered inside a I18nProvider.`;
202
+ }
203
+ const lingui = useLinguiInternal(errMessage);
204
+ return createComponent(TransNoContext, mergeProps(props, {
205
+ get lingui() {
206
+ return {
207
+ i18n: lingui.i18n,
208
+ defaultComponent: lingui.defaultComponent
209
+ };
210
+ }
211
+ }));
212
+ }
213
+
214
+ export { I18nProvider, LinguiContext, Trans, useLingui };
@@ -0,0 +1,11 @@
1
+ export const Trans = function () {}
2
+ export const Plural = function () {}
3
+ export const Select = function () {}
4
+ export const SelectOrdinal = function () {}
5
+ export const useLingui = function () {}
6
+
7
+ throw new Error(
8
+ `The macro you imported from "@huliiiiii/lingui-solid/macro" is being executed outside the context of compilation. \n` +
9
+ `This indicates that you don't configured correctly one of the "babel-plugin-macros" / "@lingui/swc-plugin" / "babel-plugin-lingui-macro" \n` +
10
+ "Additionally, dynamic imports — e.g., `await import('@huliiiiii/lingui-solid/macro')` — are not supported.",
11
+ )
@@ -0,0 +1,134 @@
1
+ import type { JSXElement } from "solid-js"
2
+ import type { TransRenderCallbackOrComponent, I18nContext } from "@huliiiiii/lingui-solid"
3
+ import type {
4
+ LabeledExpression,
5
+ MacroMessageDescriptor,
6
+ } from "@lingui/core/macro"
7
+
8
+ type CommonProps = TransRenderCallbackOrComponent & {
9
+ id?: string
10
+ comment?: string
11
+ context?: string
12
+ }
13
+
14
+ type TransChildren = JSXElement | LabeledExpression<string | number>
15
+ type TransProps = {
16
+ children: TransChildren | TransChildren[]
17
+ } & CommonProps
18
+
19
+ type PluralChoiceProps = {
20
+ value: string | number | LabeledExpression<string | number>
21
+ offset?: number
22
+ zero?: JSXElement
23
+ one?: JSXElement
24
+ two?: JSXElement
25
+ few?: JSXElement
26
+ many?: JSXElement
27
+ other: JSXElement
28
+ [digit: `_${number}`]: JSXElement
29
+ } & CommonProps
30
+
31
+ type SelectChoiceProps = {
32
+ value: string | LabeledExpression<string | number>
33
+ other: JSXElement
34
+ [option: `_${string}`]: JSXElement
35
+ } & CommonProps
36
+
37
+ /**
38
+ * Trans is the basic macro for static messages,
39
+ * messages with variables, but also for messages with inline markup
40
+ *
41
+ * @example
42
+ * ```
43
+ * <Trans>Hello {username}. Read the <a href="/docs">docs</a>.</Trans>
44
+ * ```
45
+ * @example
46
+ * ```
47
+ * <Trans id="custom.id">Hello {username}.</Trans>
48
+ * ```
49
+ */
50
+ export const Trans: (props: TransProps) => JSXElement
51
+
52
+ /**
53
+ * Props of Plural macro are transformed into plural format.
54
+ *
55
+ * @example
56
+ * ```
57
+ * import { Plural } from "@lingui/core/macro"
58
+ * <Plural value={numBooks} one="Book" other="Books" />
59
+ *
60
+ * // ↓ ↓ ↓ ↓ ↓ ↓
61
+ * import { Trans } from "@huliiiiii/lingui-solid"
62
+ * <Trans id="{numBooks, plural, one {Book} other {Books}}" values={{ numBooks }} />
63
+ * ```
64
+ */
65
+ export const Plural: (props: PluralChoiceProps) => JSXElement
66
+
67
+ /**
68
+ * Props of SelectOrdinal macro are transformed into selectOrdinal format.
69
+ *
70
+ * @example
71
+ * ```
72
+ * // count == 1 -> 1st
73
+ * // count == 2 -> 2nd
74
+ * // count == 3 -> 3rd
75
+ * // count == 4 -> 4th
76
+ * <SelectOrdinal
77
+ * value={count}
78
+ * one="#st"
79
+ * two="#nd"
80
+ * few="#rd"
81
+ * other="#th"
82
+ * />
83
+ * ```
84
+ */
85
+ export const SelectOrdinal: (props: PluralChoiceProps) => JSXElement
86
+
87
+ /**
88
+ * Props of Select macro are transformed into select format
89
+ *
90
+ * @example
91
+ * ```
92
+ * // gender == "female" -> Her book
93
+ * // gender == "male" -> His book
94
+ * // gender == "non-binary" -> Their book
95
+ *
96
+ * <Select
97
+ * value={gender}
98
+ * _male="His book"
99
+ * _female="Her book"
100
+ * other="Their book"
101
+ * />
102
+ * ```
103
+ */
104
+ export const Select: (props: SelectChoiceProps) => JSXElement
105
+
106
+ /**
107
+ *
108
+ * Macro version of useLingui replaces _ function with `t` macro function which is bound to i18n passed from Solid context
109
+ *
110
+ * Returned `t` macro function has all the same signatures as global `t`
111
+ *
112
+ * @example
113
+ * ```
114
+ * const { t } = useLingui();
115
+ * const message = t`Text`;
116
+ * ```
117
+ *
118
+ * @example
119
+ * ```
120
+ * const { i18n, t } = useLingui();
121
+ * const locale = i18n().locale;
122
+ * const message = t({
123
+ * id: "msg.hello",
124
+ * comment: "Greetings at the homepage",
125
+ * message: `Hello ${name}`,
126
+ * });
127
+ * ```
128
+ */
129
+ export function useLingui(): Omit<I18nContext, "_"> & {
130
+ t: {
131
+ (descriptor: MacroMessageDescriptor): string
132
+ (literals: TemplateStringsArray, ...placeholders: unknown[]): string
133
+ }
134
+ }
@@ -0,0 +1,22 @@
1
+ import babelPluginMacros from "babel-plugin-macros"
2
+ import { macro } from "@lingui/babel-plugin-lingui-macro/macro"
3
+
4
+ const { createMacro } = babelPluginMacros
5
+
6
+ export default createMacro(macro, {
7
+ configName: "lingui",
8
+ })
9
+
10
+ function printError() {
11
+ throw new Error(
12
+ `The macro you imported from "@huliiiiii/lingui-solid/macro" is being executed outside the context of compilation. \n` +
13
+ `This indicates that you don't configured correctly one of the "babel-plugin-macros" / "@lingui/swc-plugin" / "babel-plugin-lingui-macro" \n` +
14
+ "Additionally, dynamic imports — e.g., `await import('@huliiiiii/lingui-solid/macro')` — are not supported.",
15
+ )
16
+ }
17
+
18
+ export const Trans = printError
19
+ export const Plural = printError
20
+ export const Select = printError
21
+ export const SelectOrdinal = printError
22
+ export const useLingui = printError
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@huliiiiii/lingui-solid",
3
+ "version": "6.0.0-next.3",
4
+ "sideEffects": false,
5
+ "description": "SolidJS bindings for Lingui with Trans components, providers, and compile-time macros",
6
+ "type": "module",
7
+ "author": {
8
+ "name": "Huliiiiii",
9
+ "email": "308013446a@gmail.com"
10
+ },
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "lingui",
14
+ "linguijs",
15
+ "solid",
16
+ "solidjs",
17
+ "i18n",
18
+ "icu",
19
+ "messageformat",
20
+ "localization",
21
+ "translation"
22
+ ],
23
+ "scripts": {
24
+ "build": "unbuild",
25
+ "check-types": "tsc --noEmit",
26
+ "test": "vitest --run"
27
+ },
28
+ "homepage": "https://lingui.dev",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/lingui/js-lingui.git",
32
+ "directory": "packages/solid"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/lingui/js-lingui/issues"
36
+ },
37
+ "engines": {
38
+ "node": ">=22.19.0"
39
+ },
40
+ "exports": {
41
+ ".": {
42
+ "default": "./dist/index.mjs"
43
+ },
44
+ "./config": {
45
+ "types": "./dist/config.d.mts",
46
+ "default": "./dist/config.mjs"
47
+ },
48
+ "./macro": {
49
+ "browser": "./macro/browser.mjs",
50
+ "types": "./macro/index.d.mts",
51
+ "default": "./macro/index.mjs"
52
+ },
53
+ "./package.json": "./package.json"
54
+ },
55
+ "files": [
56
+ "LICENSE",
57
+ "README.md",
58
+ "dist/",
59
+ "macro/browser.mjs",
60
+ "macro/index.d.mts",
61
+ "macro/index.mjs"
62
+ ],
63
+ "peerDependencies": {
64
+ "babel-plugin-macros": "2 || 3",
65
+ "solid-js": "^1.8.0 || ^1.9.0"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "babel-plugin-macros": {
69
+ "optional": true
70
+ }
71
+ },
72
+ "dependencies": {
73
+ "@lingui/babel-plugin-lingui-macro": "6.0.0-next.3",
74
+ "@lingui/conf": "6.0.0-next.3",
75
+ "@lingui/core": "6.0.0-next.3"
76
+ },
77
+ "devDependencies": {
78
+ "@babel/core": "7.29.0",
79
+ "@lingui/test-utils": "3.0.3",
80
+ "@rollup/plugin-babel": "7.0.0",
81
+ "@solidjs/testing-library": "^0.8.10",
82
+ "babel-preset-solid": "1.9.12",
83
+ "eslint": "^9.39.3",
84
+ "happy-dom": "^20.0.10",
85
+ "solid-js": "^1.9.5",
86
+ "unbuild": "3.6.1",
87
+ "vite": "7.3.1",
88
+ "vite-plugin-solid": "^2.11.12",
89
+ "vitest": "4.0.18"
90
+ }
91
+ }