A multilingual application is about more than translating interface labels. If it also offers articles, product pages, or other editorial resources, it must represent the language of each piece of content, how its versions relate to one another, and what it means for a translation to be ready for publication. An imprecise model can lead to outdated text, links with no destination, or drafts being shown to users who should not see them.
When planning multilingual content management in PHP, it helps to separate interface, data, and editorial workflow decisions. The implementation can use translation files for the interface and the database for variable content, but that division should reflect the domain and the needs of the people who edit the content.
Separate the interface language, original language, and translation

The interface language determines labels, validation messages, date formats, and other product-specific text. In a PHP application, it can be managed with translation catalogs, such as files organized by locale, and selected based on a user preference or session setting. It should not be confused with the language of the content being viewed.
The original language, in turn, identifies the language in which an editorial resource was created. Each translation is a version associated with that resource and has its own language. A user may browse the interface in Spanish and open a page whose original content is in English; the application should explicitly decide whether this is allowed and how to communicate it.
Store normalized language codes and apply a consistent policy for regional locales where necessary. Do not assume that language and country are interchangeable: a regional variant can affect text, as well as formats, availability, or business requirements. Define which locales the product supports and which ones are used to resolve an incomplete preference.
Choose a data model that represents the domain
There are three common patterns, each with different trade-offs:
- Fields per language: Columns such as
title_esandtitle_enare simple when there are few languages, a stable set of fields, and straightforward queries. They become less flexible as languages are added and make every schema change depend on the language catalog. - Independent records: Each version is stored as a separate resource. This may be appropriate if versions have truly independent lifecycles or structures, but it requires another reliable way to group them. Do not use a similar title or URL as an implicit link.
- Related translations table: A shared resource is associated with one row per language, for example through
content_idandlocale. This makes it easier to add languages and query available versions. It requires constraints to prevent duplicate translations in the same language for a resource.
A related table is often a good fit when versions share an identity and structure, but it is not a universal rule. Fields that are not translated—for example, an internal reference—can remain on the shared entity; localized editorial fields belong in the translation. Also clarify whether a translation can have its own URL, search metadata, or publication date.
In the database, define foreign keys, uniqueness per resource and language, and deletion behavior. The PHP application logic should also validate that the language is supported and that the related resource exists. Database constraints protect against concurrent writes and errors that validation beforehand alone cannot prevent.
Link versions without requiring all of them
Not every resource will exist in every language, and not every translation will be completed at the same time. Model this reality: the absence of a row should not be treated as an integrity error if the translation is optional. By contrast, an editorial state should indicate what happens when a row exists but is not yet ready for publication.
Avoid duplicating information that belongs to the shared resource in each translation, unless the domain requires variations. If translations can be unlinked, moved, or retained as an archive, define those operations and their permissions. To identify a group of versions, use a stable relationship, not matching text, slugs, or dates.
When a translation changes, record which version of the original it was based on if the team needs to detect potentially outdated content. That signal does not by itself prove that the translation is incorrect; it helps prioritize a review. A pending-review flag may be enough for some products, while others will need version history and auditing.
Define editorial states for each language
The publication state should belong to each translation when each language can be drafted, reviewed, and published independently. A resource can be published in one language and remain a draft in another. A single publication boolean at the resource level does not represent this difference.
Design a small, explicit workflow, such as draft, in review, and published. Define who can change each state, which fields are required, and whether a review requires approval. The publication date, responsible person, and change history may be necessary to operate the process; avoid adding states that do not correspond to real team actions.
Public queries must filter by state and language rather than relying on the editorial interface to hide unpublished rows. In PHP, centralize these rules in a domain access layer or reusable queries, and test that controllers, APIs, and background tasks follow them. Editing and publication actions must also verify permissions for the specific language and resource.
Handle missing translations, URLs, and search consistently
If a translation is missing, there are several possible policies. The application can hide the resource in that language, explain that it is available only in another language, or display a fallback. Choose based on the content type and the effect on the user experience; a fallback must not be presented as if it were a translation. If content in another language is shown, clearly indicate this and preserve the option to return to the requested version.
Apply separate rules to the interface and the content. The fact that navigation labels fall back to another catalog does not mean articles should automatically be replaced with their original-language versions. Editorial fallback should be limited to allowed languages and publishable content, and must not return drafts.
URLs should identify an actual version or follow a documented redirect rule. When switching languages, look up the translation of the same resource; if none exists, offer an explicit alternative instead of constructing a route that looks valid. For SEO, avoid publishing empty or duplicate pages due to invisible fallbacks. Search should index only eligible versions and use the corresponding language to filter and display results.
Pre-publication checklist

- Are the interface language, original language, and language of each translation separate concepts in the model?
- Is it impossible to save two translations of the same resource in the same language?
- Can a translation be missing without creating an inconsistent state?
- Can the team distinguish draft, review, and publication states for each language?
- Do public routes and language-switching links check that a visible version exists?
- Is fallback behavior defined for each use case, communicated to the user, and guaranteed never to expose drafts?
- Does search filter by language and state, and stop indexing a withdrawn version?
- Have permissions, concurrent editing, deletion, incomplete content, and language switching been tested?
Also test withdrawing a translation that is already linked, updating the original after publishing a version, and directly requesting an unavailable URL. In each case, verify the response, navigation, and search visibility. The goal is not to force every language to progress at the same pace, but to ensure that each version has an identity, a verifiable state, and predictable behavior for editors and users.



