Internationalization as Application Infrastructure
Internationalization often enters an application as a small feature: read a language header, look up a string, and return the translated text. That approach works—until the application grows beyond one HTTP endpoint, one runtime, or one team.
TeaQL is taking a different path. We are designing internationalization as part of the application infrastructure: explicit in UserContext, structured before rendering, consistent across six programming languages, and constrained strongly enough that both people and coding agents can extend it without inventing a new architecture at every call site.
This work is still in design and is not yet a released portable TeaQL capability. This article explains why we believe the design is worth doing, the trade-offs we are making, and the kinds of organizations that benefit from it.
The problem is not translating a string
Mature applications execute work through many paths:
- an HTTP request;
- a command-line tool;
- a background job;
- a message consumer;
- a scheduled process;
- a federated call between services;
- a test or an AI-operated development harness.
If each entry point discovers the locale independently, internationalization becomes transport-specific. The controller reads Accept-Language; the job uses an application default; a message consumer receives a language field; another service falls back to the operating system; and a test quietly depends on the developer's machine.
Every individual implementation may appear reasonable. Together they create several incompatible sources of truth.
The problem becomes more serious when an application returns only rendered text. Consider a validation failure reduced to this response:
{
"message": "工作时长是必填项"
}
The consumer can no longer reliably determine the error identity, affected field, typed arguments, or whether fallback occurred. Another API consumer cannot render it differently without parsing a sentence. Logs and tests become coupled to wording that translators should be free to improve.
The hard problem is therefore not string lookup. It is preserving meaning and context across the entire execution path.
One place for runtime context
TeaQL already treats UserContext as the explicit carrier of runtime information. Internationalization should follow the same rule.
application-specific inputs and override rules
↓
initialize one UserContext
↓
validation, translation, API output, jobs, and federation
The logical internationalization state in UserContext separates two concerns:
LocalizationConfigurationdescribes supported locales, defaults, fallback rules, catalogs, output mode, and safety policy.LocalizationPreferencedescribes the locale, time zone, currency, and formatting choices desired for the current execution.
Configuration and preference are allowed to differ. Applications can replace either while initializing UserContext. A Web adapter might consider a validated request header; a background process might use a configured preference; a test might construct both directly. TeaQL does not prescribe one universal precedence algorithm for those application inputs.
After initialization, translation reads only UserContext. It does not query HTTP headers, authentication records, databases, thread-local state, or process defaults. It has no concept of the business source from which the application derived a preference.
This boundary costs a little convenience. Every execution path must propagate UserContext correctly. We accept that cost because explicit propagation is observable, testable, and portable across runtimes with very different concurrency models.
Preserve meaning before rendering
TeaQL messages should remain structured until a deliberate rendering boundary. A validation result can retain:
{
"code": "REQUIRED",
"path": ["timesheet", "workedHour"],
"message": {
"key": "validation.required",
"arguments": {
"field": {
"term": "entity.Timesheet.field.workedHour"
}
}
}
}
The stable code, key, field path, and typed argument names form the contract. Rendered text is a presentation derived from that contract.
This leads to three useful API modes:
STRUCTUREDlets a client or downstream service own rendering.RENDEREDserves consumers that want ready-to-display text while retaining stable identity.BOTHcarries the structured message and rendered result, which is useful for migration and diagnostics.
The effective mode is also part of UserContext. An API adapter may map an explicitly allowed consumer preference into the context during initialization, but unrestricted dynamic input and ordinary federation payloads cannot rewrite the established policy.
Models contain language-sensitive meaning
TeaQL is model-driven, so internationalization cannot stop at application error strings. The model contains entities, properties, relations, actions, and query predicates that users eventually see.
Generated descriptors can give these concepts stable identities without putting translated sentences into generated source files. Application catalogs can then override generated or framework text without being overwritten by regeneration.
Natural-language details matter here. Pluralization is not appending s or es. Human and non-human subjects may require different predicates. A plural human collection may read “Who are active?”, while an attributed predicate may use “Whose email is …”. These are language semantics, not naming shortcuts.
We want the generator to provide stable descriptors and reviewed grammatical intent. We want translators and mature localization engines to control the final sentence.
What TeaQL should own—and what it should not
TeaQL should own the portable application contract:
- where localization state lives;
- how configuration and preference are represented;
- stable message and term identities;
- typed arguments and field paths;
- deterministic fallback and catalog precedence;
- structured federation behavior;
- observability and privacy rules;
- the conformance corpus shared by all runtimes.
TeaQL should not invent a new set of plural, date, number, currency, or grammatical rules. ICU, CLDR, Fluent, and mature language ecosystems already contain deep expertise in those areas. The portable TeaQL subset should be implemented on top of proven facilities where possible.
This division is important. A proprietary formatter would quickly diverge across Java, Rust, Go, Python, C#/.NET, and TypeScript. A shared semantic contract backed by established formatting engines gives us both portability and linguistic depth.
Shared runtimes create an opportunity for shared governance
Supporting six languages creates a problem if every runtime also creates an independent language site. An enterprise could end up translating the same entity, field, action, and validation concept six times—and still use different terminology in each product.
We see an opportunity to treat terminology as governed application metadata. A centralized TeaQL console can receive generated model descriptors and manage:
- stable identities and approved display names for domain concepts;
- definitions and usage guidance for enterprise vocabulary;
- human/non-human and other grammatical metadata;
- locale variants and translator context;
- ownership, review, approval, publication, and rollback;
- catalog versions, hashes, and compatibility information;
- conflicts, missing translations, and affected applications.
The workflow becomes:
models and application descriptors
↓
central terminology and catalog console
author → review → approve → publish
↓
versioned catalog snapshots
↓
Java · Rust · Go · Python · .NET · TypeScript
This is more than centralized storage. It allows an organization to decide once what a business concept means and how it should be presented, then make that decision observable and consistent across language stacks. A terminology change has an owner, a review record, an immutable version, an impact report, and a rollback path.
The console is a control plane, not a synchronous dependency of every translation. Runtimes consume versioned, content-addressed catalog snapshots and select the active registry through UserContext. Applications remain available when the console is unavailable, and a rendered result can report exactly which catalog version produced it.
This separation preserves the runtime boundary: translation still knows only UserContext and published catalogs. It does not learn about the organizational systems that authored or approved them.
Six languages change the standard of correctness
Implementing the feature in Java is not enough. TeaQL supports Java, Rust, Go, Python, C#/.NET, and TypeScript, and the same application meaning must survive all six.
We therefore plan one shared conformance corpus covering:
- locale normalization and deterministic fallback;
- missing and malformed catalogs;
- named and typed arguments;
- plural, ordinal, selection, and term behavior;
- numbers, dates, currencies, and time zones;
- generated domain labels and validation paths;
- human and non-human predicates;
- catalog overrides and cache invalidation;
- direct and federated parity;
- trusted-context protection;
- pseudolocalization and right-to-left text.
The goal is not identical internal code. Each runtime should feel natural in its own language. The goal is identical observable semantics.
AI makes architectural boundaries more important
Coding agents are very good at extending a visible pattern. When no pattern is explicit, they are equally capable of creating locally convincing architecture drift.
An agent asked to localize one endpoint may read a header directly, add a locale parameter, translate an exception into a string, and use the machine default when no value is available. The change may pass its local test. Repeated across a codebase, it creates a system that nobody intentionally designed.
TeaQL's response is not to ask every agent to rediscover the architecture. The framework should make the safe path obvious and the wrong path difficult:
- Internationalization state belongs in
UserContext. - Translation, validation, and execution do not gain a second locale or policy parameter.
- Entry-point adapters initialize the same context contract.
- Structured error identity is never replaced by localized prose.
- Unsupported or forbidden input fails explicitly instead of selecting an accidental fallback.
- Every runtime must pass the same portable fixtures.
These constraints will eventually become maintained agent rules in the generator as well as runtime APIs and tests. Documentation explains the architecture; generated guidance puts it in front of coding agents; types and conformance tests enforce it.
Where this matters most
The clearest beneficiaries are organizations whose systems already span multiple languages and infrastructure generations. A core transaction platform may use Java, performance-sensitive services Rust, cloud services Go, AI workloads Python, internal enterprise systems .NET, and application edges TypeScript.
Without a shared contract, each ecosystem gradually develops its own interpretation of context, validation, errors, audit, pagination, and localization. The cost is not visible in the first service. It appears years later as duplicated platform work, inconsistent behavior, and migrations that cannot be verified.
For platform-engineering teams, TeaQL can provide a paved road that is broader than one framework template. Teams keep language-appropriate APIs while inheriting the same application guarantees. New languages and infrastructure can enter without resetting the organization's governance and semantics.
Long-lived software products also benefit. Their technology stacks rarely remain frozen for a decade. A stable, model-driven contract allows the product to evolve without turning each new runtime into an independent application platform.
This does not mean a new or single-language system has nothing to gain. Explicit context, structured errors, generated descriptors, deterministic behavior, and AI-oriented guardrails are valuable before a second language arrives. Such a system can start with one runtime while avoiding assumptions that make later growth expensive.
The primary value, however, becomes most visible when organizational and technical diversity are unavoidable: languages may differ, but application meaning should not.
The goal is durable evolution
TeaQL is not trying to become another translation-string library. We are designing a model-driven internationalization and context layer that can remain coherent across languages, execution paths, APIs, and coding agents.
That is a larger commitment than adding translate(key). It requires a portable schema, runtime integrations, generated descriptors, federation rules, shared fixtures, and release evidence. It also gives us something much more durable: an application can evolve its languages, databases, frameworks, and infrastructure without allowing its meaning to fragment at the same rate.
The complete proposal is available in the Internationalization Design Baseline. The development warning will remain until the portable contract is implemented and verified across the supported runtimes.
