RogerManich wrote a reply+100 XP
6d ago
Finally I found a possible solution that avoid flickr and no warnings errors on debug console.
import { createInertiaApp } from '@inertiajs/vue3';
import { initializeTheme } from '@/composables/useAppearance';
import AppLayout from '@/layouts/AppLayout.vue';
import AuthLayout from '@/layouts/AuthLayout.vue';
import SettingsLayout from '@/layouts/settings/Layout.vue';
import { initializeFlashToast } from '@/lib/flashToast';
//lang support
import { createSSRApp, h } from 'vue';
import { i18nVue, loadLanguageAsync } from 'laravel-vue-i18n';
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
createInertiaApp({
title: (title) => (title ? `${title} - ${appName}` : appName),
layout: (name) => {
switch (true) {
case name === 'Welcome':
return null;
case name.startsWith('auth/'):
return AuthLayout;
case name.startsWith('settings/'):
return [AppLayout, SettingsLayout];
default:
return AppLayout;
}
},
/*
setup({ el, App, props, plugin }) {
const app = createApp({ render: () => h(App, props) })
.use(plugin)
.use(i18nVue, {
lang: (props.initialPage.props.locale as string) ?? 'en',
fallbackLang: 'en',
resolve: async (lang: string) => {
const langs = import.meta.glob('../../lang/*.json');
return await langs[`../../lang/${lang}.json`]();
},
});
// Only mount in the browser. On SSR `el` is undefined and mounting
// would try to access `window`.
if (typeof window !== 'undefined' && el) {
app.mount(el);
}
return app;
},
*/
setup({ el, App, props, plugin }) {
const langModules = import.meta.glob<{ default: Record<string, string> }>(
'../../lang/*.json',
{ eager: true },
);
const currentLocale = (props.initialPage.props as { locale: string }).locale;
const app = createSSRApp({ render: () => h(App, props) })
.use(plugin)
.use(i18nVue, {
lang: currentLocale,
fallbackLang: 'en',
resolve: (lang: string) =>
langModules[`../../lang/${lang}.json`]?.default ?? {},
});
if (typeof window !== 'undefined' && el) {
// Ensure translations are fully resolved before hydration
// starts, so server-rendered HTML matches client output.
loadLanguageAsync(currentLocale).then(() => app.mount(el));
}
return app;
},
progress: {
color: '#4B5563',
},
});
// This will set light / dark mode on page load...
initializeTheme();
// This will listen for flash toast data from the server...
initializeFlashToast();
RogerManich started a new conversation+100 XP
6d ago
Hi,
I am in learning process and I started a new project to practice a bit. My first goal is having language support to my App using vue starter kit.
The backend part is acomplished and the frontend almost acomplished there is a refresh issue. When I refresh the page I see the original labels and then the translated ones. This is weird for me. But first I want to review what I did in case I did somenthing wrong. Once I create standard project with Larave 13 + inertia + vue3 + authorization enabled:
- populate language files
php artisan lang:publish
- create en.json in lang folder with my labels.
- translate al language files to my supported languages (somthing I'll do at the end. For the moment. Just create a few keys tot test it.)
- Add new field in users to store desired languge (in fact it is a json field named preferences with multiple options.)
- Create a new middleware SetLocal to get current language in Laravel
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
class SetLocale
{
public function handle(Request $request, Closure $next)
{
$available = array_keys(config('app.available_locales'));
// Precendece
// 1. session locale
// 2. user
// 3. Browser preferences
// 4. config.
$locale = $request->session()->get('locale')
?? optional($request->user())?->lang
?? $request->getPreferredLanguage($available)
?? config('app.locale', 'en');
if (in_array($locale, $available, true)) {
App::setLocale($locale);
} else {
//Misconfiguration issue => en
App::setLocale('en');
}
return $next($request);
}
}
- Register middleware in bootstrap app.php
<?php
use App\Http\Middleware\HandleAppearance;
use App\Http\Middleware\HandleInertiaRequests;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
use App\Http\Middleware\SetLocale;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
$middleware->encryptCookies(except: ['appearance', 'sidebar_state']);
$middleware->web(append: [
HandleAppearance::class,
SetLocale::class, /* THIS */
HandleInertiaRequests::class,
AddLinkHeadersForPreloadedAssets::class,
]);
})
->withExceptions(function (Exceptions $exceptions): void {
//
})->create();
- add in shere method in HandleInertiaRequests two data to be shered with frontend. current language and available language (for future language selector not covered here.).
public function share(Request $request): array
{
return [
...parent::share($request),
'auth' => [
'user' => $request->user(),
],
'locale' => fn () => app()->getLocale(),
'available_locales' => fn () => config('app.available_locales'),
];
}
- Install laravel-vue-i18n
- Add in vite.config.js
//at the beginning of the file.
import i18n from 'laravel-vue-i18n/vite';
//in plugins section
i18n(),
- In app ts
//at the beginning of file
import { createApp, h } from 'vue';
import { i18nVue } from 'laravel-vue-i18n';
//Inside the createInertiaApp
setup({ el, App, props, plugin }) {
const app = createApp({ render: () => h(App, props) })
.use(plugin)
.use(i18nVue, {
lang: (props.initialPage.props.locale as string) ?? 'en',
fallbackLang: 'en',
resolve: async (lang: string) => {
const langs = import.meta.glob('../../lang/*.json');
return await langs[`../../lang/${lang}.json`]();
},
});
// Only mount in the browser. On SSR `el` is undefined and mounting
// would try to access `window`.
if (typeof window !== 'undefined' && el) {
app.mount(el);
}
return app;
},
- Now we can use this to translate
in php
__('hello world!');
In vue3
{{ $t('hello world') }}
And now my question:
It works fine. But when I refresh the page I see the original label "hello world" and then the translated text "Hola món". Is there something wrong? Maybe my vue part is not quite fine and I forget something or I doing something too late?
thank you
RogerManich liked a comment+100 XP
6d ago
@Ottenim I google the question and I check documentation.
What you said is right but I want to display i in different languages. (Current app Language). For this case we can use:
php artisan lang:publish
To populate language files. Then make copies for each language you want to support. en, fr, sk, ca, es, nl, etc.
Finally, you can use it in your backend with __('hello world'). It also accept placeholders. If you use Livewire it also works fine. For vue3 I am investigating a bit. Acomplished but I need to polish some things. Ah, don't forget to add a middleware SetLocale to obtain your current language based on your criteria and precedence (session => user => browser => config => hardcoded default.
RogerManich wrote a comment+100 XP
6d ago
@Ottenim I google the question and I check documentation.
What you said is right but I want to display i in different languages. (Current app Language). For this case we can use:
php artisan lang:publish
To populate language files. Then make copies for each language you want to support. en, fr, sk, ca, es, nl, etc.
Finally, you can use it in your backend with __('hello world'). It also accept placeholders. If you use Livewire it also works fine. For vue3 I am investigating a bit. Acomplished but I need to polish some things. Ah, don't forget to add a middleware SetLocale to obtain your current language based on your criteria and precedence (session => user => browser => config => hardcoded default.
RogerManich wrote a reply+100 XP
1w ago
It what I did but it didn't work it. Looks like I need to do something like this:
Route::get('/lab', function () {
return back()->with('flux-toast', [
'text' => 'hellou',
'variant' => 'success',
]);
})->name('lab')->middleware('auth');
Which it is pretty much the same as session()->flash. Maybe there is something easier we can do. But as @imranbru suggest, not bad solution using this approach.
For the moment, with both works fine. Only one is displayed.
RogerManich wrote a reply+100 XP
1w ago
RogerManich started a new conversation+100 XP
1w ago
Hi,
After I watched the last Laravel course I wanted to try to build something with Laravel + LiveWire. My first goal was expanding the user preferences to accept language and color scheme. It works but in my first design I wanted to use a route + controller to update the user preferences instead of doing it insde the component settings. It worked but I realized that flux::toast doesn't work in this scenario. I've seen a post where explaining that now is supported out of the box. Well, inside the component works fine.
After googling a bit and some IA help I found out that I require to use session to store the message and add some listener in my layout. Now it works but I wonder if I did something wrong and I am reinventing the wheel or the starterkit missing this piece of code.
thank you
a Route example:
Route::post('/lab', function () {
session()->flash('flux-toast', [
'text' => 'Record saved successfully!',
'variant' => 'success',
]);
return redirect()->back();
})->name('lab')->middleware('auth');
and in my layout after
@persist('toast')
<flux:toast position="top right" />
@endpersist
@if(session()->has('flux-toast'))
@php $toast = session('flux-toast'); @endphp
<script>
function showToast() {
Flux.toast({
text: '{{ $toast['text'] }}',
variant: '{{ $toast['variant'] ?? 'success' }}',
});
}
if (document.readyState === 'complete') {
showToast();
} else {
document.addEventListener('DOMContentLoaded', showToast, { once: true });
}
document.addEventListener('livewire:navigated', showToast, { once: true });
</script>
@endif
RogerManich liked a comment+100 XP
2w ago
@RogerManich Yes, I noticed this after a while. Thanks Roger
RogerManich wrote a comment+100 XP
4w ago
@Go3shom the if is correct but did you fix it in the when clausule?
require to be $status instead of $request->status
$ideas = $user
->ideas()
->when($status, fn($query, $status) => $query->where('status', $status))
->get();
RogerManich liked a comment+100 XP
4w ago
@wordxpression If I understand what you mean right, you may get the All button count by calling the count method on $statusCounts like so:
<span class="text-xs pl-3">{{ $statusCounts->count() }}</span>
RogerManich liked a comment+100 XP
4w ago
RogerManich wrote a comment+100 XP
1mo ago
@RogerManich a better version
@props([
'status' => ""
])
@php
use App\IdeaStatus;
$classes = 'inline-block rounded-full border px-2 py-1 text-xs font-medium';
$classes .= match($status) {
IdeaStatus::PENDING->value => ' bg-yellow-500/10 text-yellow-500 border-yellow-500/20',
IdeaStatus::IN_PROGRESS->value => ' bg-blue-500/10 text-blue-500 border-blue-500/20',
IdeaStatus::COMPLETED->value => ' bg-green-500/10 text-green-500 border-green-500/20',
default => ' bg-red-500/10 text-red-500 border-red-500/20'
};
@endphp
<span {{ $attributes(['class' => $classes]) }}>
{{ $slot }}
</span>
RogerManich wrote a comment+100 XP
1mo ago
I wonder if it is better use this code. Use a switch instead of several if statements. Use the IdeaStatus enum we created in previous lessons to have consistency. Adding a red color for unknown status (improvably but possible). It is what I do in real life but not sure if Laravel has any considerations to use strings or it is just a lesson and Jeffrey make easier to use strings to not add to much stuff.
@props([
'status' => null
])
@php
use App\IdeaStatus;
$classes = 'inline-block rounded-full border px-2 py-1 text-xs font-medium';
switch($status) {
case IdeaStatus::PENDING->value:
$classes .=' bg-yellow-500/10 text-yellow-500 border-yellow-500/20';
break;
case IdeaStatus::IN_PROGRESS->value:
$classes .=' bg-blue-500/10 text-blue-500 border-blue-500/20';
break;
case IdeaStatus::COMPLETED->value:
$classes .=' bg-green-500/10 text-green-500 border-green-500/20';
break;
default:
$classes .=' bg-red-500/10 text-red-500 border-red-500/20';
}
@endphp
<span {{ $attributes(['class' => $classes]) }}>
{{ $slot }}
</span>
RogerManich wrote a comment+100 XP
1mo ago
@senxor it's a matter of trying and check if it works. Or do you asking if it is a good practice?
RogerManich wrote a comment+100 XP
1mo ago
RogerManich liked a comment+100 XP
1mo ago
I’m using https://heroicons.com/, and it has worked well for me. I just copy the icon, create the Blade view, and add the width and height attributes set to 20, but that’s optional. Thank you
RogerManich wrote a comment+100 XP
1mo ago
@XavierHsiao it is explained in next episodes.
RogerManich liked a comment+100 XP
1mo ago
Seems that Jeffery did not mention displaying flash data. We just need to add it from seesion as below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Idea</title>
@vite(['resources/css/app.css'])
</head>
<body class="bg-background text-foreground">
<x-layout.nav />
{{-- Flash Data --}}
@if (session('success'))
<div class="fixed bottom-4 right-4 bg-primary text-primary-foreground px-6 py-3 rounded-xl shadow-lg">
{{ session('success') }}</div>
@endif
<main class="max-w-7xl mx-auto px-6 pb-10">
{{ $slot }}
</main>
</body>
</html>
RogerManich wrote a comment+100 XP
1mo ago
@Alext1926 we use the DB each time we use Auth::login or Auth::destroy, Auth::attempt, etc. You are using a builtin Laravel classes that make this tasks out of the box. If you open your database you'll see the registered users and sessions.
Maybe did I misunderstand your question?
RogerManich wrote a comment+100 XP
1mo ago
RogerManich wrote a comment+100 XP
1mo ago
@hendriaprianto99 well, maybe you have something in mind.
RogerManich wrote a comment+100 XP
1mo ago
Just a question @Jefrey: In real life when you work with git, you only maintain one branch? Main / develop branch? Main / Develop and one branch per feature you work?
thanks
RogerManich wrote a comment+100 XP
1mo ago
@nosthas you added WithNames.
What I see this rector.php modify some original file in Laravel. Not sure if it is good practice do that.
RogerManich wrote a comment+100 XP
2mos ago
@crscnc if you plan increase complexity there are a few great course in here: Laravel API masterclass, Modular Laravel and others. My concern is about time to dedicate to a technology: Blade looks like great but when you plan to do things close to app maybe vue3 is better. But not entirely sure. Maybe you dedicate efforts to vue3 and an experienced developers tell you that now the trend is CanavisReact 4 (fake name) because it handle better some things that vue3 doesn't. As an example: I usually use MariaDB for all kind of projects. It is a bit work to configure MariaDB, maybe a Linux, Apache or nginx, etc. @jeffreyway suggest in a course that SQLite should be enough for most Laravel projects. I tried it and looks like a good advice. So, I expect the opinion who was there in the battle. You know. :-)
Thank you
RogerManich wrote a comment+100 XP
2mos ago
@crscnc The point is about choosing the right technology among all that Laravel offers. As an example: Before starting to follow Jeffrey I use to make my little projects with MariaDB. Jeffrey suggest in his Laravel in 30 days course that sqlite is good enough for little / medium projects. Good advice. I test it and it is ok. So, if I have to learn Blade or vue3 I want to know if at the end is better to use Vue or Blade is ok. Vue looks like better in terms of I can use it in other places, for instance. Just want to leverage the experience of who were there before.
RogerManich wrote a comment+100 XP
2mos ago
@jawaid interface is something you define independent of a class. If an interface define get, set, erase methods all the classes that implements that interface must define that methods. A class can accept multiple interfaces.
When you use an abstract class is more specifically to think with a classes that you want to instruct how you want to be defined. It can includes implementation (I think it. not sure). It is like a sketch of your class in terms of methods, and specific implementations.
More less.
RogerManich wrote a comment+100 XP
2mos ago
RogerManich liked a comment+100 XP
2mos ago
RogerManich liked a comment+100 XP
2mos ago
And in the controller if we are using authorize method with one parameter, we are using gate:
Gate::authorize(parameter1);
// ex.
Gate::authorize(gateName);
If we are using authorize method with 2 parameters, we are using policies:
Gate::authorize(parameter1, parameter2);
// ex.
Gate::authorize(methodName, modelOrClassInstance);
RogerManich wrote a comment+100 XP
2mos ago
@akaydin I think if you plan having undetermined amount of admins and don't want to make anything complex, you can replicate what Jeffrey suggest: A field named role and define different roles such as user, advanced user, operator, admin, superadmin, etc. According to your needs.
if you require anything more sophisticated you can create a permissions table, role table and pivot table. Then you can associate that role to a user. Each permission can correspond to a Gate. And inside the gate you have to check if you have that particular permission.
RogerManich wrote a comment+100 XP
2mos ago
RogerManich wrote a comment+100 XP
2mos ago
@jake83 I thought the same. I test it in my project and update is required to update the data which is what I expect.
RogerManich wrote a comment+100 XP
2mos ago
@jeffry if we want to display the messages in a different language is there a way to achieve that?
RogerManich wrote a comment+100 XP
2mos ago
RogerManich liked a comment+100 XP
2mos ago
@koulritesh98 While developing, you added some new tables or columns to existing tables, after you deployed to production. You add them by writing new migrations. Then, when you update your production site, you also update your table by running "php artisan migrate". It will ask you "are you sure, this is prod?", you answer yes, and the prod DB is updated. It will run only the newly added migrations, not the old ones. How, might you ask? It keeps a list of migrations that have been already run in the DB table called "migrations". Open it and see for yourself.
Of course, it goes without saying: always double check what your migrations are doing and always made a DB backup before updating.
RogerManich liked a comment+100 XP
2mos ago
@jeffreyway in every video, there's a moment cracks me up. This time, the super explanation for the 419 page expired.. typing fast enough ahahah.
RogerManich wrote a comment+100 XP
2mos ago
@subhrodeb888 I think he meant that when you define a get route is to fetch data and ultimatelly display / return something. It is not a good practice to do something different there like delete something. If you plan to delete something you need to define a route for this. Rest define a way to do this.
RogerManich wrote a comment+100 XP
2mos ago
RogerManich wrote a comment+100 XP
2mos ago
As we can work with Blade, Vue or React what do you recommend to use in Laravel @jeffreyway? Blade is enough or is limited and Vue is much powerful? I have a bit confusion how to use Vue in a project with Laravel (the Vue3 course is not clear enough in this part). But finally I see it and I wonder what is the best? Or when to choose one or another based on your experience.
RogerManich wrote a comment+100 XP
2mos ago
@timgavin Yes and No. From my point of view, places like Laracast are escencial because the course and the teacher is like the man that show the right path. Show you the best practices. AI without knowlede and context is often dangerous. To solve a problem through an AI you need to know what are the right questions. You need to know the capabilities of the technology you choose. And here is where Laracast is valuable. Once you draw the map thanks to the course is when you can start to use AI to expand your knowledge or to help you to build something. Or you can use to clarify something is not entirely clear in the course. But without this essencial context AI is like a car without keys.
RogerManich wrote a comment+100 XP
3mos ago
What I miss in this setup is a 30 seconds to indicate what extensions required to work on VS Code. Php Storm is not free. Only 30 days which is not much.
Also it could be nice some references to Linux. Not everything is apple.
At the end, it is a couple of lines to have an operational setup.
Anyway, you contents are pretty amazing!
thank you Roger