Closed buzzclue closed 4 years ago
Hey,
thanks for the kind words! 🙂
Just to summarize what I've understood:
You have a Page
model which is translatable. Until timestamp XYZ
your required app locale was es
and optional locale was en
. Now you have switched it and have en
as required for all new pages and es
is the optional language.
You now have the problem that you have a mixed translation base and not this single fallback language anymore. For some of the next ideas I assume that you only have these two locales in your app - if you have any additional locales (fr for example) they don't work this easy.
The first things that come to mind:
created_at
timestamp of your Page
model to decide if it was created in es
or en
era - I have to be honest that I don't have a quick idea which would be the best way, I think you would have to override some/one fallback related methods on the Page
model. Your benefit: by default we load all translations in one query and do the decision which to use in PHP.\Illuminate\Foundation\Events\LocaleUpdated
and invert the fallback locale in package configuration. This way you will have en
as fallback if the user wants es
and vice versa.At all I will again promote the v12 #129 as you can use multiple fallbacks or your very own fallback strategy when v12 is released.
Thank you for the quick response.
if you have any additional locales (fr for example) they don't work this easy.
Yes we do have more languages but I wanted to ask question in simple way.
I have a system that several people are using and some might change default/fallback locales back and forth tracking with created_at
isn't practical in such case. I was thinking maybe add a new column and store fallback locale with each page/post.
Is there a method to load all translations for specific model?
Yes multiple fallback idea is good and will work. v12 will be exciting 👍
There's a translations
relationship which is used in the package and fully loaded by default. All logic goes down to this method:
https://github.com/Astrotomic/laravel-translatable/blob/ee5caabd8172f08a70187eae5f92e0b790690db3/src/Translatable/Translatable.php#L425-L436
While scrolling through the code I've found this - strange syntax and was the original trigger for v12 but right now it's in the package like this so you can use it like this.^^
https://github.com/Astrotomic/laravel-translatable/blob/ee5caabd8172f08a70187eae5f92e0b790690db3/src/Translatable/Translatable.php#L214-L226
If you set translatable.fallback_locale
to null
and translatable.use_fallback
or $this->useTranslationFallback
to true
it will loop all configured locales (in order of configuration) until a translation is found.
It still runs only one query - the logic explained in a bit of pseudo-code:
locales = [
en,
es,
fr,
]
translations = SELECT * FROM translations WHERE model_id = model.id;
if translations[fr]
return translations[fr]
foreach locales as locale // 1: en | 2: es | 3: fr
if translations[locale]
return translations[locale]
return null
Like you can see there's only one query - because we utilize default eloquent logic it also works by eager-loading the relation for a collection of pages and will run only one query $pages->load('translations')
.
It will only be heavier on PHP side, so configure your locales (order) wisely and don't have too many locales. 😉
My translations relationship is in the model because I needed some other data with translations.
public function translations(): HasMany
{
return $this->hasMany(PostTranslation::class, 'post_id')->with('postmeta');
}
I have already tried the translatable.fallback_locale=null
and use_fallback
in my configuration is set to true
with these settings the following queries run:
select * from `posts` where exists (select * from `users` where `posts`.`author_id` = `users`.`id` and `users`.`deleted_at` is null) and `posts`.`status` = 1 and `posts`.`visibility` = 'public' and `posts`.`type` is not null and `posts`.`deleted_at` is null limit 10
and for translations
select * from `post_translations` where `post_translations`.`post_id` in (2, 5, 6, 7, 9, 10, 11, 12, 13, 15) and `post_translations`.`locale` in ('es', '')
That loop will return null because translations are not loaded.
My locales in translations
are
'locales' => [
'en',
'es',
'ar',
'fr',
],
Could you show me the code that produces the translations query? It seems like you are loading the translation
(singular) relationship - which should only be used if you know EXACTLY what you want/need and depending on your translated data and amount of locales it doesn't really speed up your app as the transfer of some texts from DB to PHP is most times not the bottleneck.
Thank you for the hint that's exactly what I was doing wrong, i didn't realized until you mentioned. I was using withTranslation
scope instead of with('translations')
Hi There,
I have said this before but what a great package.
I am having a small issue with the fallback option, in my project we used to have Spanish as default and fallback language (most of the old pages are translated in Spanish and some of them have English translations too) now our default language and fallback is changed English but the translateOrDefault returns null for the old pages.
Is there a work around to use Spanish(es) as fallback for old pages? without running new queries?