Laravel in Barcelona
Laravel development for Barcelona companies
A Laravel development company working with Barcelona teams. Product companies with their own engineers, travel and mobility platforms, and content in three languages that belongs in the database.
The buyers in Barcelona are product companies rather than corporates - travel and mobility platforms, marketplaces, subscription products with a few engineers and a backlog longer than the team.
What these teams buy is bounded work - one named defect the engineers have been looking at for a quarter, fixed inside their own branch policy, with an end date rather than a retainer.
Three languages in Barcelona, and where the content lives
This is the local specific, and it is a schema question rather than an internationalisation one.
Interface strings are a solved problem and belong in language files. Content that belongs to a record does not: a listing title, a route description, a help article. That is data with a lifecycle - it is edited by somebody who is not a developer, reviewed, published, occasionally rolled back - and putting it in a language file means every change is a deployment.
Which means it does not happen, which means the non-default languages quietly fall behind. In a region where one of those languages is not optional, that is visible to everybody.
So translated content sits beside the record with its own completeness state, and two decisions have to be made explicitly rather than inherited.
The first is the fallback order. If a record exists in Spanish and English but not Catalan, what does a Catalan visitor see? Falling back silently is helpful to a reader and dishonest to a crawler, so the application has to distinguish between content that exists in a language and content that is being substituted.
The second is that completeness is a queryable state. Somebody has to be able to ask which records are missing a translation, because that is the editorial workload, and an application that cannot answer it leaves the gap invisible until a customer finds it.
Two languages let you get away with not deciding either. Three do not.
What usually needs fixing in a Barcelona Laravel codebase
Beyond the language work, Barcelona applications arrive with the shape of something built quickly and correctly for an earlier stage.
The queue most often: jobs that are not safe to run twice in a system that retries by design, which means a duplicate somewhere that nobody has traced yet.
Then the schema that described the business two pivots ago - a status enum whose values mean different things depending on when the row was created, and a JSON column that became the place new fields go because a migration felt heavy. Every addition was reasonable; the sum is a model nobody can reason about.
A Barcelona URL has to exist in three languages
If the content exists in Catalan, Spanish and English, so does its address, and the addresses are not translations of each other performed at render time.
A slug per language, stored, is the arrangement that works. It is editable by whoever writes the content, it is stable, and it does not change because somebody corrected a typo in a title. Deriving the URL from the title means every title edit silently moves a page that may be linked from elsewhere, which is a problem that shows up as lost traffic rather than as an error.
Which means slug history. When a slug does change deliberately, the old one keeps resolving - to a permanent redirect at the new address - and that requires the previous slugs to be rows rather than memories. Without it the third or fourth content revision quietly breaks every external link to the page.
The language versions have to point at each other explicitly, because a crawler cannot infer that three different addresses are the same document in three languages. Each page declares its alternates, in every language that genuinely exists for it, and declares nothing for the ones that do not. Pointing at an address that returns a translation of the navigation around English body text is worse than pointing at nothing.
Barcelona content that exists in two languages but not the third
Translation is never complete, and a system that assumes completeness produces the worst available outcome, which is a page that claims to be Catalan and is not.
So the record knows, per language, whether it exists. A list of articles in Catalan shows the ones that exist in Catalan, not every article with the untranslated ones rendering in Spanish. An article that is missing in the requested language either does not appear or appears clearly labelled, and which of those is right depends on the content rather than on the framework's default.
The fallback has to be honest at the level of the page, not the string. Falling back field by field produces a page with a Catalan heading, a Spanish body and an English call to action, which reads as broken to a person and as a thin translation to a crawler. Falling back as a whole page, and saying so, is the version a reader can work with.
And the gap has to be visible to whoever can close it. A list of what is missing, per language, ordered by how much traffic the page gets, is a short report that turns an abstract backlog into three afternoons of work by somebody who writes Catalan.
Laravel caching when the page varies by language and by user
Caching gets added when the site gets slow, and the bug it introduces is almost always the same - somebody sees a page in the wrong language, or worse, sees somebody else's.
The cause is a cache key that does not include everything the output depends on. Language is the obvious omission on a trilingual site. Authentication state is the dangerous one, because a page cached while logged out and served to a logged-in user is merely wrong, while the reverse is a disclosure. Anything the response varies by - locale, role, currency, the tenant - belongs in the key, and the discipline is to build the key from a declared list rather than from whatever the developer remembered.
Fragment caching avoids most of it by scoping the cache to the part that is genuinely shared. The article body in Catalan is the same for everybody and can be cached hard; the header with the user's name cannot be cached at all. Splitting on that boundary gives most of the benefit with none of the risk, and it survives a new personalised element being added later.
Invalidation is then the only hard part left, and the thing that makes it tractable is invalidating on the event rather than on a timer. Content saved, cache cleared for that content in that language - not a fifteen-minute expiry that leaves an editor refreshing and wondering whether their change worked.
Commercially
The invoice comes from Codefacture Yazılım A.Ş., registered in Türkiye, in euros by bank transfer, with no Turkish VAT under the export-of-services exemption.
The country-level ground is on the Spain market page.
