@tooinfinity/lingua-react 1.0.0 → 1.1.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.1] - 2026-01-17
9
+
10
+ ### Fixed
11
+
12
+ - Expanded `lucide-react` peer dependency from `^0.400.0 || ^0.500.0` to `>=0.400.0` to support newer versions (e.g., 0.562.0)
13
+
14
+ ## [1.1.0] - 2026-01-17
15
+
16
+ ### Added
17
+
18
+ - **LocaleSwitcher Component** - A pre-built, accessible locale switcher with shadcn UI styling
19
+ - `dropdown` variant (default) - Button with dropdown menu for locale selection
20
+ - `buttons` variant - Inline buttons for each available locale
21
+ - `showFlag` prop - Display flag emojis alongside locale names
22
+ - `endpoint` prop - Customizable API endpoint for locale switching (default: `/locale`)
23
+ - `localeNames` prop - Override default display names for locales
24
+ - `className` prop - Additional CSS classes for styling customization
25
+ - Built-in support for 30+ languages with display names and flag emojis
26
+ - Full keyboard navigation (Arrow keys, Enter, Escape, Tab)
27
+ - ARIA labels and roles for screen reader accessibility
28
+ - Click outside to close functionality
29
+ - Dark mode support with Tailwind CSS `dark:` variants
30
+ - Smooth transitions and animations
31
+ - `LocaleSwitcherProps` type export for TypeScript users
32
+ - `lucide-react` as optional peer dependency for icons (Globe, Check, ChevronDown)
33
+
34
+ ### Changed
35
+
36
+ - Updated README.md with comprehensive LocaleSwitcher documentation
37
+ - Added Features section to README.md highlighting package capabilities
38
+
8
39
  ## [1.0.0] - 2025-01-14
9
40
 
10
41
  ### Added
package/README.md CHANGED
@@ -1,18 +1,44 @@
1
1
  # @tooinfinity/lingua-react
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@tooinfinity/lingua-react)](https://www.npmjs.com/package/@tooinfinity/lingua-react)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@tooinfinity/lingua-react)](https://www.npmjs.com/package/@tooinfinity/lingua-react)
5
+ [![npm bundle size](https://img.shields.io/bundlephobia/minzip/@tooinfinity/lingua-react)](https://bundlephobia.com/package/@tooinfinity/lingua-react)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
7
+ [![React](https://img.shields.io/badge/React-18%20%7C%2019-61DAFB.svg)](https://react.dev/)
8
+ [![License](https://img.shields.io/npm/l/@tooinfinity/lingua-react)](LICENSE.md)
9
+
3
10
  React bindings for [Laravel Lingua](https://github.com/tooinfinity/lingua) - seamless translations with Inertia.js.
4
11
 
12
+ ## Features
13
+
14
+ - 🌍 **useTranslations Hook** - Access translations with Laravel-style syntax
15
+ - 🔄 **LocaleSwitcher Component** - Beautiful, accessible locale switcher with shadcn UI styling
16
+ - 🎨 **Dark Mode Support** - Built-in dark mode with Tailwind CSS
17
+ - ⌨️ **Keyboard Navigation** - Full accessibility with ARIA support
18
+ - 🚀 **TypeScript Ready** - Complete type definitions included
19
+ - 📦 **Tree Shakeable** - Import only what you need
20
+
5
21
  ## Installation
6
22
 
7
23
  ```bash
8
24
  npm install @tooinfinity/lingua-react
9
25
  ```
10
26
 
27
+ ### Optional: Install lucide-react for icons
28
+
29
+ The `LocaleSwitcher` component uses [Lucide React](https://lucide.dev/) icons. Install it if you want to use the component:
30
+
31
+ ```bash
32
+ npm install lucide-react
33
+ ```
34
+
11
35
  ## Requirements
12
36
 
13
37
  - React 18+ or 19+
14
38
  - @inertiajs/react 1.0+ or 2.0+
15
39
  - Laravel Lingua (PHP package)
40
+ - Tailwind CSS (for LocaleSwitcher styling)
41
+ - lucide-react (optional, for LocaleSwitcher icons)
16
42
 
17
43
  ## Usage
18
44
 
@@ -34,7 +60,7 @@ function Welcome() {
34
60
  }
35
61
  ```
36
62
 
37
- ### Available Returns
63
+ ### useTranslations Hook Returns
38
64
 
39
65
  | Property | Type | Description |
40
66
  |----------|------|-------------|
@@ -51,13 +77,169 @@ Use dot notation for nested translations:
51
77
  __('messages.hello', { name: 'World' }) // "Hello World"
52
78
  ```
53
79
 
54
- ### Locale Switcher Example
80
+ ---
81
+
82
+ ## LocaleSwitcher Component
83
+
84
+ A pre-built, accessible locale switcher component with shadcn UI styling. Supports dropdown and button variants with full keyboard navigation and dark mode.
85
+
86
+ ### Basic Usage
87
+
88
+ ```tsx
89
+ import { LocaleSwitcher } from '@tooinfinity/lingua-react';
90
+
91
+ function Header() {
92
+ return (
93
+ <nav>
94
+ <LocaleSwitcher />
95
+ </nav>
96
+ );
97
+ }
98
+ ```
99
+
100
+ ### With Flags
101
+
102
+ ```tsx
103
+ <LocaleSwitcher showFlag />
104
+ ```
105
+
106
+ ### Button Variant
107
+
108
+ Display locales as inline buttons instead of a dropdown:
109
+
110
+ ```tsx
111
+ <LocaleSwitcher variant="buttons" showFlag />
112
+ ```
113
+
114
+ ### Custom Endpoint
115
+
116
+ By default, the component posts to `/locale`. Customize this:
117
+
118
+ ```tsx
119
+ <LocaleSwitcher endpoint="/api/switch-locale" />
120
+ ```
121
+
122
+ ### Custom Locale Names
123
+
124
+ Override the default display names:
125
+
126
+ ```tsx
127
+ <LocaleSwitcher
128
+ localeNames={{
129
+ en: 'English (US)',
130
+ fr: 'Français',
131
+ es: 'Español'
132
+ }}
133
+ />
134
+ ```
135
+
136
+ ### Full Example
137
+
138
+ ```tsx
139
+ import { LocaleSwitcher } from '@tooinfinity/lingua-react';
140
+
141
+ function Header() {
142
+ return (
143
+ <header className="flex items-center justify-between p-4">
144
+ <h1>My App</h1>
145
+ <LocaleSwitcher
146
+ variant="dropdown"
147
+ showFlag
148
+ endpoint="/locale"
149
+ localeNames={{
150
+ en: 'English',
151
+ fr: 'Français',
152
+ de: 'Deutsch',
153
+ }}
154
+ className="ml-auto"
155
+ />
156
+ </header>
157
+ );
158
+ }
159
+ ```
160
+
161
+ ### Props
162
+
163
+ | Prop | Type | Default | Description |
164
+ |------|------|---------|-------------|
165
+ | `variant` | `'dropdown' \| 'buttons'` | `'dropdown'` | Display style - dropdown menu or inline buttons |
166
+ | `showFlag` | `boolean` | `false` | Show flag emojis alongside locale names |
167
+ | `endpoint` | `string` | `'/locale'` | API endpoint for locale switching |
168
+ | `localeNames` | `Record<string, string>` | - | Custom display names for locales |
169
+ | `className` | `string` | - | Additional CSS classes for the root element |
170
+
171
+ ### Supported Locales
172
+
173
+ The component includes built-in display names and flags for 30+ languages:
174
+
175
+ | Code | Language | Flag |
176
+ |------|----------|------|
177
+ | `en` | English | 🇺🇸 |
178
+ | `es` | Español | 🇪🇸 |
179
+ | `fr` | Français | 🇫🇷 |
180
+ | `de` | Deutsch | 🇩🇪 |
181
+ | `it` | Italiano | 🇮🇹 |
182
+ | `pt` | Português | 🇵🇹 |
183
+ | `ja` | 日本語 | 🇯🇵 |
184
+ | `zh` | 中文 | 🇨🇳 |
185
+ | `ko` | 한국어 | 🇰🇷 |
186
+ | `ar` | العربية | 🇸🇦 |
187
+ | ... | and 20+ more | ... |
188
+
189
+ Unknown locale codes will display as uppercase (e.g., `XY` → `XY`) with a 🌐 globe flag.
190
+
191
+ ### Accessibility
192
+
193
+ The LocaleSwitcher component is built with accessibility in mind:
194
+
195
+ - ✅ Full keyboard navigation (Arrow keys, Enter, Escape, Tab)
196
+ - ✅ ARIA labels and roles (`listbox`, `option`, `aria-selected`)
197
+ - ✅ Focus management and visible focus states
198
+ - ✅ Screen reader friendly
199
+ - ✅ Click outside to close
200
+
201
+ ### Styling
202
+
203
+ The component uses Tailwind CSS classes compatible with shadcn UI's design system:
204
+
205
+ - Slate color palette for neutral tones
206
+ - Proper hover, focus, and active states
207
+ - Dark mode support via `dark:` variants
208
+ - Smooth transitions and animations
209
+
210
+ To customize the styling, you can:
211
+
212
+ 1. Pass additional classes via the `className` prop
213
+ 2. Override styles using Tailwind's utility classes
214
+ 3. Use CSS custom properties if your project supports them
215
+
216
+ ### Laravel Backend Setup
217
+
218
+ Make sure your Laravel backend has a route to handle locale switching:
219
+
220
+ ```php
221
+ // routes/web.php
222
+ Route::post('/locale', function (Request $request) {
223
+ $locale = $request->validate(['locale' => 'required|string|in:en,fr,de,es'])['locale'];
224
+
225
+ session(['locale' => $locale]);
226
+ app()->setLocale($locale);
227
+
228
+ return back();
229
+ });
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Custom Locale Switcher
235
+
236
+ If you need more control, you can build your own switcher using the hook:
55
237
 
56
238
  ```tsx
57
239
  import { useTranslations } from '@tooinfinity/lingua-react';
58
240
  import { router } from '@inertiajs/react';
59
241
 
60
- function LocaleSwitcher() {
242
+ function CustomLocaleSwitcher() {
61
243
  const { locale, locales } = useTranslations();
62
244
 
63
245
  const switchLocale = (newLocale: string) => {
@@ -76,14 +258,45 @@ function LocaleSwitcher() {
76
258
  }
77
259
  ```
78
260
 
261
+ ---
262
+
79
263
  ## TypeScript
80
264
 
81
265
  Full TypeScript support with exported types:
82
266
 
83
267
  ```tsx
84
- import type { LinguaProps, TranslateFunction } from '@tooinfinity/lingua-react';
268
+ import type {
269
+ LinguaProps,
270
+ TranslateFunction,
271
+ LocaleSwitcherProps
272
+ } from '@tooinfinity/lingua-react';
85
273
  ```
86
274
 
275
+ ### Type Definitions
276
+
277
+ ```typescript
278
+ interface LinguaProps {
279
+ locale: string;
280
+ locales: string[];
281
+ translations: Record<string, any>;
282
+ }
283
+
284
+ type TranslateFunction = (
285
+ key: string,
286
+ replacements?: Record<string, string | number>
287
+ ) => string;
288
+
289
+ interface LocaleSwitcherProps {
290
+ endpoint?: string;
291
+ className?: string;
292
+ showFlag?: boolean;
293
+ localeNames?: Record<string, string>;
294
+ variant?: 'dropdown' | 'buttons';
295
+ }
296
+ ```
297
+
298
+ ---
299
+
87
300
  ## Development
88
301
 
89
302
  ```bash
@@ -99,6 +312,7 @@ npm run build
99
312
  # Watch mode
100
313
  npm run dev
101
314
  ```
315
+
102
316
  ## License
103
317
 
104
318
  The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
@@ -0,0 +1,26 @@
1
+ import type { LocaleSwitcherProps } from '../types';
2
+ /**
3
+ * LocaleSwitcher component for switching between available locales
4
+ *
5
+ * This component uses the useTranslations hook to get the current locale
6
+ * and available locales, then provides a UI for switching between them.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * // Basic usage
11
+ * <LocaleSwitcher />
12
+ *
13
+ * // With custom endpoint and locale names
14
+ * <LocaleSwitcher
15
+ * endpoint="/api/locale"
16
+ * localeNames={{ en: 'English (US)', fr: 'French' }}
17
+ * showFlag
18
+ * />
19
+ *
20
+ * // Button variant
21
+ * <LocaleSwitcher variant="buttons" showFlag />
22
+ * ```
23
+ */
24
+ export declare function LocaleSwitcher({ endpoint, className, showFlag, localeNames, variant, }: LocaleSwitcherProps): import("react/jsx-runtime").JSX.Element | null;
25
+ export default LocaleSwitcher;
26
+ //# sourceMappingURL=LocaleSwitcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocaleSwitcher.d.ts","sourceRoot":"","sources":["../../src/components/LocaleSwitcher.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AA0DpD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,QAAoB,EACpB,SAAc,EACd,QAAgB,EAChB,WAAW,EACX,OAAoB,GACrB,EAAE,mBAAmB,kDA0RrB;AAED,eAAe,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { LocaleSwitcher } from './LocaleSwitcher';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { useTranslations } from './useTranslations';
2
- export type { LinguaProps, TranslateFunction } from './types';
2
+ export { LocaleSwitcher } from './components/LocaleSwitcher';
3
+ export type { LinguaProps, TranslateFunction, LocaleSwitcherProps } from './types';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC"}
@@ -1,2 +1,92 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("@inertiajs/react");function u(){const{props:n}=i.usePage(),e=n.lingua;return{__:(o,s)=>{const c=o.split(".");let t=e==null?void 0:e.translations;for(const r of c){if(t==null)break;t=t[r]}return typeof t!="string"?o:s?Object.entries(s).reduce((r,[l,a])=>r.replace(new RegExp(`:${l}`,"g"),String(a)),t):t},locale:(e==null?void 0:e.locale)??"en",locales:(e==null?void 0:e.locales)??["en"]}}exports.useTranslations=u;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const We=require("@inertiajs/react"),$=require("react");function Er(o){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const v in o)if(v!=="default"){const f=Object.getOwnPropertyDescriptor(o,v);Object.defineProperty(a,v,f.get?f:{enumerable:!0,get:()=>o[v]})}}return a.default=o,Object.freeze(a)}const N=Er($);function Me(){const{props:o}=We.usePage(),a=o.lingua;return{__:(f,T)=>{const g=f.split(".");let h=a==null?void 0:a.translations;for(const p of g){if(h==null)break;h=h[p]}return typeof h!="string"?f:T?Object.entries(T).reduce((p,[u,R])=>p.replace(new RegExp(`:${u}`,"g"),String(R)),h):h},locale:(a==null?void 0:a.locale)??"en",locales:(a==null?void 0:a.locales)??["en"]}}var Q={exports:{}},q={};/**
2
+ * @license React
3
+ * react-jsx-runtime.production.min.js
4
+ *
5
+ * Copyright (c) Facebook, Inc. and its affiliates.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */var Fe;function _r(){if(Fe)return q;Fe=1;var o=$,a=Symbol.for("react.element"),v=Symbol.for("react.fragment"),f=Object.prototype.hasOwnProperty,T=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,g={key:!0,ref:!0,__self:!0,__source:!0};function h(p,u,R){var m,x={},C=null,W=null;R!==void 0&&(C=""+R),u.key!==void 0&&(C=""+u.key),u.ref!==void 0&&(W=u.ref);for(m in u)f.call(u,m)&&!g.hasOwnProperty(m)&&(x[m]=u[m]);if(p&&p.defaultProps)for(m in u=p.defaultProps,u)x[m]===void 0&&(x[m]=u[m]);return{$$typeof:a,type:p,key:C,ref:W,props:x,_owner:T.current}}return q.Fragment=v,q.jsx=h,q.jsxs=h,q}var B={};/**
10
+ * @license React
11
+ * react-jsx-runtime.development.js
12
+ *
13
+ * Copyright (c) Facebook, Inc. and its affiliates.
14
+ *
15
+ * This source code is licensed under the MIT license found in the
16
+ * LICENSE file in the root directory of this source tree.
17
+ */var Ie;function Rr(){return Ie||(Ie=1,process.env.NODE_ENV!=="production"&&(function(){var o=$,a=Symbol.for("react.element"),v=Symbol.for("react.portal"),f=Symbol.for("react.fragment"),T=Symbol.for("react.strict_mode"),g=Symbol.for("react.profiler"),h=Symbol.for("react.provider"),p=Symbol.for("react.context"),u=Symbol.for("react.forward_ref"),R=Symbol.for("react.suspense"),m=Symbol.for("react.suspense_list"),x=Symbol.for("react.memo"),C=Symbol.for("react.lazy"),W=Symbol.for("react.offscreen"),l=Symbol.iterator,w="@@iterator";function D(e){if(e===null||typeof e!="object")return null;var r=l&&e[l]||e[w];return typeof r=="function"?r:null}var O=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;function E(e){{for(var r=arguments.length,t=new Array(r>1?r-1:0),n=1;n<r;n++)t[n-1]=arguments[n];J("error",e,t)}}function J(e,r,t){{var n=O.ReactDebugCurrentFrame,c=n.getStackAddendum();c!==""&&(r+="%s",t=t.concat([c]));var d=t.map(function(s){return String(s)});d.unshift("Warning: "+r),Function.prototype.apply.call(console[e],console,d)}}var z=!1,F=!1,P=!1,Ve=!1,qe=!1,ce;ce=Symbol.for("react.module.reference");function Be(e){return!!(typeof e=="string"||typeof e=="function"||e===f||e===g||qe||e===T||e===R||e===m||Ve||e===W||z||F||P||typeof e=="object"&&e!==null&&(e.$$typeof===C||e.$$typeof===x||e.$$typeof===h||e.$$typeof===p||e.$$typeof===u||e.$$typeof===ce||e.getModuleId!==void 0))}function Ke(e,r,t){var n=e.displayName;if(n)return n;var c=r.displayName||r.name||"";return c!==""?t+"("+c+")":t}function fe(e){return e.displayName||"Context"}function A(e){if(e==null)return null;if(typeof e.tag=="number"&&E("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case f:return"Fragment";case v:return"Portal";case g:return"Profiler";case T:return"StrictMode";case R:return"Suspense";case m:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case p:var r=e;return fe(r)+".Consumer";case h:var t=e;return fe(t._context)+".Provider";case u:return Ke(e,e.render,"ForwardRef");case x:var n=e.displayName||null;return n!==null?n:A(e.type)||"Memo";case C:{var c=e,d=c._payload,s=c._init;try{return A(s(d))}catch{return null}}}return null}var I=Object.assign,U=0,de,ve,pe,ge,he,be,me;function ye(){}ye.__reactDisabledLog=!0;function Je(){{if(U===0){de=console.log,ve=console.info,pe=console.warn,ge=console.error,he=console.group,be=console.groupCollapsed,me=console.groupEnd;var e={configurable:!0,enumerable:!0,value:ye,writable:!0};Object.defineProperties(console,{info:e,log:e,warn:e,error:e,group:e,groupCollapsed:e,groupEnd:e})}U++}}function ze(){{if(U--,U===0){var e={configurable:!0,enumerable:!0,writable:!0};Object.defineProperties(console,{log:I({},e,{value:de}),info:I({},e,{value:ve}),warn:I({},e,{value:pe}),error:I({},e,{value:ge}),group:I({},e,{value:he}),groupCollapsed:I({},e,{value:be}),groupEnd:I({},e,{value:me})})}U<0&&E("disabledDepth fell below zero. This is a bug in React. Please file an issue.")}}var ee=O.ReactCurrentDispatcher,re;function G(e,r,t){{if(re===void 0)try{throw Error()}catch(c){var n=c.stack.trim().match(/\n( *(at )?)/);re=n&&n[1]||""}return`
18
+ `+re+e}}var te=!1,X;{var Ge=typeof WeakMap=="function"?WeakMap:Map;X=new Ge}function Ee(e,r){if(!e||te)return"";{var t=X.get(e);if(t!==void 0)return t}var n;te=!0;var c=Error.prepareStackTrace;Error.prepareStackTrace=void 0;var d;d=ee.current,ee.current=null,Je();try{if(r){var s=function(){throw Error()};if(Object.defineProperty(s.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(s,[])}catch(j){n=j}Reflect.construct(e,[],s)}else{try{s.call()}catch(j){n=j}e.call(s.prototype)}}else{try{throw Error()}catch(j){n=j}e()}}catch(j){if(j&&n&&typeof j.stack=="string"){for(var i=j.stack.split(`
19
+ `),k=n.stack.split(`
20
+ `),b=i.length-1,y=k.length-1;b>=1&&y>=0&&i[b]!==k[y];)y--;for(;b>=1&&y>=0;b--,y--)if(i[b]!==k[y]){if(b!==1||y!==1)do if(b--,y--,y<0||i[b]!==k[y]){var S=`
21
+ `+i[b].replace(" at new "," at ");return e.displayName&&S.includes("<anonymous>")&&(S=S.replace("<anonymous>",e.displayName)),typeof e=="function"&&X.set(e,S),S}while(b>=1&&y>=0);break}}}finally{te=!1,ee.current=d,ze(),Error.prepareStackTrace=c}var Y=e?e.displayName||e.name:"",L=Y?G(Y):"";return typeof e=="function"&&X.set(e,L),L}function Xe(e,r,t){return Ee(e,!1)}function He(e){var r=e.prototype;return!!(r&&r.isReactComponent)}function H(e,r,t){if(e==null)return"";if(typeof e=="function")return Ee(e,He(e));if(typeof e=="string")return G(e);switch(e){case R:return G("Suspense");case m:return G("SuspenseList")}if(typeof e=="object")switch(e.$$typeof){case u:return Xe(e.render);case x:return H(e.type,r,t);case C:{var n=e,c=n._payload,d=n._init;try{return H(d(c),r,t)}catch{}}}return""}var V=Object.prototype.hasOwnProperty,_e={},Re=O.ReactDebugCurrentFrame;function Z(e){if(e){var r=e._owner,t=H(e.type,e._source,r?r.type:null);Re.setExtraStackFrame(t)}else Re.setExtraStackFrame(null)}function Ze(e,r,t,n,c){{var d=Function.call.bind(V);for(var s in e)if(d(e,s)){var i=void 0;try{if(typeof e[s]!="function"){var k=Error((n||"React class")+": "+t+" type `"+s+"` is invalid; it must be a function, usually from the `prop-types` package, but received `"+typeof e[s]+"`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.");throw k.name="Invariant Violation",k}i=e[s](r,s,n,t,null,"SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED")}catch(b){i=b}i&&!(i instanceof Error)&&(Z(c),E("%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).",n||"React class",t,s,typeof i),Z(null)),i instanceof Error&&!(i.message in _e)&&(_e[i.message]=!0,Z(c),E("Failed %s type: %s",t,i.message),Z(null))}}}var Qe=Array.isArray;function ae(e){return Qe(e)}function er(e){{var r=typeof Symbol=="function"&&Symbol.toStringTag,t=r&&e[Symbol.toStringTag]||e.constructor.name||"Object";return t}}function rr(e){try{return ke(e),!1}catch{return!0}}function ke(e){return""+e}function xe(e){if(rr(e))return E("The provided key is an unsupported type %s. This value must be coerced to a string before before using it here.",er(e)),ke(e)}var we=O.ReactCurrentOwner,tr={key:!0,ref:!0,__self:!0,__source:!0},je,Te;function ar(e){if(V.call(e,"ref")){var r=Object.getOwnPropertyDescriptor(e,"ref").get;if(r&&r.isReactWarning)return!1}return e.ref!==void 0}function nr(e){if(V.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function or(e,r){typeof e.ref=="string"&&we.current}function ir(e,r){{var t=function(){je||(je=!0,E("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)",r))};t.isReactWarning=!0,Object.defineProperty(e,"key",{get:t,configurable:!0})}}function sr(e,r){{var t=function(){Te||(Te=!0,E("%s: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)",r))};t.isReactWarning=!0,Object.defineProperty(e,"ref",{get:t,configurable:!0})}}var lr=function(e,r,t,n,c,d,s){var i={$$typeof:a,type:e,key:r,ref:t,props:s,_owner:d};return i._store={},Object.defineProperty(i._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:!1}),Object.defineProperty(i,"_self",{configurable:!1,enumerable:!1,writable:!1,value:n}),Object.defineProperty(i,"_source",{configurable:!1,enumerable:!1,writable:!1,value:c}),Object.freeze&&(Object.freeze(i.props),Object.freeze(i)),i};function ur(e,r,t,n,c){{var d,s={},i=null,k=null;t!==void 0&&(xe(t),i=""+t),nr(r)&&(xe(r.key),i=""+r.key),ar(r)&&(k=r.ref,or(r,c));for(d in r)V.call(r,d)&&!tr.hasOwnProperty(d)&&(s[d]=r[d]);if(e&&e.defaultProps){var b=e.defaultProps;for(d in b)s[d]===void 0&&(s[d]=b[d])}if(i||k){var y=typeof e=="function"?e.displayName||e.name||"Unknown":e;i&&ir(s,y),k&&sr(s,y)}return lr(e,i,k,c,n,we.current,s)}}var ne=O.ReactCurrentOwner,Se=O.ReactDebugCurrentFrame;function M(e){if(e){var r=e._owner,t=H(e.type,e._source,r?r.type:null);Se.setExtraStackFrame(t)}else Se.setExtraStackFrame(null)}var oe;oe=!1;function ie(e){return typeof e=="object"&&e!==null&&e.$$typeof===a}function Oe(){{if(ne.current){var e=A(ne.current.type);if(e)return`
22
+
23
+ Check the render method of \``+e+"`."}return""}}function cr(e){return""}var Ce={};function fr(e){{var r=Oe();if(!r){var t=typeof e=="string"?e:e.displayName||e.name;t&&(r=`
24
+
25
+ Check the top-level render call using <`+t+">.")}return r}}function Pe(e,r){{if(!e._store||e._store.validated||e.key!=null)return;e._store.validated=!0;var t=fr(r);if(Ce[t])return;Ce[t]=!0;var n="";e&&e._owner&&e._owner!==ne.current&&(n=" It was passed a child from "+A(e._owner.type)+"."),M(e),E('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.',t,n),M(null)}}function De(e,r){{if(typeof e!="object")return;if(ae(e))for(var t=0;t<e.length;t++){var n=e[t];ie(n)&&Pe(n,r)}else if(ie(e))e._store&&(e._store.validated=!0);else if(e){var c=D(e);if(typeof c=="function"&&c!==e.entries)for(var d=c.call(e),s;!(s=d.next()).done;)ie(s.value)&&Pe(s.value,r)}}}function dr(e){{var r=e.type;if(r==null||typeof r=="string")return;var t;if(typeof r=="function")t=r.propTypes;else if(typeof r=="object"&&(r.$$typeof===u||r.$$typeof===x))t=r.propTypes;else return;if(t){var n=A(r);Ze(t,e.props,"prop",n,e)}else if(r.PropTypes!==void 0&&!oe){oe=!0;var c=A(r);E("Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?",c||"Unknown")}typeof r.getDefaultProps=="function"&&!r.getDefaultProps.isReactClassApproved&&E("getDefaultProps is only used on classic React.createClass definitions. Use a static property named `defaultProps` instead.")}}function vr(e){{for(var r=Object.keys(e.props),t=0;t<r.length;t++){var n=r[t];if(n!=="children"&&n!=="key"){M(e),E("Invalid prop `%s` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.",n),M(null);break}}e.ref!==null&&(M(e),E("Invalid attribute `ref` supplied to `React.Fragment`."),M(null))}}var Ae={};function $e(e,r,t,n,c,d){{var s=Be(e);if(!s){var i="";(e===void 0||typeof e=="object"&&e!==null&&Object.keys(e).length===0)&&(i+=" You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.");var k=cr();k?i+=k:i+=Oe();var b;e===null?b="null":ae(e)?b="array":e!==void 0&&e.$$typeof===a?(b="<"+(A(e.type)||"Unknown")+" />",i=" Did you accidentally export a JSX literal instead of a component?"):b=typeof e,E("React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s",b,i)}var y=ur(e,r,t,c,d);if(y==null)return y;if(s){var S=r.children;if(S!==void 0)if(n)if(ae(S)){for(var Y=0;Y<S.length;Y++)De(S[Y],e);Object.freeze&&Object.freeze(S)}else E("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else De(S,e)}if(V.call(r,"key")){var L=A(e),j=Object.keys(r).filter(function(yr){return yr!=="key"}),se=j.length>0?"{key: someKey, "+j.join(": ..., ")+": ...}":"{key: someKey}";if(!Ae[L+se]){var mr=j.length>0?"{"+j.join(": ..., ")+": ...}":"{}";E(`A props object containing a "key" prop is being spread into JSX:
26
+ let props = %s;
27
+ <%s {...props} />
28
+ React keys must be passed directly to JSX without using spread:
29
+ let props = %s;
30
+ <%s key={someKey} {...props} />`,se,L,mr,L),Ae[L+se]=!0}}return e===f?vr(y):dr(y),y}}function pr(e,r,t){return $e(e,r,t,!0)}function gr(e,r,t){return $e(e,r,t,!1)}var hr=gr,br=pr;B.Fragment=f,B.jsx=hr,B.jsxs=br})()),B}var Le;function kr(){return Le||(Le=1,process.env.NODE_ENV==="production"?Q.exports=_r():Q.exports=Rr()),Q.exports}var _=kr();/**
31
+ * @license lucide-react v0.511.0 - ISC
32
+ *
33
+ * This source code is licensed under the ISC license.
34
+ * See the LICENSE file in the root directory of this source tree.
35
+ */const xr=o=>o.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),wr=o=>o.replace(/^([A-Z])|[\s-_]+(\w)/g,(a,v,f)=>f?f.toUpperCase():v.toLowerCase()),Ne=o=>{const a=wr(o);return a.charAt(0).toUpperCase()+a.slice(1)},Ye=(...o)=>o.filter((a,v,f)=>!!a&&a.trim()!==""&&f.indexOf(a)===v).join(" ").trim(),jr=o=>{for(const a in o)if(a.startsWith("aria-")||a==="role"||a==="title")return!0};/**
36
+ * @license lucide-react v0.511.0 - ISC
37
+ *
38
+ * This source code is licensed under the ISC license.
39
+ * See the LICENSE file in the root directory of this source tree.
40
+ */var Tr={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/**
41
+ * @license lucide-react v0.511.0 - ISC
42
+ *
43
+ * This source code is licensed under the ISC license.
44
+ * See the LICENSE file in the root directory of this source tree.
45
+ */const Sr=$.forwardRef(({color:o="currentColor",size:a=24,strokeWidth:v=2,absoluteStrokeWidth:f,className:T="",children:g,iconNode:h,...p},u)=>$.createElement("svg",{ref:u,...Tr,width:a,height:a,stroke:o,strokeWidth:f?Number(v)*24/Number(a):v,className:Ye("lucide",T),...!g&&!jr(p)&&{"aria-hidden":"true"},...p},[...h.map(([R,m])=>$.createElement(R,m)),...Array.isArray(g)?g:[g]]));/**
46
+ * @license lucide-react v0.511.0 - ISC
47
+ *
48
+ * This source code is licensed under the ISC license.
49
+ * See the LICENSE file in the root directory of this source tree.
50
+ */const ue=(o,a)=>{const v=$.forwardRef(({className:f,...T},g)=>$.createElement(Sr,{ref:g,iconNode:a,className:Ye(`lucide-${xr(Ne(o))}`,`lucide-${o}`,f),...T}));return v.displayName=Ne(o),v};/**
51
+ * @license lucide-react v0.511.0 - ISC
52
+ *
53
+ * This source code is licensed under the ISC license.
54
+ * See the LICENSE file in the root directory of this source tree.
55
+ */const Or=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],Cr=ue("check",Or);/**
56
+ * @license lucide-react v0.511.0 - ISC
57
+ *
58
+ * This source code is licensed under the ISC license.
59
+ * See the LICENSE file in the root directory of this source tree.
60
+ */const Pr=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],Dr=ue("chevron-down",Pr);/**
61
+ * @license lucide-react v0.511.0 - ISC
62
+ *
63
+ * This source code is licensed under the ISC license.
64
+ * See the LICENSE file in the root directory of this source tree.
65
+ */const Ar=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]],$r=ue("globe",Ar),Ue={en:{name:"English",flag:"🇺🇸"},es:{name:"Español",flag:"🇪🇸"},fr:{name:"Français",flag:"🇫🇷"},de:{name:"Deutsch",flag:"🇩🇪"},it:{name:"Italiano",flag:"🇮🇹"},pt:{name:"Português",flag:"🇵🇹"},nl:{name:"Nederlands",flag:"🇳🇱"},pl:{name:"Polski",flag:"🇵🇱"},ru:{name:"Русский",flag:"🇷🇺"},ja:{name:"日本語",flag:"🇯🇵"},zh:{name:"中文",flag:"🇨🇳"},ko:{name:"한국어",flag:"🇰🇷"},ar:{name:"العربية",flag:"🇸🇦"},hi:{name:"हिन्दी",flag:"🇮🇳"},tr:{name:"Türkçe",flag:"🇹🇷"},vi:{name:"Tiếng Việt",flag:"🇻🇳"},th:{name:"ไทย",flag:"🇹🇭"},sv:{name:"Svenska",flag:"🇸🇪"},da:{name:"Dansk",flag:"🇩🇰"},fi:{name:"Suomi",flag:"🇫🇮"},no:{name:"Norsk",flag:"🇳🇴"},cs:{name:"Čeština",flag:"🇨🇿"},uk:{name:"Українська",flag:"🇺🇦"},el:{name:"Ελληνικά",flag:"🇬🇷"},he:{name:"עברית",flag:"🇮🇱"},id:{name:"Bahasa Indonesia",flag:"🇮🇩"},ms:{name:"Bahasa Melayu",flag:"🇲🇾"},ro:{name:"Română",flag:"🇷🇴"},hu:{name:"Magyar",flag:"🇭🇺"},bg:{name:"Български",flag:"🇧🇬"}};function K(o,a){var v;return a!=null&&a[o]?a[o]:((v=Ue[o])==null?void 0:v.name)??o.toUpperCase()}function le(o){var a;return((a=Ue[o])==null?void 0:a.flag)??"🌐"}function Fr({endpoint:o="/locale",className:a="",showFlag:v=!1,localeNames:f,variant:T="dropdown"}){const{locale:g,locales:h}=Me(),[p,u]=N.useState(!1),R=N.useRef(null),m=N.useRef(null),x=N.useCallback(l=>{if(l===g){u(!1);return}We.router.post(o,{locale:l},{preserveState:!0,preserveScroll:!0,onSuccess:()=>{u(!1)}})},[g,o]);N.useEffect(()=>{function l(w){R.current&&!R.current.contains(w.target)&&u(!1)}if(p)return document.addEventListener("mousedown",l),()=>document.removeEventListener("mousedown",l)},[p]);const C=N.useCallback(l=>{var w;switch(l.key){case"Escape":u(!1),(w=m.current)==null||w.focus();break;case"ArrowDown":l.preventDefault(),p||u(!0);break;case"ArrowUp":l.preventDefault();break;case"Enter":case" ":p||(l.preventDefault(),u(!0));break}},[p]),W=N.useCallback((l,w,D)=>{var O,E,J,z;switch(l.key){case"Enter":case" ":l.preventDefault(),x(w);break;case"ArrowDown":l.preventDefault();{const F=D+1;if(F<h.length){const P=(O=R.current)==null?void 0:O.querySelector(`[data-locale-index="${F}"]`);P==null||P.focus()}}break;case"ArrowUp":l.preventDefault();{const F=D-1;if(F>=0){const P=(E=R.current)==null?void 0:E.querySelector(`[data-locale-index="${F}"]`);P==null||P.focus()}else(J=m.current)==null||J.focus(),u(!1)}break;case"Escape":u(!1),(z=m.current)==null||z.focus();break;case"Tab":u(!1);break}},[x,h.length]);return h.length<=1?null:T==="buttons"?_.jsx("div",{className:`inline-flex items-center gap-1 rounded-lg border border-slate-200 bg-white p-1 dark:border-slate-700 dark:bg-slate-800 ${a}`,role:"group","aria-label":"Language selection",children:h.map(l=>{const w=l===g;return _.jsxs("button",{type:"button",onClick:()=>x(l),className:`
66
+ inline-flex items-center justify-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium
67
+ transition-all duration-150
68
+ focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2
69
+ dark:focus:ring-slate-500 dark:focus:ring-offset-slate-800
70
+ ${w?"bg-slate-900 text-white shadow-sm dark:bg-slate-100 dark:text-slate-900":"text-slate-600 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-700 dark:hover:text-slate-100"}
71
+ `,"aria-pressed":w,"aria-label":`Switch to ${K(l,f)}`,children:[v&&_.jsx("span",{className:"text-base","aria-hidden":"true",children:le(l)}),_.jsx("span",{children:K(l,f)})]},l)})}):_.jsxs("div",{ref:R,className:`relative inline-block text-left ${a}`,children:[_.jsxs("button",{ref:m,type:"button",onClick:()=>u(!p),onKeyDown:C,className:`
72
+ inline-flex items-center justify-center gap-2 rounded-md border border-slate-200 bg-white
73
+ px-3 py-2 text-sm font-medium text-slate-700 shadow-sm
74
+ transition-all duration-150
75
+ hover:bg-slate-50 hover:text-slate-900
76
+ focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2
77
+ dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300
78
+ dark:hover:bg-slate-700 dark:hover:text-slate-100
79
+ dark:focus:ring-slate-500 dark:focus:ring-offset-slate-900
80
+ `,"aria-haspopup":"listbox","aria-expanded":p,"aria-label":`Current language: ${K(g,f)}. Click to change language.`,children:[v?_.jsx("span",{className:"text-base","aria-hidden":"true",children:le(g)}):_.jsx($r,{className:"h-4 w-4","aria-hidden":"true"}),_.jsx("span",{children:K(g,f)}),_.jsx(Dr,{className:`h-4 w-4 transition-transform duration-200 ${p?"rotate-180":""}`,"aria-hidden":"true"})]}),p&&_.jsx("div",{className:`
81
+ absolute right-0 z-50 mt-2 min-w-[160px] origin-top-right
82
+ rounded-md border border-slate-200 bg-white shadow-lg
83
+ ring-1 ring-black ring-opacity-5
84
+ dark:border-slate-700 dark:bg-slate-800
85
+ animate-in fade-in-0 zoom-in-95
86
+ `,role:"listbox","aria-label":"Available languages","aria-activedescendant":`locale-option-${g}`,children:_.jsx("div",{className:"py-1",children:h.map((l,w)=>{const D=l===g;return _.jsxs("button",{id:`locale-option-${l}`,type:"button",role:"option","aria-selected":D,"data-locale-index":w,onClick:()=>x(l),onKeyDown:O=>W(O,l,w),className:`
87
+ flex w-full items-center justify-between gap-2 px-3 py-2 text-sm
88
+ transition-colors duration-150
89
+ focus:outline-none focus:bg-slate-100 dark:focus:bg-slate-700
90
+ ${D?"bg-slate-50 text-slate-900 dark:bg-slate-700/50 dark:text-slate-100":"text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-300 dark:hover:bg-slate-700 dark:hover:text-slate-100"}
91
+ `,children:[_.jsxs("span",{className:"flex items-center gap-2",children:[v&&_.jsx("span",{className:"text-base","aria-hidden":"true",children:le(l)}),_.jsx("span",{children:K(l,f)})]}),D&&_.jsx(Cr,{className:"h-4 w-4 text-slate-600 dark:text-slate-400","aria-hidden":"true"})]},l)})})})]})}exports.LocaleSwitcher=Fr;exports.useTranslations=Me;
2
92
  //# sourceMappingURL=lingua-react.cjs.map