diff --git a/.editorconfig b/.editorconfig index a7c44dd..a4c879f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,7 +5,7 @@ charset = utf-8 indent_size = 4 indent_style = space end_of_line = lf -insert_final_newline = true +insert_final_newline = false trim_trailing_whitespace = true [*.md] diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index c167103..b9b1b4c 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index b20f3b6..0cdea23 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: main @@ -21,7 +21,7 @@ jobs: release-notes: ${{ github.event.release.body }} - name: Commit updated CHANGELOG - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: branch: main commit_message: Update CHANGELOG diff --git a/README.md b/README.md index f8af48c..f02dfb8 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,18 @@
-# Filament Language(Locale) Switcher +# Language(Locale) Switch -Zero config Language Switch(Changer/Localizer) plugin for Filamentphp Admin +Zero config Language Switch(Changer/Localizer) plugin for Filament Panels. -* For Filamentphp 2.x use version 1.x + +## Requirement +* [Filament v3](https://filamentphp.com/docs/3.x/panels/installation) +> [!NOTE] +> For [Filament v2](https://filamentphp.com/docs/2.x/admin/installation) use [v1](https://github.com/bezhanSalleh/filament-language-switch/tree/1.x) + + ## Installation Install the package via composer: @@ -38,61 +44,272 @@ Install the package via composer: composer require bezhansalleh/filament-language-switch ``` -Publish the config file with: +## Usage -```bash -php artisan vendor:publish --tag="filament-language-switch-config" +The plugin boots after installation automatically. For the plugin to work, provide an array of locales that your Panel(s) support to switch between them inside a service provider's `boot()` method. You can either create a new service provider or use the default `AppServiceProvider` as follow: + +```php + +... +use BezhanSalleh\FilamentLanguageSwitch\LanguageSwitch; + +class AppServiceProvider extends ServiceProvider +{ + ... + + public function boot() + { + ... + + LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch + ->locales(['ar','en','fr']); // also accepts a closure + }); + + ... + } +} ``` -Configure your preferred options and then register the plugin to your panel(s). +Though this is all you would need, but the plugin is designed to be very customizable. Delve into the **Configuration** section below for detailed customization options. -> **Note** -> You can find the supported country flag codes here [flag codes](https://flagicons.lipis.dev/) +## Configuration -Optionally, you can publish the views using +The plugin comes with following options that you can customize and configure as per your requirements. The plugin has a fluent API so you can chain the methods and easily configure it all in one place. -```bash -php artisan vendor:publish --tag="filament-language-switch-views" -``` +### Visibility Control + +The `visible()` method configures the visibility of the **Language Switch** within the application's UI. It has two parameters: + +- **insidePanels**: +Determines if the language switcher is visible inside Filament panels, which is `true` by default. The language switcher will be visible inside panels only if the `insidePanels` condition is true, more than one locale is available, and the current panel is included (not excluded). + +- **outsidePanels**: Controls visibility outside of the panels, with a default of false. The language switcher will be visible outside of panels only if the `outsidePanels` condition is true, the current route is included in the `outsidePanelRoutes()`, and the current panel is included (not excluded). + +Both arguments can be provided as a `boolean` or a `Closure` that returns a boolean value. The Closure enables dynamic determination of visibility, allowing you to incorporate complex logic based on the application state, user permissions, or other criteria. -## Plugin Usage -Using the plugin is easy all you need to do is instanciate it to the `Panels` you want the plugin to be available in. ```php -use BezhanSalleh\FilamentLanguageSwitch\FilamentLanguageSwitchPlugin; +//AppServiceProvider.php + ... + LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch + ... + ->visible(outsidePanels: true) + ...; + }); + ... +``` +### Outside Panel Routes -public function panel(Panel $panel): Panel -{ - return $panel +The `outsidePanelRoutes()` method is used to define the routes where the **Language Switch** should be visible outside of the Filament panels. This method accepts either an `array` of route names or a `Closure` that returns an array of route names. By default, it includes common authentication routes such as `auth.login`, `auth.profile`, and `auth.register`. + +To specify custom routes for displaying the language switcher, pass an array of route names to the method: + +```php +// AppServiceProvider.php +... +LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch ... - ->plugins([ - FilamentLanguageSwitchPlugin::make() + ->outsidePanelRoutes([ + 'profile', + 'home', + // Additional custom routes where the switcher should be visible outside panels ]) + ...; +}); +... +``` + +If you want to dynamically determine the routes, use a Closure: + +```php +// AppServiceProvider.php +... +LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch ... -} + ->outsidePanelRoutes(fn() => someCondition() ? ['dynamic.route'] : ['default.route']) + ...; +}); +... ``` -## Customize Render Hook -By default the switch render in the `panels::global-search.after` hook but you can render the **Language Switch** in any of the [Render Hooks](https://beta.filamentphp.com/docs/3.x/panels/configuration#render-hooks) available in Filamentphp using the `renderHookName()` method inside your panel's `plugins()` method. +### Outside Panel Placement +The `outsidePanelPlacement()` method specifies the placement of the **Language Switch** when it is rendered outside of Filament panels. This method accepts an `Placement` enum value that determines the switch's position on the screen. + +You can choose from the following placements defined in the `Placement` enum: + +* `TopLeft` default +* `TopCenter` +* `TopRight` +* `BottomLeft` +* `BottomCenter` +* `BottomRight` + +Set the desired placement for the **language switch** outside Filament Panels like this: ```php -use BezhanSalleh\FilamentLanguageSwitch\FilamentLanguageSwitchPlugin; +// AppServiceProvider.php +... +use BezhanSalleh\FilamentLanguageSwitch\Enums\Placement; -public function panel(Panel $panel): Panel -{ - return $panel +LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch ... - ->plugins([ - FilamentLanguageSwitchPlugin::make() - ->renderHookName('panels::global-search.before'), - ]) + ->outsidePanelPlacement(Placement::BottomRight) + // Sets the language switch to appear at the bottom right outside of panels + ...; +}); +... +``` +### Localized Labels +The `displayLocale()` method is used to set the locale that influences how labels for given locales are generated by PHP's native function `locale_get_display_name()`. This method specifies the language in which the labels for given locales are displayed when custom labels are not set using the `labels()` method. + +By default, if `displayLocale()` is not explicitly set, the locale labels are generated based on the application's current locale. This affects the automatic label generation for locales without custom labels. + +For example, if your application's current locale is `English ('en')`, and you have not set a specific display locale, then the labels for locales like `pt_BR` and `pt_PT` would automatically be generated as `Portuguese (Brazil)` and `Portuguese (Portugal)` respectively, in English. + +To specify a different language for the automatic label generation, use `displayLocale()`: +```php +// AppServiceProvider.php +... +LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch ... -} + ->displayLocale('fr') // Sets French as the language for label localization + ...; +}); +... +``` + +### Custom Labels + +The `labels()` method in the **Language Switch** allows you to define custom text labels for each locale that your application supports. This customization is particularly useful when the default labels generated by PHP's native function `locale_get_display_name()` are not suitable for your application's needs. + +By default, if no custom labels are provided, the **Language switch** will generate labels for each locale using the native PHP function `locale_get_display_name()`, which creates a label based on the current application's locale. For example, the locales `pt_BR` and `pt_PT` will be labeled as **Portuguese (Brazil)** and **Portuguese (Portugal)** respectively, when the application's locale is set to `en`. + +However, you might prefer to display labels that are shorter or differently formatted. This is where the `labels()` method is beneficial. You can specify exactly how each language should be labeled, overriding the default behavior. + +Here's how to set custom labels: + +```php +// AppServiceProvider.php +... +LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch + ... + ->locales(['en','fr','pt_BR','pt_PT']) + ->labels([ + 'pt_BR' => 'Português (BR)', + 'pt_PT' => 'Português (PT)', + // Other custom labels as needed + ]) + ...; +}); +... ``` -## Custom Theme -By default the plugin uses the default theme of Filamentphp, but you can customize it by adding the plugins view path into the `content` array of your `tailwind.config.js` file: +### Panel Exclusion + +By default the **Language Switch** will be available inside all existing Panels. But you can choose which panels will have the switch by providing an array of valid panel ids using the `exclude()` method. The method also accepts a `Closure` so you have more control over how to exclude certain panels. ```php +//AppServiceProvider.php + ... + LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch + ... + ->excludes([ + 'app' + ]) + ...; + }); + ... +``` + +### Render Hook + +By default the `panels::global-search.after` hook is used to render the **Language Switch**. But you can use any of the [Render Hooks](https://filamentphp.com/docs/3.x/support/render-hooks) available in Filament using the `renderHook()` method as: + +```php +//AppServiceProvider.php + ... + LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch + ... + ->renderHook('panels::global-search.before') + ...; + }); + ... +``` + +### Flags + +By default the **Language Switch** uses the locales as `Language Badges` to serve as placeholders for the flags. But you may associate each locale with its corresponding flag image by passing an array to the `flags()` method. Each key in the array represents the locale code, and its value should be the asset path to the flag image for that locale. For example, to set flag images for Arabic, French, and English (US), you would provide an array like this: + +```php +//AppServiceProvider.php + ... + LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch + ... + ->flags([ + 'ar' => asset('flags/saudi-arabia.svg'), + 'fr' => asset('flags/france.svg'), + 'en' => asset('flags/usa.svg'), + ]) + ...; + }); + ... +``` + +Make sure that the provided paths in the `asset()` helper point to the correct location of the flag images in your Laravel project's public directory. + +### Flags Only + +The `flagsOnly()` method controls whether the **Language Switch** displays only flag images, without accompanying text labels. This method can enhance the UI by providing a cleaner look when space is limited or when you prefer a more visual representation of language options. + +To display only the flags for each language, invoke the method and make sure you have provided the flags for locales just like shown above using the `flags()` method: + +```php +//AppServiceProvider.php + ... + LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch + ... + ->flags([ + 'ar' => asset('flags/saudi-arabia.svg'), + 'fr' => asset('flags/france.svg'), + 'en' => asset('flags/usa.svg'), + ]) + ->flagsOnly() + ...; + }); + ... +``` + +### Circular + +By default the **Language Switch** `Flags` or `Language Badges` are slightly rounded like the most other Filament components. But you may make it fully rounded using the `circular()` method. + +```php +//AppServiceProvider.php + ... + LanguageSwitch::configureUsing(function (LanguageSwitch $switch) { + $switch + ... + ->circular() + ...; + }); + ... +``` + +## Theme +The plugin follows Filament's theming rules. So, if you have custom themes add the plugin's view path into the `content` array of your themes' `tailwind.config.js` file: + +```php +//tailwind.config.js export default { content: [ // ... @@ -101,7 +318,17 @@ export default { // ... } ``` +... now build your theme using: +```bash +npm run build +``` + +## Views +In case you want to tweak the design, you can publish the views using the following command and adjust it however you like: +```bash +php artisan vendor:publish --tag="filament-language-switch-views" +``` ## Changelog diff --git a/config/filament-language-switch.php b/config/filament-language-switch.php deleted file mode 100644 index b4b9ffb..0000000 --- a/config/filament-language-switch.php +++ /dev/null @@ -1,333 +0,0 @@ - true, - - /* - |-------------------------------------------------------------------------- - | Flag - |-------------------------------------------------------------------------- - | - | Option to display flag for the Language. - | By default the first and second letter of the display name (if single word, otherwise first letter of first two words) will be used instead of flag. - | If set to true, the following package needs to be installed via composer. - | "composer require stijnvanouplines/blade-country-flags" - */ - - 'flag' => false, - - /* - |-------------------------------------------------------------------------- - | All Locales (Languages) - |-------------------------------------------------------------------------- - | - | Uncomment the languages that your site supports - or add new ones. - | These are sorted by the native name, which is the order you might show them in a language selector. - | - */ - - 'locales' => [ - 'ar' => ['name' => 'Arabic', 'script' => 'Arab', 'native' => 'العربية', 'flag_code' => 'sa'], - 'en' => ['name' => 'English', 'script' => 'Latn', 'native' => 'English', 'flag_code' => 'us'], - 'fr' => ['name' => 'French', 'script' => 'Latn', 'native' => 'français', 'flag_code' => 'fr'], - - // 'ace' => ['name' => 'Achinese', 'script' => 'Latn', 'native' => 'Aceh', 'flag_code' => ''], - //'af' => ['name' => 'Afrikaans', 'script' => 'Latn', 'native' => 'Afrikaans', 'flag_code' => '' ], - //'agq' => ['name' => 'Aghem', 'script' => 'Latn', 'native' => 'Aghem', 'flag_code' => '' ], - //'ak' => ['name' => 'Akan', 'script' => 'Latn', 'native' => 'Akan', 'flag_code' => '' ], - //'an' => ['name' => 'Aragonese', 'script' => 'Latn', 'native' => 'aragonés', 'flag_code' => '' ], - //'cch' => ['name' => 'Atsam', 'script' => 'Latn', 'native' => 'Atsam', 'flag_code' => '' ], - //'gn' => ['name' => 'Guaraní', 'script' => 'Latn', 'native' => 'Avañe’ẽ', 'flag_code' => '' ], - //'ae' => ['name' => 'Avestan', 'script' => 'Latn', 'native' => 'avesta', 'flag_code' => '' ], - //'ay' => ['name' => 'Aymara', 'script' => 'Latn', 'native' => 'aymar aru', 'flag_code' => '' ], - //'az' => ['name' => 'Azerbaijani (Latin)', 'script' => 'Latn', 'native' => 'azərbaycanca', 'flag_code' => '' ], - //'id' => ['name' => 'Indonesian', 'script' => 'Latn', 'native' => 'Bahasa Indonesia', 'flag_code' => '' ], - //'ms' => ['name' => 'Malay', 'script' => 'Latn', 'native' => 'Bahasa Melayu', 'flag_code' => '' ], - //'bm' => ['name' => 'Bambara', 'script' => 'Latn', 'native' => 'bamanakan', 'flag_code' => '' ], - //'jv' => ['name' => 'Javanese (Latin)', 'script' => 'Latn', 'native' => 'Basa Jawa', 'flag_code' => '' ], - //'su' => ['name' => 'Sundanese', 'script' => 'Latn', 'native' => 'Basa Sunda', 'flag_code' => '' ], - //'bh' => ['name' => 'Bihari', 'script' => 'Latn', 'native' => 'Bihari', 'flag_code' => '' ], - //'bi' => ['name' => 'Bislama', 'script' => 'Latn', 'native' => 'Bislama', 'flag_code' => '' ], - //'nb' => ['name' => 'Norwegian Bokmål', 'script' => 'Latn', 'native' => 'Bokmål', 'flag_code' => '' ], - //'bs' => ['name' => 'Bosnian', 'script' => 'Latn', 'native' => 'bosanski', 'flag_code' => '' ], - //'br' => ['name' => 'Breton', 'script' => 'Latn', 'native' => 'brezhoneg', 'flag_code' => '' ], - //'ca' => ['name' => 'Catalan', 'script' => 'Latn', 'native' => 'català', 'flag_code' => '' ], - //'ch' => ['name' => 'Chamorro', 'script' => 'Latn', 'native' => 'Chamoru', 'flag_code' => '' ], - //'ny' => ['name' => 'Chewa', 'script' => 'Latn', 'native' => 'chiCheŵa', 'flag_code' => '' ], - //'kde' => ['name' => 'Makonde', 'script' => 'Latn', 'native' => 'Chimakonde', 'flag_code' => '' ], - //'sn' => ['name' => 'Shona', 'script' => 'Latn', 'native' => 'chiShona', 'flag_code' => '' ], - //'co' => ['name' => 'Corsican', 'script' => 'Latn', 'native' => 'corsu', 'flag_code' => '' ], - //'cy' => ['name' => 'Welsh', 'script' => 'Latn', 'native' => 'Cymraeg', 'flag_code' => '' ], - //'da' => ['name' => 'Danish', 'script' => 'Latn', 'native' => 'dansk', 'flag_code' => '' ], - //'se' => ['name' => 'Northern Sami', 'script' => 'Latn', 'native' => 'davvisámegiella', 'flag_code' => '' ], - //'de' => ['name' => 'German', 'script' => 'Latn', 'native' => 'Deutsch', 'flag_code' => 'de' ], - //'luo' => ['name' => 'Luo', 'script' => 'Latn', 'native' => 'Dholuo', 'flag_code' => '' ], - //'nv' => ['name' => 'Navajo', 'script' => 'Latn', 'native' => 'Diné bizaad', 'flag_code' => '' ], - //'dua' => ['name' => 'Duala', 'script' => 'Latn', 'native' => 'duálá', 'flag_code' => '' ], - //'et' => ['name' => 'Estonian', 'script' => 'Latn', 'native' => 'eesti', 'flag_code' => '' ], - //'na' => ['name' => 'Nauru', 'script' => 'Latn', 'native' => 'Ekakairũ Naoero', 'flag_code' => '' ], - //'guz' => ['name' => 'Ekegusii', 'script' => 'Latn', 'native' => 'Ekegusii', 'flag_code' => '' ], - //'en-AU' => ['name' => 'Australian English', 'script' => 'Latn', 'native' => 'Australian English', 'flag_code' => '' ], - // 'en-GB' => ['name' => 'British English', 'script' => 'Latn', 'native' => 'British English', 'flag_code' => 'gb' ], - //'en-CA' => ['name' => 'Canadian English', 'script' => 'Latn', 'native' => 'Canadian English', 'flag_code' => '' ], - //'en-US' => ['name' => 'U.S. English', 'script' => 'Latn', 'native' => 'U.S. English', 'flag_code' => '' ], - // 'es' => ['name' => 'Spanish', 'script' => 'Latn', 'native' => 'español', 'flag_code' => '' ], - //'eo' => ['name' => 'Esperanto', 'script' => 'Latn', 'native' => 'esperanto', 'flag_code' => '' ], - //'eu' => ['name' => 'Basque', 'script' => 'Latn', 'native' => 'euskara', 'flag_code' => '' ], - //'ewo' => ['name' => 'Ewondo', 'script' => 'Latn', 'native' => 'ewondo', 'flag_code' => '' ], - //'ee' => ['name' => 'Ewe', 'script' => 'Latn', 'native' => 'eʋegbe', 'flag_code' => '' ], - //'fil' => ['name' => 'Filipino', 'script' => 'Latn', 'native' => 'Filipino', 'flag_code' => '' ], - //'fr' => ['name' => 'French', 'script' => 'Latn', 'native' => 'français', 'flag_code' => '' ], - //'fr-CA' => ['name' => 'Canadian French', 'script' => 'Latn', 'native' => 'français canadien', 'flag_code' => '' ], - //'fy' => ['name' => 'Western Frisian', 'script' => 'Latn', 'native' => 'frysk', 'flag_code' => '' ], - //'fur' => ['name' => 'Friulian', 'script' => 'Latn', 'native' => 'furlan', 'flag_code' => '' ], - //'fo' => ['name' => 'Faroese', 'script' => 'Latn', 'native' => 'føroyskt', 'flag_code' => '' ], - //'gaa' => ['name' => 'Ga', 'script' => 'Latn', 'native' => 'Ga', 'flag_code' => '' ], - //'ga' => ['name' => 'Irish', 'script' => 'Latn', 'native' => 'Gaeilge', 'flag_code' => '' ], - //'gv' => ['name' => 'Manx', 'script' => 'Latn', 'native' => 'Gaelg', 'flag_code' => '' ], - //'sm' => ['name' => 'Samoan', 'script' => 'Latn', 'native' => 'Gagana fa’a Sāmoa', 'flag_code' => '' ], - //'gl' => ['name' => 'Galician', 'script' => 'Latn', 'native' => 'galego', 'flag_code' => '' ], - //'ki' => ['name' => 'Kikuyu', 'script' => 'Latn', 'native' => 'Gikuyu', 'flag_code' => '' ], - //'gd' => ['name' => 'Scottish Gaelic', 'script' => 'Latn', 'native' => 'Gàidhlig', 'flag_code' => '' ], - //'ha' => ['name' => 'Hausa', 'script' => 'Latn', 'native' => 'Hausa', 'flag_code' => '' ], - //'bez' => ['name' => 'Bena', 'script' => 'Latn', 'native' => 'Hibena', 'flag_code' => '' ], - //'ho' => ['name' => 'Hiri Motu', 'script' => 'Latn', 'native' => 'Hiri Motu', 'flag_code' => '' ], - //'hr' => ['name' => 'Croatian', 'script' => 'Latn', 'native' => 'hrvatski', 'flag_code' => '' ], - //'bem' => ['name' => 'Bemba', 'script' => 'Latn', 'native' => 'Ichibemba', 'flag_code' => '' ], - //'io' => ['name' => 'Ido', 'script' => 'Latn', 'native' => 'Ido', 'flag_code' => '' ], - //'ig' => ['name' => 'Igbo', 'script' => 'Latn', 'native' => 'Igbo', 'flag_code' => '' ], - //'rn' => ['name' => 'Rundi', 'script' => 'Latn', 'native' => 'Ikirundi', 'flag_code' => '' ], - //'ia' => ['name' => 'Interlingua', 'script' => 'Latn', 'native' => 'interlingua', 'flag_code' => '' ], - //'iu-Latn' => ['name' => 'Inuktitut (Latin)', 'script' => 'Latn', 'native' => 'Inuktitut', 'flag_code' => '' ], - //'sbp' => ['name' => 'Sileibi', 'script' => 'Latn', 'native' => 'Ishisangu', 'flag_code' => '' ], - //'nd' => ['name' => 'North Ndebele', 'script' => 'Latn', 'native' => 'isiNdebele', 'flag_code' => '' ], - //'nr' => ['name' => 'South Ndebele', 'script' => 'Latn', 'native' => 'isiNdebele', 'flag_code' => '' ], - //'xh' => ['name' => 'Xhosa', 'script' => 'Latn', 'native' => 'isiXhosa', 'flag_code' => '' ], - //'zu' => ['name' => 'Zulu', 'script' => 'Latn', 'native' => 'isiZulu', 'flag_code' => '' ], - //'it' => ['name' => 'Italian', 'script' => 'Latn', 'native' => 'italiano', 'flag_code' => '' ], - //'ik' => ['name' => 'Inupiaq', 'script' => 'Latn', 'native' => 'Iñupiaq', 'flag_code' => '' ], - //'dyo' => ['name' => 'Jola-Fonyi', 'script' => 'Latn', 'native' => 'joola', 'flag_code' => '' ], - //'kea' => ['name' => 'Kabuverdianu', 'script' => 'Latn', 'native' => 'kabuverdianu', 'flag_code' => '' ], - //'kaj' => ['name' => 'Jju', 'script' => 'Latn', 'native' => 'Kaje', 'flag_code' => '' ], - //'mh' => ['name' => 'Marshallese', 'script' => 'Latn', 'native' => 'Kajin M̧ajeļ', 'flag_code' => '' ], - //'kl' => ['name' => 'Kalaallisut', 'script' => 'Latn', 'native' => 'kalaallisut', 'flag_code' => '' ], - //'kln' => ['name' => 'Kalenjin', 'script' => 'Latn', 'native' => 'Kalenjin', 'flag_code' => '' ], - //'kr' => ['name' => 'Kanuri', 'script' => 'Latn', 'native' => 'Kanuri', 'flag_code' => '' ], - //'kcg' => ['name' => 'Tyap', 'script' => 'Latn', 'native' => 'Katab', 'flag_code' => '' ], - //'kw' => ['name' => 'Cornish', 'script' => 'Latn', 'native' => 'kernewek', 'flag_code' => '' ], - //'naq' => ['name' => 'Nama', 'script' => 'Latn', 'native' => 'Khoekhoegowab', 'flag_code' => '' ], - //'rof' => ['name' => 'Rombo', 'script' => 'Latn', 'native' => 'Kihorombo', 'flag_code' => '' ], - //'kam' => ['name' => 'Kamba', 'script' => 'Latn', 'native' => 'Kikamba', 'flag_code' => '' ], - //'kg' => ['name' => 'Kongo', 'script' => 'Latn', 'native' => 'Kikongo', 'flag_code' => '' ], - //'jmc' => ['name' => 'Machame', 'script' => 'Latn', 'native' => 'Kimachame', 'flag_code' => '' ], - //'rw' => ['name' => 'Kinyarwanda', 'script' => 'Latn', 'native' => 'Kinyarwanda', 'flag_code' => '' ], - //'asa' => ['name' => 'Kipare', 'script' => 'Latn', 'native' => 'Kipare', 'flag_code' => '' ], - //'rwk' => ['name' => 'Rwa', 'script' => 'Latn', 'native' => 'Kiruwa', 'flag_code' => '' ], - //'saq' => ['name' => 'Samburu', 'script' => 'Latn', 'native' => 'Kisampur', 'flag_code' => '' ], - //'ksb' => ['name' => 'Shambala', 'script' => 'Latn', 'native' => 'Kishambaa', 'flag_code' => '' ], - //'swc' => ['name' => 'Congo Swahili', 'script' => 'Latn', 'native' => 'Kiswahili ya Kongo', 'flag_code' => '' ], - //'sw' => ['name' => 'Swahili', 'script' => 'Latn', 'native' => 'Kiswahili', 'flag_code' => '' ], - //'dav' => ['name' => 'Dawida', 'script' => 'Latn', 'native' => 'Kitaita', 'flag_code' => '' ], - //'teo' => ['name' => 'Teso', 'script' => 'Latn', 'native' => 'Kiteso', 'flag_code' => '' ], - //'khq' => ['name' => 'Koyra Chiini', 'script' => 'Latn', 'native' => 'Koyra ciini', 'flag_code' => '' ], - //'ses' => ['name' => 'Songhay', 'script' => 'Latn', 'native' => 'Koyraboro senni', 'flag_code' => '' ], - //'mfe' => ['name' => 'Morisyen', 'script' => 'Latn', 'native' => 'kreol morisien', 'flag_code' => '' ], - //'ht' => ['name' => 'Haitian', 'script' => 'Latn', 'native' => 'Kreyòl ayisyen', 'flag_code' => '' ], - //'kj' => ['name' => 'Kuanyama', 'script' => 'Latn', 'native' => 'Kwanyama', 'flag_code' => '' ], - //'ksh' => ['name' => 'Kölsch', 'script' => 'Latn', 'native' => 'Kölsch', 'flag_code' => '' ], - //'ebu' => ['name' => 'Kiembu', 'script' => 'Latn', 'native' => 'Kĩembu', 'flag_code' => '' ], - //'mer' => ['name' => 'Kimîîru', 'script' => 'Latn', 'native' => 'Kĩmĩrũ', 'flag_code' => '' ], - //'lag' => ['name' => 'Langi', 'script' => 'Latn', 'native' => 'Kɨlaangi', 'flag_code' => '' ], - //'lah' => ['name' => 'Lahnda', 'script' => 'Latn', 'native' => 'Lahnda', 'flag_code' => '' ], - //'la' => ['name' => 'Latin', 'script' => 'Latn', 'native' => 'latine', 'flag_code' => '' ], - //'lv' => ['name' => 'Latvian', 'script' => 'Latn', 'native' => 'latviešu', 'flag_code' => '' ], - //'to' => ['name' => 'Tongan', 'script' => 'Latn', 'native' => 'lea fakatonga', 'flag_code' => '' ], - //'lt' => ['name' => 'Lithuanian', 'script' => 'Latn', 'native' => 'lietuvių', 'flag_code' => '' ], - //'li' => ['name' => 'Limburgish', 'script' => 'Latn', 'native' => 'Limburgs', 'flag_code' => '' ], - //'ln' => ['name' => 'Lingala', 'script' => 'Latn', 'native' => 'lingála', 'flag_code' => '' ], - //'lg' => ['name' => 'Ganda', 'script' => 'Latn', 'native' => 'Luganda', 'flag_code' => '' ], - //'luy' => ['name' => 'Oluluyia', 'script' => 'Latn', 'native' => 'Luluhia', 'flag_code' => '' ], - //'lb' => ['name' => 'Luxembourgish', 'script' => 'Latn', 'native' => 'Lëtzebuergesch', 'flag_code' => '' ], - //'hu' => ['name' => 'Hungarian', 'script' => 'Latn', 'native' => 'magyar', 'flag_code' => '' ], - //'mgh' => ['name' => 'Makhuwa-Meetto', 'script' => 'Latn', 'native' => 'Makua', 'flag_code' => '' ], - //'mg' => ['name' => 'Malagasy', 'script' => 'Latn', 'native' => 'Malagasy', 'flag_code' => '' ], - //'mt' => ['name' => 'Maltese', 'script' => 'Latn', 'native' => 'Malti', 'flag_code' => '' ], - //'mtr' => ['name' => 'Mewari', 'script' => 'Latn', 'native' => 'Mewari', 'flag_code' => '' ], - //'mua' => ['name' => 'Mundang', 'script' => 'Latn', 'native' => 'Mundang', 'flag_code' => '' ], - //'mi' => ['name' => 'Māori', 'script' => 'Latn', 'native' => 'Māori', 'flag_code' => '' ], - //'nl' => ['name' => 'Dutch', 'script' => 'Latn', 'native' => 'Nederlands', 'flag_code' => '' ], - //'nmg' => ['name' => 'Kwasio', 'script' => 'Latn', 'native' => 'ngumba', 'flag_code' => '' ], - //'yav' => ['name' => 'Yangben', 'script' => 'Latn', 'native' => 'nuasue', 'flag_code' => '' ], - //'nn' => ['name' => 'Norwegian Nynorsk', 'script' => 'Latn', 'native' => 'nynorsk', 'flag_code' => '' ], - //'oc' => ['name' => 'Occitan', 'script' => 'Latn', 'native' => 'occitan', 'flag_code' => '' ], - //'ang' => ['name' => 'Old English', 'script' => 'Runr', 'native' => 'Old English', 'flag_code' => '' ], - //'xog' => ['name' => 'Soga', 'script' => 'Latn', 'native' => 'Olusoga', 'flag_code' => '' ], - //'om' => ['name' => 'Oromo', 'script' => 'Latn', 'native' => 'Oromoo', 'flag_code' => '' ], - //'ng' => ['name' => 'Ndonga', 'script' => 'Latn', 'native' => 'OshiNdonga', 'flag_code' => '' ], - //'hz' => ['name' => 'Herero', 'script' => 'Latn', 'native' => 'Otjiherero', 'flag_code' => '' ], - //'uz-Latn' => ['name' => 'Uzbek (Latin)', 'script' => 'Latn', 'native' => 'oʼzbekcha', 'flag_code' => '' ], - //'nds' => ['name' => 'Low German', 'script' => 'Latn', 'native' => 'Plattdüütsch', 'flag_code' => '' ], - //'pl' => ['name' => 'Polish', 'script' => 'Latn', 'native' => 'polski', 'flag_code' => '' ], - //'pt' => ['name' => 'Portuguese', 'script' => 'Latn', 'native' => 'português', 'flag_code' => '' ], - //'pt-BR' => ['name' => 'Brazilian Portuguese', 'script' => 'Latn', 'native' => 'português do Brasil', 'flag_code' => '' ], - //'ff' => ['name' => 'Fulah', 'script' => 'Latn', 'native' => 'Pulaar', 'flag_code' => '' ], - //'pi' => ['name' => 'Pahari-Potwari', 'script' => 'Latn', 'native' => 'Pāli', 'flag_code' => '' ], - //'aa' => ['name' => 'Afar', 'script' => 'Latn', 'native' => 'Qafar', 'flag_code' => '' ], - //'ty' => ['name' => 'Tahitian', 'script' => 'Latn', 'native' => 'Reo Māohi', 'flag_code' => '' ], - //'ksf' => ['name' => 'Bafia', 'script' => 'Latn', 'native' => 'rikpa', 'flag_code' => '' ], - //'ro' => ['name' => 'Romanian', 'script' => 'Latn', 'native' => 'română', 'flag_code' => '' ], - //'cgg' => ['name' => 'Chiga', 'script' => 'Latn', 'native' => 'Rukiga', 'flag_code' => '' ], - //'rm' => ['name' => 'Romansh', 'script' => 'Latn', 'native' => 'rumantsch', 'flag_code' => '' ], - //'qu' => ['name' => 'Quechua', 'script' => 'Latn', 'native' => 'Runa Simi', 'flag_code' => '' ], - //'nyn' => ['name' => 'Nyankole', 'script' => 'Latn', 'native' => 'Runyankore', 'flag_code' => '' ], - //'ssy' => ['name' => 'Saho', 'script' => 'Latn', 'native' => 'Saho', 'flag_code' => '' ], - //'sc' => ['name' => 'Sardinian', 'script' => 'Latn', 'native' => 'sardu', 'flag_code' => '' ], - //'de-CH' => ['name' => 'Swiss High German', 'script' => 'Latn', 'native' => 'Schweizer Hochdeutsch', 'flag_code' => '' ], - //'gsw' => ['name' => 'Swiss German', 'script' => 'Latn', 'native' => 'Schwiizertüütsch', 'flag_code' => '' ], - //'trv' => ['name' => 'Taroko', 'script' => 'Latn', 'native' => 'Seediq', 'flag_code' => '' ], - //'seh' => ['name' => 'Sena', 'script' => 'Latn', 'native' => 'sena', 'flag_code' => '' ], - //'nso' => ['name' => 'Northern Sotho', 'script' => 'Latn', 'native' => 'Sesotho sa Leboa', 'flag_code' => '' ], - //'st' => ['name' => 'Southern Sotho', 'script' => 'Latn', 'native' => 'Sesotho', 'flag_code' => '' ], - //'tn' => ['name' => 'Tswana', 'script' => 'Latn', 'native' => 'Setswana', 'flag_code' => '' ], - //'sq' => ['name' => 'Albanian', 'script' => 'Latn', 'native' => 'shqip', 'flag_code' => '' ], - //'sid' => ['name' => 'Sidamo', 'script' => 'Latn', 'native' => 'Sidaamu Afo', 'flag_code' => '' ], - //'ss' => ['name' => 'Swati', 'script' => 'Latn', 'native' => 'Siswati', 'flag_code' => '' ], - //'sk' => ['name' => 'Slovak', 'script' => 'Latn', 'native' => 'slovenčina', 'flag_code' => '' ], - //'sl' => ['name' => 'Slovene', 'script' => 'Latn', 'native' => 'slovenščina', 'flag_code' => '' ], - //'so' => ['name' => 'Somali', 'script' => 'Latn', 'native' => 'Soomaali', 'flag_code' => '' ], - //'sr-Latn' => ['name' => 'Serbian (Latin)', 'script' => 'Latn', 'native' => 'Srpski', 'flag_code' => '' ], - //'sh' => ['name' => 'Serbo-Croatian', 'script' => 'Latn', 'native' => 'srpskohrvatski', 'flag_code' => '' ], - //'fi' => ['name' => 'Finnish', 'script' => 'Latn', 'native' => 'suomi', 'flag_code' => '' ], - //'sv' => ['name' => 'Swedish', 'script' => 'Latn', 'native' => 'svenska', 'flag_code' => '' ], - //'sg' => ['name' => 'Sango', 'script' => 'Latn', 'native' => 'Sängö', 'flag_code' => '' ], - //'tl' => ['name' => 'Tagalog', 'script' => 'Latn', 'native' => 'Tagalog', 'flag_code' => '' ], - //'tzm-Latn' => ['name' => 'Central Atlas Tamazight (Latin)', 'script' => 'Latn', 'native' => 'Tamazight', 'flag_code' => '' ], - //'kab' => ['name' => 'Kabyle', 'script' => 'Latn', 'native' => 'Taqbaylit', 'flag_code' => '' ], - //'twq' => ['name' => 'Tasawaq', 'script' => 'Latn', 'native' => 'Tasawaq senni', 'flag_code' => '' ], - //'shi' => ['name' => 'Tachelhit (Latin)', 'script' => 'Latn', 'native' => 'Tashelhit', 'flag_code' => '' ], - //'nus' => ['name' => 'Nuer', 'script' => 'Latn', 'native' => 'Thok Nath', 'flag_code' => '' ], - //'vi' => ['name' => 'Vietnamese', 'script' => 'Latn', 'native' => 'Tiếng Việt', 'flag_code' => '' ], - //'tg-Latn' => ['name' => 'Tajik (Latin)', 'script' => 'Latn', 'native' => 'tojikī', 'flag_code' => '' ], - //'lu' => ['name' => 'Luba-Katanga', 'script' => 'Latn', 'native' => 'Tshiluba', 'flag_code' => '' ], - //'ve' => ['name' => 'Venda', 'script' => 'Latn', 'native' => 'Tshivenḓa', 'flag_code' => '' ], - //'tw' => ['name' => 'Twi', 'script' => 'Latn', 'native' => 'Twi', 'flag_code' => '' ], - //'tr' => ['name' => 'Turkish', 'script' => 'Latn', 'native' => 'Türkçe', 'flag_code' => '' ], - //'ale' => ['name' => 'Aleut', 'script' => 'Latn', 'native' => 'Unangax tunuu', 'flag_code' => '' ], - //'ca-valencia' => ['name' => 'Valencian', 'script' => 'Latn', 'native' => 'valencià', 'flag_code' => '' ], - //'vai-Latn' => ['name' => 'Vai (Latin)', 'script' => 'Latn', 'native' => 'Viyamíĩ', 'flag_code' => '' ], - //'vo' => ['name' => 'Volapük', 'script' => 'Latn', 'native' => 'Volapük', 'flag_code' => '' ], - //'fj' => ['name' => 'Fijian', 'script' => 'Latn', 'native' => 'vosa Vakaviti', 'flag_code' => '' ], - //'wa' => ['name' => 'Walloon', 'script' => 'Latn', 'native' => 'Walon', 'flag_code' => '' ], - //'wae' => ['name' => 'Walser', 'script' => 'Latn', 'native' => 'Walser', 'flag_code' => '' ], - //'wen' => ['name' => 'Sorbian', 'script' => 'Latn', 'native' => 'Wendic', 'flag_code' => '' ], - //'wo' => ['name' => 'Wolof', 'script' => 'Latn', 'native' => 'Wolof', 'flag_code' => '' ], - //'ts' => ['name' => 'Tsonga', 'script' => 'Latn', 'native' => 'Xitsonga', 'flag_code' => '' ], - //'dje' => ['name' => 'Zarma', 'script' => 'Latn', 'native' => 'Zarmaciine', 'flag_code' => '' ], - //'yo' => ['name' => 'Yoruba', 'script' => 'Latn', 'native' => 'Èdè Yorùbá', 'flag_code' => '' ], - // 'de-AT' => ['name' => 'Austrian German', 'script' => 'Latn', 'native' => 'Österreichisches Deutsch', 'flag_code' => '' ], - //'is' => ['name' => 'Icelandic', 'script' => 'Latn', 'native' => 'íslenska', 'flag_code' => '' ], - //'cs' => ['name' => 'Czech', 'script' => 'Latn', 'native' => 'čeština', 'flag_code' => '' ], - //'bas' => ['name' => 'Basa', 'script' => 'Latn', 'native' => 'Ɓàsàa', 'flag_code' => '' ], - //'mas' => ['name' => 'Masai', 'script' => 'Latn', 'native' => 'ɔl-Maa', 'flag_code' => '' ], - //'haw' => ['name' => 'Hawaiian', 'script' => 'Latn', 'native' => 'ʻŌlelo Hawaiʻi', 'flag_code' => '' ], - //'el' => ['name' => 'Greek', 'script' => 'Grek', 'native' => 'Ελληνικά', 'flag_code' => '' ], - //'uz' => ['name' => 'Uzbek (Cyrillic)', 'script' => 'Cyrl', 'native' => 'Ўзбек', 'flag_code' => '' ], - //'az-Cyrl' => ['name' => 'Azerbaijani (Cyrillic)', 'script' => 'Cyrl', 'native' => 'Азәрбајҹан', 'flag_code' => '' ], - //'ab' => ['name' => 'Abkhazian', 'script' => 'Cyrl', 'native' => 'Аҧсуа', 'flag_code' => '' ], - //'os' => ['name' => 'Ossetic', 'script' => 'Cyrl', 'native' => 'Ирон', 'flag_code' => '' ], - //'ky' => ['name' => 'Kyrgyz', 'script' => 'Cyrl', 'native' => 'Кыргыз', 'flag_code' => '' ], - //'sr' => ['name' => 'Serbian (Cyrillic)', 'script' => 'Cyrl', 'native' => 'Српски', 'flag_code' => '' ], - //'av' => ['name' => 'Avaric', 'script' => 'Cyrl', 'native' => 'авар мацӀ', 'flag_code' => '' ], - //'ady' => ['name' => 'Adyghe', 'script' => 'Cyrl', 'native' => 'адыгэбзэ', 'flag_code' => '' ], - //'ba' => ['name' => 'Bashkir', 'script' => 'Cyrl', 'native' => 'башҡорт теле', 'flag_code' => '' ], - //'be' => ['name' => 'Belarusian', 'script' => 'Cyrl', 'native' => 'беларуская', 'flag_code' => '' ], - //'bg' => ['name' => 'Bulgarian', 'script' => 'Cyrl', 'native' => 'български', 'flag_code' => '' ], - //'kv' => ['name' => 'Komi', 'script' => 'Cyrl', 'native' => 'коми кыв', 'flag_code' => '' ], - //'mk' => ['name' => 'Macedonian', 'script' => 'Cyrl', 'native' => 'македонски', 'flag_code' => '' ], - //'mn' => ['name' => 'Mongolian (Cyrillic)', 'script' => 'Cyrl', 'native' => 'монгол', 'flag_code' => '' ], - //'ce' => ['name' => 'Chechen', 'script' => 'Cyrl', 'native' => 'нохчийн мотт', 'flag_code' => '' ], - //'ru' => ['name' => 'Russian', 'script' => 'Cyrl', 'native' => 'русский', 'flag_code' => '' ], - //'sah' => ['name' => 'Yakut', 'script' => 'Cyrl', 'native' => 'саха тыла', 'flag_code' => '' ], - //'tt' => ['name' => 'Tatar', 'script' => 'Cyrl', 'native' => 'татар теле', 'flag_code' => '' ], - //'tg' => ['name' => 'Tajik (Cyrillic)', 'script' => 'Cyrl', 'native' => 'тоҷикӣ', 'flag_code' => '' ], - //'tk' => ['name' => 'Turkmen', 'script' => 'Cyrl', 'native' => 'түркменче', 'flag_code' => '' ], - //'uk' => ['name' => 'Ukrainian', 'script' => 'Cyrl', 'native' => 'українська', 'flag_code' => '' ], - //'cv' => ['name' => 'Chuvash', 'script' => 'Cyrl', 'native' => 'чӑваш чӗлхи', 'flag_code' => '' ], - //'cu' => ['name' => 'Church Slavic', 'script' => 'Cyrl', 'native' => 'ѩзыкъ словѣньскъ', 'flag_code' => '' ], - //'kk' => ['name' => 'Kazakh', 'script' => 'Cyrl', 'native' => 'қазақ тілі', 'flag_code' => '' ], - //'hy' => ['name' => 'Armenian', 'script' => 'Armn', 'native' => 'Հայերեն', 'flag_code' => '' ], - //'yi' => ['name' => 'Yiddish', 'script' => 'Hebr', 'native' => 'ייִדיש', 'flag_code' => '' ], - //'he' => ['name' => 'Hebrew', 'script' => 'Hebr', 'native' => 'עברית', 'flag_code' => '' ], - //'ug' => ['name' => 'Uyghur', 'script' => 'Arab', 'native' => 'ئۇيغۇرچە', 'flag_code' => '' ], - //'ur' => ['name' => 'Urdu', 'script' => 'Arab', 'native' => 'اردو', 'flag_code' => '' ], - //'uz-Arab' => ['name' => 'Uzbek (Arabic)', 'script' => 'Arab', 'native' => 'اۉزبېک', 'flag_code' => '' ], - //'tg-Arab' => ['name' => 'Tajik (Arabic)', 'script' => 'Arab', 'native' => 'تاجیکی', 'flag_code' => '' ], - //'sd' => ['name' => 'Sindhi', 'script' => 'Arab', 'native' => 'سنڌي', 'flag_code' => '' ], - //'fa' => ['name' => 'Persian', 'script' => 'Arab', 'native' => 'فارسی', 'flag_code' => '' ], - //'pa-Arab' => ['name' => 'Punjabi (Arabic)', 'script' => 'Arab', 'native' => 'پنجاب', 'flag_code' => '' ], - //'ps' => ['name' => 'Pashto', 'script' => 'Arab', 'native' => 'پښتو', 'flag_code' => '' ], - //'ks' => ['name' => 'Kashmiri (Arabic)', 'script' => 'Arab', 'native' => 'کأشُر', 'flag_code' => '' ], - //'ku' => ['name' => 'Kurdish', 'script' => 'Arab', 'native' => 'کوردی', 'flag_code' => '' ], - //'dv' => ['name' => 'Divehi', 'script' => 'Thaa', 'native' => 'ދިވެހިބަސް', 'flag_code' => '' ], - //'ks-Deva' => ['name' => 'Kashmiri (Devaganari)', 'script' => 'Deva', 'native' => 'कॉशुर', 'flag_code' => '' ], - //'kok' => ['name' => 'Konkani', 'script' => 'Deva', 'native' => 'कोंकणी', 'flag_code' => '' ], - //'doi' => ['name' => 'Dogri', 'script' => 'Deva', 'native' => 'डोगरी', 'flag_code' => '' ], - //'ne' => ['name' => 'Nepali', 'script' => 'Deva', 'native' => 'नेपाली', 'flag_code' => '' ], - //'pra' => ['name' => 'Prakrit', 'script' => 'Deva', 'native' => 'प्राकृत', 'flag_code' => '' ], - //'brx' => ['name' => 'Bodo', 'script' => 'Deva', 'native' => 'बड़ो', 'flag_code' => '' ], - //'bra' => ['name' => 'Braj', 'script' => 'Deva', 'native' => 'ब्रज भाषा', 'flag_code' => '' ], - //'mr' => ['name' => 'Marathi', 'script' => 'Deva', 'native' => 'मराठी', 'flag_code' => '' ], - //'mai' => ['name' => 'Maithili', 'script' => 'Tirh', 'native' => 'मैथिली', 'flag_code' => '' ], - //'raj' => ['name' => 'Rajasthani', 'script' => 'Deva', 'native' => 'राजस्थानी', 'flag_code' => '' ], - //'sa' => ['name' => 'Sanskrit', 'script' => 'Deva', 'native' => 'संस्कृतम्', 'flag_code' => '' ], - //'hi' => ['name' => 'Hindi', 'script' => 'Deva', 'native' => 'हिन्दी', 'flag_code' => '' ], - //'as' => ['name' => 'Assamese', 'script' => 'Beng', 'native' => 'অসমীয়া', 'flag_code' => '' ], - //'bn' => ['name' => 'Bengali', 'script' => 'Beng', 'native' => 'বাংলা', 'flag_code' => '' ], - //'mni' => ['name' => 'Manipuri', 'script' => 'Beng', 'native' => 'মৈতৈ', 'flag_code' => '' ], - //'pa' => ['name' => 'Punjabi (Gurmukhi)', 'script' => 'Guru', 'native' => 'ਪੰਜਾਬੀ', 'flag_code' => '' ], - //'gu' => ['name' => 'Gujarati', 'script' => 'Gujr', 'native' => 'ગુજરાતી', 'flag_code' => '' ], - //'or' => ['name' => 'Oriya', 'script' => 'Orya', 'native' => 'ଓଡ଼ିଆ', 'flag_code' => '' ], - //'ta' => ['name' => 'Tamil', 'script' => 'Taml', 'native' => 'தமிழ்', 'flag_code' => '' ], - //'te' => ['name' => 'Telugu', 'script' => 'Telu', 'native' => 'తెలుగు', 'flag_code' => '' ], - //'kn' => ['name' => 'Kannada', 'script' => 'Knda', 'native' => 'ಕನ್ನಡ', 'flag_code' => '' ], - //'ml' => ['name' => 'Malayalam', 'script' => 'Mlym', 'native' => 'മലയാളം', 'flag_code' => '' ], - //'si' => ['name' => 'Sinhala', 'script' => 'Sinh', 'native' => 'සිංහල', 'flag_code' => '' ], - //'th' => ['name' => 'Thai', 'script' => 'Thai', 'native' => 'ไทย', 'flag_code' => '' ], - //'lo' => ['name' => 'Lao', 'script' => 'Laoo', 'native' => 'ລາວ', 'flag_code' => '' ], - //'bo' => ['name' => 'Tibetan', 'script' => 'Tibt', 'native' => 'པོད་སྐད་', 'flag_code' => '' ], - //'dz' => ['name' => 'Dzongkha', 'script' => 'Tibt', 'native' => 'རྫོང་ཁ', 'flag_code' => '' ], - //'my' => ['name' => 'Burmese', 'script' => 'Mymr', 'native' => 'မြန်မာဘာသာ', 'flag_code' => '' ], - //'ka' => ['name' => 'Georgian', 'script' => 'Geor', 'native' => 'ქართული', 'flag_code' => '' ], - //'byn' => ['name' => 'Blin', 'script' => 'Ethi', 'native' => 'ብሊን', 'flag_code' => '' ], - //'tig' => ['name' => 'Tigre', 'script' => 'Ethi', 'native' => 'ትግረ', 'flag_code' => '' ], - //'ti' => ['name' => 'Tigrinya', 'script' => 'Ethi', 'native' => 'ትግርኛ', 'flag_code' => '' ], - //'am' => ['name' => 'Amharic', 'script' => 'Ethi', 'native' => 'አማርኛ', 'flag_code' => '' ], - //'wal' => ['name' => 'Wolaytta', 'script' => 'Ethi', 'native' => 'ወላይታቱ', 'flag_code' => '' ], - //'chr' => ['name' => 'Cherokee', 'script' => 'Cher', 'native' => 'ᏣᎳᎩ', 'flag_code' => '' ], - //'iu' => ['name' => 'Inuktitut (Canadian Aboriginal Syllabics)', 'script' => 'Cans', 'native' => 'ᐃᓄᒃᑎᑐᑦ', 'flag_code' => '' ], - //'oj' => ['name' => 'Ojibwa', 'script' => 'Cans', 'native' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ', 'flag_code' => '' ], - //'cr' => ['name' => 'Cree', 'script' => 'Cans', 'native' => 'ᓀᐦᐃᔭᐍᐏᐣ', 'flag_code' => '' ], - //'km' => ['name' => 'Khmer', 'script' => 'Khmr', 'native' => 'ភាសាខ្មែរ', 'flag_code' => '' ], - //'mn-Mong' => ['name' => 'Mongolian (Mongolian)', 'script' => 'Mong', 'native' => 'ᠮᠣᠨᠭᠭᠣᠯ ᠬᠡᠯᠡ', 'flag_code' => '' ], - //'shi-Tfng' => ['name' => 'Tachelhit (Tifinagh)', 'script' => 'Tfng', 'native' => 'ⵜⴰⵎⴰⵣⵉⵖⵜ', 'flag_code' => '' ], - //'tzm' => ['name' => 'Central Atlas Tamazight (Tifinagh)','script' => 'Tfng', 'native' => 'ⵜⴰⵎⴰⵣⵉⵖⵜ', 'flag_code' => '' ], - //'yue' => ['name' => 'Yue', 'script' => 'Hant', 'native' => '廣州話', 'flag_code' => '' ], - //'ja' => ['name' => 'Japanese', 'script' => 'Jpan', 'native' => '日本語', 'flag_code' => '' ], - //'zh' => ['name' => 'Chinese (Simplified)', 'script' => 'Hans', 'native' => '简体中文', 'flag_code' => '' ], - //'zh-Hant' => ['name' => 'Chinese (Traditional)', 'script' => 'Hant', 'native' => '繁體中文', 'flag_code' => '' ], - //'ii' => ['name' => 'Sichuan Yi', 'script' => 'Yiii', 'native' => 'ꆈꌠꉙ', 'flag_code' => '' ], - //'vai' => ['name' => 'Vai (Vai)', 'script' => 'Vaii', 'native' => 'ꕙꔤ', 'flag_code' => '' ], - //'jv-Java' => ['name' => 'Javanese (Javanese)', 'script' => 'Java', 'native' => 'ꦧꦱꦗꦮ', 'flag_code' => '' ], - //'ko' => ['name' => 'Korean', 'script' => 'Hang', 'native' => '한국어', 'flag_code' => '' ], - ], -]; diff --git a/pint.json b/pint.json index 1cfcc92..6f2f12e 100644 --- a/pint.json +++ b/pint.json @@ -11,7 +11,5 @@ "space": "single" } }, - "exclude": [ - "build" - ] + "exclude": ["build"] } diff --git a/resources/css/filament-language-switch.css b/resources/css/filament-language-switch.css index 62d8df8..7966361 100644 --- a/resources/css/filament-language-switch.css +++ b/resources/css/filament-language-switch.css @@ -1,3 +1,13 @@ @tailwind components; @tailwind utilities; @tailwind base; + +@layer utilities { + .flags-only { + max-width: 3rem !important; + } + + .fls-dropdown-width { + max-width: fit-content !important; + } +} \ No newline at end of file diff --git a/resources/dist/filament-language-switch.css b/resources/dist/filament-language-switch.css index efac5a5..1e4a250 100644 --- a/resources/dist/filament-language-switch.css +++ b/resources/dist/filament-language-switch.css @@ -1 +1 @@ -.flex-shrink-0{flex-shrink:0}.bg-primary-500\/10{background-color:rgba(var(--primary-500),.1)}/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border-width:0;border-style:solid;border-color:rgba(var(--gray-200),1)}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-family),ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:rgba(var(--gray-400),1)}input::placeholder,textarea::placeholder{opacity:1;color:rgba(var(--gray-400),1)}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:rgba(var(--gray-500),var(--tw-border-opacity,1));border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:rgba(var(--gray-500),var(--tw-text-opacity,1));opacity:1}input::placeholder,textarea::placeholder{color:rgba(var(--gray-500),var(--tw-text-opacity,1));opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='rgba(var(--gray-500), var(--tw-stroke-opacity, 1))' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:rgba(var(--gray-500),var(--tw-border-opacity,1));border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=checkbox]:indeterminate,[type=radio]:checked:focus,[type=radio]:checked:hover{border-color:#0000;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.hover\:bg-gray-950\/5:hover{background-color:rgba(var(--gray-950),.05)}.hover\:bg-transparent:hover{background-color:initial}.focus\:bg-gray-950\/5:focus{background-color:rgba(var(--gray-950),.05)}.group:hover .group-hover\:border{border-width:1px}.group:hover .group-hover\:border-primary-500\/10{border-color:rgba(var(--primary-500),.1)}.group:hover .group-hover\:bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.group:hover .group-hover\:text-primary-600{--tw-text-opacity:1;color:rgba(var(--primary-600),var(--tw-text-opacity))}.group:focus .group-focus\:text-white,.group:hover .group-hover\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}:is(.dark .dark\:text-primary-500){--tw-text-opacity:1;color:rgba(var(--primary-500),var(--tw-text-opacity))}:is(.dark .dark\:ring-white\/20){--tw-ring-color:#fff3}:is(.dark .dark\:focus\:bg-white\/5:focus),:is(.dark .dark\:hover\:bg-white\/5:hover){background-color:#ffffff0d} \ No newline at end of file +.flex-shrink-0{flex-shrink:0}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.bg-primary-500\/10{background-color:rgba(var(--primary-500),.1)}.\!p-2{padding:.5rem!important}.\!p-2\.5{padding:.625rem!important}.text-gray-600,.text-primary-600{--tw-text-opacity:1}.flags-only{max-width:3rem!important}.fls-dropdown-width{max-width:-moz-fit-content!important;max-width:fit-content!important}/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border-width:0;border-style:solid;border-color:rgba(var(--gray-200),1)}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-family),ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:rgba(var(--gray-400),1)}input::placeholder,textarea::placeholder{opacity:1;color:rgba(var(--gray-400),1)}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:rgba(var(--gray-500),var(--tw-border-opacity,1));border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:rgba(var(--gray-500),var(--tw-text-opacity,1));opacity:1}input::placeholder,textarea::placeholder{color:rgba(var(--gray-500),var(--tw-text-opacity,1));opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='rgba(var(--gray-500), var(--tw-stroke-opacity, 1))' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:rgba(var(--gray-500),var(--tw-border-opacity,1));border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=checkbox]:indeterminate,[type=radio]:checked:focus,[type=radio]:checked:hover{border-color:#0000;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.hover\:bg-gray-950\/5:hover{background-color:rgba(var(--gray-950),.05)}.hover\:bg-transparent:hover{background-color:initial}.hover\:ring-gray-300:hover{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-300),var(--tw-ring-opacity))}.focus\:bg-gray-950\/5:focus{background-color:rgba(var(--gray-950),.05)}.group:hover .group-hover\:border{border-width:1px}.group:hover .group-hover\:border-primary-500\/10{border-color:rgba(var(--primary-500),.1)}.group:hover .group-hover\:bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.group:hover .group-hover\:text-primary-600{--tw-text-opacity:1;color:rgba(var(--primary-600),var(--tw-text-opacity))}.group:focus .group-focus\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is([dir=rtl] .rtl\:space-x-reverse)>:not([hidden])~:not([hidden]){--tw-space-x-reverse:1}:is(.dark .dark\:bg-gray-950){--tw-bg-opacity:1;background-color:rgba(var(--gray-950),var(--tw-bg-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}:is(.dark .dark\:ring-gray-500){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-500),var(--tw-ring-opacity))}:is(.dark .dark\:hover\:bg-white\/5:hover){background-color:#ffffff0d}:is(.dark .hover\:dark\:ring-gray-400):hover{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-400),var(--tw-ring-opacity))}:is(.dark .dark\:focus\:bg-white\/5:focus){background-color:#ffffff0d} \ No newline at end of file diff --git a/resources/views/components/flag.blade.php b/resources/views/components/flag.blade.php new file mode 100644 index 0000000..7325790 --- /dev/null +++ b/resources/views/components/flag.blade.php @@ -0,0 +1,21 @@ +@props([ + 'src', + 'alt' => '', + 'circular' => false, + 'switch' => false, +]) +class([ + 'object-cover object-center max-w-none', + 'rounded-full' => $circular, + 'rounded-lg' => ! $circular && ! $switch, + 'rounded-md' => ! $circular && $switch, + '' + ]) + }} + @class([ + + ]) +/> \ No newline at end of file diff --git a/resources/views/language-switch.blade.php b/resources/views/language-switch.blade.php index fe977f3..1dffed0 100644 --- a/resources/views/language-switch.blade.php +++ b/resources/views/language-switch.blade.php @@ -1,52 +1,33 @@ - - - -
- {{ \Illuminate\Support\Str::of(app()->getLocale())->length() > 2 - ? \Illuminate\Support\Str::of(app()->getLocale())->substr(0, 2)->upper() - : \Illuminate\Support\Str::of(app()->getLocale())->upper() }} +@php + $languageSwitch = \BezhanSalleh\FilamentLanguageSwitch\LanguageSwitch::make(); + $locales = $languageSwitch->getLocales(); + $isCircular = $languageSwitch->isCircular(); + $isFlagsOnly = $languageSwitch->isFlagsOnly(); + $hasFlags = filled($languageSwitch->getFlags()); + $isVisibleOutsidePanels = $languageSwitch->isVisibleOutsidePanels(); + $outsidePanelsPlacement = $languageSwitch->getOutsidePanelPlacement()->value; + $placement = match(true){ + $outsidePanelsPlacement === 'top-center' && $isFlagsOnly => 'bottom', + $outsidePanelsPlacement === 'bottom-center' && $isFlagsOnly => 'top', + ! $isVisibleOutsidePanels && $isFlagsOnly=> 'bottom', + default => 'bottom-end', + }; +@endphp +
+ @if ($isVisibleOutsidePanels) +
str_contains($outsidePanelsPlacement, 'top'), + 'bottom-0' => str_contains($outsidePanelsPlacement, 'bottom'), + 'justify-start' => str_contains($outsidePanelsPlacement, 'left'), + 'justify-end' => str_contains($outsidePanelsPlacement, 'right'), + 'justify-center' => str_contains($outsidePanelsPlacement, 'center'), + ])> +
+ @include('filament-language-switch::switch') +
- - - @foreach (config('filament-language-switch.locales') as $key => $locale) - @if (!app()->isLocale($key)) - - @endif - @endforeach - - - - + @else + @include('filament-language-switch::switch') + @endif +
\ No newline at end of file diff --git a/resources/views/switch.blade.php b/resources/views/switch.blade.php new file mode 100644 index 0000000..8e46a12 --- /dev/null +++ b/resources/views/switch.blade.php @@ -0,0 +1,90 @@ + + +
$isCircular, + 'rounded-lg' => !$isCircular, + 'p-1 ring-2 ring-inset ring-gray-200 hover:ring-gray-300 dark:ring-gray-500 hover:dark:ring-gray-400' => $isFlagsOnly || $hasFlags, + ]) + x-tooltip="{ + content: @js($languageSwitch->getLabel(app()->getLocale())), + theme: $store.theme, + placement: 'bottom' + }" + > + @if ($isFlagsOnly || $hasFlags) + + @else + {{ $languageSwitch->getCharAvatar(app()->getLocale()) }} + @endif +
+
+ + + @foreach ($locales as $locale) + @if (!app()->isLocale($locale)) + + @endif + @endforeach + +
\ No newline at end of file diff --git a/src/Enums/Placement.php b/src/Enums/Placement.php new file mode 100644 index 0000000..b7d4372 --- /dev/null +++ b/src/Enums/Placement.php @@ -0,0 +1,20 @@ +configure(); - - return $static; - } - - public function renderHookName(string $hookName): static - { - $this->renderHookName = $hookName; - - return $this; - } - - public function getRenderHookName(): string - { - return $this->renderHookName; - } - - public static function get(): static - { - return filament(app(static::class)->getId()); - } - - public function getId(): string - { - return 'filament-language-switch'; - } - - public function register(Panel $panel): void - { - Livewire::component('switch-filament-language', SwitchFilamentLanguage::class); - - $panel - ->renderHook( - name: $this->getRenderHookName(), - hook: fn (): string => Blade::render('@livewire(\'switch-filament-language\')') - ); - } - - public function boot(Panel $panel): void - { - // - } -} diff --git a/src/FilamentLanguageSwitchServiceProvider.php b/src/FilamentLanguageSwitchServiceProvider.php index d4b0745..f786a0d 100644 --- a/src/FilamentLanguageSwitchServiceProvider.php +++ b/src/FilamentLanguageSwitchServiceProvider.php @@ -2,12 +2,14 @@ namespace BezhanSalleh\FilamentLanguageSwitch; +use BezhanSalleh\FilamentLanguageSwitch\Http\Livewire\FilamentLanguageSwitch; use BezhanSalleh\FilamentLanguageSwitch\Http\Middleware\SwitchLanguageLocale; use Filament\Facades\Filament; use Filament\Http\Middleware\DispatchServingFilamentEvent; use Filament\Panel; use Filament\Support\Assets\Css; use Filament\Support\Facades\FilamentAsset; +use Livewire\Livewire; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; @@ -19,20 +21,14 @@ public function configurePackage(Package $package): void { $package ->name(static::$name) - ->hasConfigFile() ->hasViews(); } public function packageBooted(): void { $this->registerPluginMiddleware(); - } - public function registerPluginMiddleware(): void - { - collect(Filament::getPanels()) - ->filter(fn ($panel) => $panel->hasPlugin(static::$name)) - ->each(fn ($panel) => $this->reorderCurrentPanelMiddlewareStack($panel)); + Livewire::component('filament-language-switch', FilamentLanguageSwitch::class); FilamentAsset::register( assets: [ @@ -40,6 +36,16 @@ public function registerPluginMiddleware(): void ], package: 'bezhansalleh/filament-language-switch' ); + + Filament::serving(function () { + LanguageSwitch::boot(); + }); + } + + public function registerPluginMiddleware(): void + { + collect(LanguageSwitch::make()->getPanels()) + ->each(fn ($panel) => $this->reorderCurrentPanelMiddlewareStack($panel)); } protected function reorderCurrentPanelMiddlewareStack(Panel $panel): void diff --git a/src/Http/Livewire/SwitchFilamentLanguage.php b/src/Http/Livewire/FilamentLanguageSwitch.php similarity index 92% rename from src/Http/Livewire/SwitchFilamentLanguage.php rename to src/Http/Livewire/FilamentLanguageSwitch.php index 809c2e4..be7d8b9 100644 --- a/src/Http/Livewire/SwitchFilamentLanguage.php +++ b/src/Http/Livewire/FilamentLanguageSwitch.php @@ -5,7 +5,7 @@ use Illuminate\Contracts\View\View; use Livewire\Component; -class SwitchFilamentLanguage extends Component +class FilamentLanguageSwitch extends Component { public function changeLocale($locale) { diff --git a/src/Http/Middleware/SwitchLanguageLocale.php b/src/Http/Middleware/SwitchLanguageLocale.php index 9b407e9..d20050b 100644 --- a/src/Http/Middleware/SwitchLanguageLocale.php +++ b/src/Http/Middleware/SwitchLanguageLocale.php @@ -2,47 +2,35 @@ namespace BezhanSalleh\FilamentLanguageSwitch\Http\Middleware; +use BezhanSalleh\FilamentLanguageSwitch\LanguageSwitch; use Closure; use Illuminate\Http\Request; -use Illuminate\Support\Arr; class SwitchLanguageLocale { - /** - * Handle an incoming request. - * - * @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next - * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse - */ - public function handle(Request $request, Closure $next) + public function handle(Request $request, Closure $next): \Illuminate\Http\Response | \Illuminate\Http\RedirectResponse { - $locale = session()->get('locale') ?? - $request->get('locale') ?? - $request->cookie('filament_language_switch_locale') ?? - $this->getBrowserLocale($request) ?? - config('app.locale', 'en'); + $locale = session()->get('locale') + ?? $request->get('locale') + ?? $request->cookie('filament_language_switch_locale') + ?? $this->getBrowserLocale($request) + ?? config('app.locale', 'en'); - if (array_key_exists($locale, config('filament-language-switch.locales'))) { + if (in_array($locale, LanguageSwitch::make()->getLocales())) { app()->setLocale($locale); } return $next($request); } - /** - * Determine the locale of the user's browser. - * - * @return ?string - */ private function getBrowserLocale(Request $request): ?string { $userLangs = preg_split('/[,;]/', $request->server('HTTP_ACCEPT_LANGUAGE')); + foreach ($userLangs as $locale) { - if (Arr::exists(config('filament-language-switch.locales'), $locale)) { - return $locale; - } + return in_array($locale, LanguageSwitch::make()->getLocales()) + ? $locale + : null; } - - return null; } } diff --git a/src/LanguageSwitch.php b/src/LanguageSwitch.php new file mode 100755 index 0000000..a65b6cc --- /dev/null +++ b/src/LanguageSwitch.php @@ -0,0 +1,273 @@ +visible(); + + $static->displayLocale(); + + $static->outsidePanelRoutes(); + + $static->configure(); + + return $static; + } + + public static function boot(): void + { + $static = static::make(); + + if ($static->isVisibleInsidePanels()) { + FilamentView::registerRenderHook( + name: $static->getRenderHook(), + hook: fn (): string => Blade::render('') + ); + } + + if ($static->isVisibleOutsidePanels()) { + FilamentView::registerRenderHook( + name: 'panels::body.end', + hook: fn (): string => Blade::render('') + ); + } + } + + public function circular(bool $condition = true): static + { + $this->isCircular = $condition; + + return $this; + } + + public function displayLocale(string $locale = null): static + { + $this->displayLocale = $locale ?? app()->getLocale(); + + return $this; + } + + public function outsidePanelRoutes(array | Closure $routes = null): static + { + $this->outsidePanelRoutes = $routes ?? [ + 'auth.login', + 'auth.profile', + 'auth.register', + ]; + + return $this; + } + + public function excludes(array | Closure $excludes): static + { + $this->excludes = $excludes; + + return $this; + } + + public function flags(array | Closure $flags): static + { + $this->flags = $flags; + + return $this; + } + + public function flagsOnly(bool $condition = true): static + { + $this->isFlagsOnly = $condition; + + return $this; + } + + public function labels(array | Closure $labels): static + { + $this->labels = $labels; + + return $this; + } + + public function locales(array | Closure $locales): static + { + $this->locales = $locales; + + return $this; + } + + public function outsidePanelPlacement(Placement $placement): static + { + $this->outsidePanelPlacement = $placement; + + return $this; + } + + public function renderHook(string $hook): static + { + $this->renderHook = $hook; + + return $this; + } + + public function visible(bool | Closure $insidePanels = true, bool | Closure $outsidePanels = false): static + { + $this->visibleInsidePanels = $insidePanels; + + $this->visibleOutsidePanels = $outsidePanels; + + return $this; + } + + public function getDisplayLocale(): string + { + return (string) $this->evaluate($this->displayLocale); + } + + public function getExcludes(): array + { + return (array) $this->evaluate($this->excludes); + } + + /** + * @throws Exception + */ + public function getFlags(): array + { + $flagUrls = (array) $this->evaluate($this->flags); + + foreach ($flagUrls as $url) { + if (! filter_var($url, FILTER_VALIDATE_URL)) { + throw new \Exception('Invalid flag url'); + exit; + } + } + + return $flagUrls; + } + + public function isCircular(): bool + { + return (bool) $this->evaluate($this->isCircular); + } + + /** + * @throws Exception + */ + public function isFlagsOnly(): bool + { + return (bool) $this->evaluate($this->isFlagsOnly) && filled($this->getFlags()); + } + + public function isVisibleInsidePanels(): bool + { + return (bool) ($this->evaluate($this->visibleInsidePanels) + && count($this->locales) > 1 + && $this->isCurrentPanelIncluded()); + } + + public function isVisibleOutsidePanels(): bool + { + return (bool) ($this->evaluate($this->visibleOutsidePanels) + && str(request()->route()->getName())->contains($this->outsidePanelRoutes) + && $this->isCurrentPanelIncluded()); + } + + public function getLabels(): array + { + return (array) $this->evaluate($this->labels); + } + + public function getLocales(): array + { + return (array) $this->evaluate($this->locales); + } + + public function getOutsidePanelPlacement(): Placement + { + return $this->outsidePanelPlacement ?? Placement::TopRight; + } + + public function getRenderHook(): string + { + return (string) $this->evaluate($this->renderHook); + } + + /** + * @return array + */ + public function getPanels(): array + { + return collect(filament()->getPanels()) + ->reject(fn (Panel $panel) => in_array($panel->getId(), $this->getExcludes())) + ->toArray(); + } + + public function getCurrentPanel(): Panel + { + return filament()->getCurrentPanel(); + } + + public function getFlag(string $locale): string + { + return $this->flags[$locale] ?? str($locale)->upper()->toString(); + } + + public function getLabel(string $locale): string + { + return $this->labels[$locale] ?? str(locale_get_display_name($locale, $this->getDisplayLocale())) + ->title() + ->toString(); + } + + public function isCurrentPanelIncluded(): bool + { + return array_key_exists($this->getCurrentPanel()->getId(), $this->getPanels()); + } + + public function getCharAvatar(string $locale): string + { + return str($locale)->length() > 2 + ? str($locale)->substr(0, 2)->upper()->toString() + : str($locale)->upper()->toString(); + } +}