Skip to main content

Internationalization Design Baseline

Not available yet

TeaQL's unified internationalization runtime is under development. The APIs, catalog format, generated descriptors, and federation representation described here are a design baseline, not released functionality. Do not write application code against the example interfaces yet.

This notice will be removed only after all six runtimes pass the shared conformance suite and the public APIs are released.

Why TeaQL needs a shared design

TeaQL supports Java, Rust, Go, Python, C#/.NET, and TypeScript. Internationalization cannot be defined by copying a Java API into five other languages. The six runtimes need the same observable behavior for:

  • locale negotiation and normalization;
  • catalog precedence and fallback;
  • message keys and named arguments;
  • plural, ordinal, and selection rules;
  • entity and property display names;
  • validation and business errors;
  • action labels and generated predicate descriptions;
  • missing-key diagnostics and audit-safe observability;
  • direct and federated execution.

The framework contract must be language-neutral. Each runtime may use an appropriate native library internally, but the same input corpus must produce the same canonical result.

Historical baseline

TeaQL Java previously provided natural-language validation translators, action translation, field dictionaries, and translators for 15 languages. That implementation was removed during the 2026 modular, zero-reflection runtime refactor. It remains useful as a record of product requirements, but it cannot be restored by copying the old source:

  • it belonged to the former monolithic runtime;
  • locale selection was not consistently driven by trusted request context;
  • several translators embedded complete sentences in Java classes;
  • dictionary loading, framework integration, and formatting were coupled;
  • the design did not define cross-language or federation semantics.

The new design preserves the valuable semantics—stable keys, localized validation, domain labels, and translated actions—while replacing the old implementation model.

Design influences

TeaQL combines proven ideas instead of adopting one application framework wholesale:

ReferenceDesign idea adopted by TeaQL
Unicode ICU and CLDRLocale data, plural categories, selection, and locale-aware value formatting
Mozilla FluentLocalization context, ordered resource bundles, terms, fallback, and pseudolocalization
Rails I18nHierarchical keys, backend chains, application overrides, and model/field/error lookup
ASP.NET Core localizationSeparation between request culture resolution and message localization
GNU gettextExtraction, translator context, catalog review, compilation, and complete-sentence guidance
FormatJSStable message descriptors, translator descriptions, extraction, and precompiled message ASTs

These are architectural references. Their public APIs and resource formats are not automatically TeaQL APIs.

Contract first, runtime adapters second

The portable contract is based on structured messages rather than final strings:

{
"key": "validation.range",
"arguments": {
"field": { "term": "entity.CustomerOrder.field.totalAmount" },
"min": 10,
"max": 100
}
}

The canonical concepts are:

UserContext
└── LocalizationContext
├── LocalizationConfiguration
├── LocalizationPreference
├── resolved locale and fallback chain
├── response mode
└── catalog registry and resolver
MessageRef
MessageArgument
MessageDescriptor
MessageCatalog
CatalogRegistry
MessageResolver
ResolutionResult

Generated and runtime APIs will follow each language's naming conventions, while their serialized forms and behavior remain identical.

Internationalization belongs to UserContext

All runtime internationalization state belongs to the real UserContext. Translation APIs receive UserContext; they do not receive a second locale, policy, request, or business-scope parameter.

Configuration and preference are deliberately separate:

  • LocalizationConfiguration defines supported locales, the application default, fallback rules, response mode, catalog sources, and safety policy.
  • LocalizationPreference expresses the locale, time zone, currency, and formatting choices desired for this execution.

Their defaults may differ, and an application may replace either one while initializing UserContext. Framework adapters, authentication code, application code, tests, and background jobs are all valid initialization mechanisms. The translation layer does not know where a value came from; it only reads the effective state already assembled in UserContext.

{
"requestedLocale": "zh-CN",
"resolvedLocale": "zh-Hans-CN",
"fallbackLocales": ["zh-Hans", "zh", "en"],
"timeZone": "Asia/Shanghai",
"currency": "CNY"
}

One application might initialize that state as follows:

application LocalizationConfiguration
+ application-selected LocalizationPreference
→ validation and normalization during UserContext initialization
→ effective LocalizationContext in UserContext
→ message resolution

This is not a mandatory source-precedence algorithm. An application is free to derive or override either input through its own integration points. TeaQL only requires the resulting state to be explicit, valid, and concentrated in UserContext.

Translation has no tenant concept and does not query an authenticated profile, HTTP header, database, or other business source. Those may be application inputs before UserContext is initialized, but they are not concepts in the message-resolution contract. Dynamic query JSON and ordinary federation payloads must not mutate the established localization state. Runtimes must not silently use the process, operating-system, JVM, or server-thread default locale.

Deterministic fallback

TeaQL will normalize language tags and construct an explicit fallback chain. For example:

zh-Hans-CN → zh-Hans → zh → en
fr-CA → fr → en

Every resolution result should retain enough metadata for diagnostics:

{
"text": "订单金额必须在 10 和 100 之间",
"requestedLocale": "zh-CN",
"resolvedLocale": "zh-Hans",
"catalogLayer": "application",
"fallbackUsed": true,
"key": "validation.range"
}

Fallback must be deterministic and observable. It must never depend on where a server happens to run.

Catalog layers

Catalogs are resolved in a defined order, from the most specific context override to framework defaults:

UserContext catalog override (optional)
→ application catalog
→ generated domain catalog
→ TeaQL framework catalog

Application text can therefore override generated or framework text without editing generated files. Each catalog has an identity, version, content hash, supported locale set, and source classification.

Possible storage adapters include packaged files, application resources, a database, or a managed translation service. Storage is an adapter concern; lookup semantics do not change with the backend.

Shared terminology governance

The six runtimes should not require six independent language sites to maintain six copies of the same enterprise vocabulary. TeaQL proposes a centralized internationalization console as the authoring and governance control plane for all generated applications and runtimes.

The console manages more than translated strings:

  • stable term and message identities from generated model descriptors;
  • approved names for entities, fields, relations, actions, and predicates;
  • human/non-human classification and grammatical metadata;
  • locale variants, definitions, usage notes, and translator context;
  • ownership, review workflow, approval status, and immutable publication history;
  • catalog versions, content hashes, compatibility checks, and rollback;
  • missing-translation, conflicting-term, and affected-application reports.

A terminology change can therefore be reviewed once and published consistently to Java, Rust, Go, Python, C#/.NET, and TypeScript applications. The console should also detect when two teams use different translations for the same concept or reuse one visible term for incompatible concepts.

This is a control-plane/data-plane separation:

models and application descriptors

central terminology and catalog console
author → review → approve → publish

versioned, content-addressed catalog snapshots

runtime CatalogRegistry selected through UserContext

Message resolution must not depend on a synchronous console call. Published catalogs are versioned artifacts that runtimes can cache, deploy, verify, and roll back. The active catalog registry and policy remain part of UserContext; the translation layer still has no knowledge of the organizational or business source that governed the artifact.

Every publication and rollback is auditable. Draft content must never become active merely because it exists in the console, and a runtime must be able to report exactly which catalog identity, version, and content hash produced a rendered result.

Message and term model

TeaQL messages use stable, language-neutral keys:

validation.required
validation.range
action.order.approve
entity.CustomerOrder
entity.CustomerOrder.field.orderNumber
predicate.human.plural.active
predicate.human.possessive.email

Business logic stores the key and structured arguments. It should not concatenate translated fragments or derive a plural by appending s or es.

Terms represent reusable domain vocabulary. Messages represent complete user-facing statements. This lets a translator reorder arguments and choose natural grammar for the target language.

Human and non-human predicates

The model already knows facts that ordinary localization systems require developers to add manually. A generated predicate descriptor can carry:

{
"subjectTerm": "entity.Employee",
"subjectKind": "human",
"subjectNumber": "plural",
"predicate": "active"
}

An English catalog may resolve this as Who are active?. A possessive predicate may resolve as Whose email is {email}?. A non-human subject uses a different message key. Other locales are free to use their own natural sentence structure; they do not emulate English who, whose, or verb agreement.

The input predicate remains semantic—such as active—instead of embedding English grammar such as is active.

Plural and selection rules

Plural behavior comes from CLDR categories:

zero, one, two, few, many, other

The other case is mandatory. Exact-number cases may be supported, but no runtime may invent singular or plural spellings. Selection also supports explicit semantic categories where required, without assuming that grammatical gender behaves identically across languages.

TeaQL will define a portable subset and compile catalogs into a common message AST. This avoids depending on six libraries having identical parser behavior. Runtime adapters may delegate number, date, time, currency, and plural-category calculation to ICU/CLDR-compatible native facilities.

Validation and errors

Validation produces structured errors first:

{
"code": "RANGE",
"message": {
"key": "validation.range",
"arguments": {
"field": { "term": "entity.CustomerOrder.field.totalAmount" },
"min": 10,
"max": 100
}
},
"path": ["order", "totalAmount"]
}

Resolution occurs at the response or presentation boundary. Logs, audit events, and machine integrations retain the stable code and key; localized text is supplementary and must not replace immutable audit semantics.

Hierarchical lookup may specialize a message without changing application code:

application.validation.CustomerOrder.totalAmount.range
domain.validation.CustomerOrder.totalAmount.range
domain.validation.totalAmount.range
teaql.validation.range

Generated descriptors and ownership

The generator can emit descriptors for information already present in the model:

{
"id": "entity.CustomerOrder.field.orderNumber",
"defaultMessage": "Order number",
"description": "Display name for CustomerOrder.orderNumber",
"origin": {
"model": "order-management",
"entity": "CustomerOrder",
"field": "orderNumber"
}
}

Ownership remains explicit:

ContentOwner
Framework validation and runtime messagesTeaQL runtime
Entity, property, relation, and generated predicate descriptorsTeaQL generator
Business messages and overridesApplication
Translated catalog contentApplication/localization team

Generated descriptors may be regenerated. Application catalogs and overrides must never be overwritten by generation.

Federation boundary

Federation transports structured message references and canonical locale metadata when the protocol requires them. It must not let a remote caller rewrite the receiving runtime's UserContext localization state or catalog precedence.

The server remains responsible for:

  • initializing LocalizationConfiguration and LocalizationPreference in UserContext;
  • validating and normalizing their effective values;
  • selecting catalogs and fallback from UserContext;
  • reading the response mode from UserContext;
  • preventing localized text from replacing stable error codes or audit facts.

Direct and federated execution must pass the same semantic conformance cases.

API localization and consumer customization

An API must not force every consumer to accept a server-rendered sentence. Returning only "message": "工作时长是必填项" loses the stable key, typed arguments, field path, fallback decision, and the context needed by another service or client to render the message differently.

TeaQL therefore proposes three explicit response modes:

ModeResponseIntended consumer
STRUCTUREDStable code, MessageRef, typed arguments, and path; no rendered text requiredService-to-service calls and clients that own localization
RENDEREDServer-rendered text plus stable code and keySimple UI or external API consumers
BOTHStructured message and server-rendered text with resolution metadataDebugging, gradual migration, and clients that need a fallback

The effective mode is stored in UserContext. An endpoint adapter may map an explicitly allowed caller preference into UserContext during initialization, but arbitrary dynamic query JSON cannot change it after that boundary.

Example BOTH response:

{
"code": "REQUIRED",
"path": ["timesheet", "workedHour"],
"message": {
"key": "validation.required",
"arguments": {
"field": {
"term": "entity.Timesheet.field.workedHour"
}
}
},
"rendered": {
"text": "工作时长是必填项",
"requestedLocale": "zh-CN",
"resolvedLocale": "zh-Hans",
"catalogLayer": "application",
"catalogVersion": "2026.08.1",
"fallbackUsed": false
}
}

The code, key, argument names, argument types, and field path are the API contract. Rendered text is presentation and may change without changing the API version.

Preference is separate from configuration

An API consumer may express a locale preference through a documented channel such as Accept-Language. The application may choose to use that value when it constructs LocalizationPreference in UserContext. Preference does not itself replace LocalizationConfiguration, inject a catalog, or bypass the supported-locale rules.

LocalizationConfiguration ─┐
├→ application initializes UserContext
LocalizationPreference ───┘ → validated effective LocalizationContext

Both objects are application-overridable. Their separation allows preferences to vary without making configuration remotely writable, while keeping every value used by translation in one UserContext.

Consumer-owned catalogs

Clients that select STRUCTURED can resolve TeaQL message keys with their own catalog. To make that safe and maintainable, TeaQL will publish versioned generated descriptors and framework catalogs. A consumer can:

  1. import the matching descriptor/catalog version;
  2. override display text in its own namespace;
  3. render the structured message locally;
  4. detect unknown keys or incompatible argument schemas explicitly.

Catalog identity and message descriptor version are therefore part of API compatibility metadata. Consumers must not scrape the server-rendered English sentence and use it as a translation key.

Application customization points

The application-facing runtime SPI should allow customization without replacing request execution or response serialization:

LocalizationContextInitializer
CatalogSource
CatalogRegistry
MessageResolver
MessageResolutionObserver

An application can replace configuration or preference, add a context-scoped catalog override, database catalog, translation-service adapter, or custom initializer while retaining TeaQL's canonical fallback, argument validation, privacy, and observability rules. Framework adapters—Spring, Axum, Gin, FastAPI, ASP.NET Core, and Hono—should populate the same UserContext contract instead of defining six unrelated extension mechanisms.

API compatibility rules

  • Never return localized text as the only error identity.
  • Never expose Java class names or runtime-specific exception text as translation keys.
  • Never make clients parse a rendered message to recover fields or values.
  • Adding a translation does not require an API version change.
  • Removing a key or changing its required argument schema is a contract change.
  • Client rendering and server rendering must pass the same conformance fixture for the supported portable subset.
  • Sensitive message arguments remain classified and masked in both structured and rendered modes.

Observability and privacy

Resolution telemetry may include:

  • stable message key;
  • requested and resolved locale;
  • selected catalog layer and version;
  • fallback or missing-key classification;
  • formatting duration and cache result.

Telemetry must not include secrets or unmasked customer values. Argument values should be typed and classified so sensitive values can be suppressed. Missing translations are observable events, not reasons to print an entire request payload.

Guardrails for AI-assisted implementation

Internationalization is especially vulnerable to locally plausible, globally inconsistent AI-generated changes. A coding agent can easily make one endpoint appear to work by reading Accept-Language, passing an extra locale argument, translating an exception directly into a string, or falling back to the machine default. Repeating those patches across HTTP requests, background jobs, message consumers, and federation creates several incompatible localization systems.

TeaQL implementations must preserve this boundary instead:

application-specific inputs and override rules

initialize one UserContext

validation, translation, API output, jobs, and federation

The following are architectural invariants, not optional style preferences:

  1. Internationalization configuration, preference, effective locale, response mode, catalogs, and resolver are concentrated in UserContext.
  2. Translation, validation, and execution APIs must not gain a second locale, policy, request, or business-scope parameter.
  3. The translation layer must not know how an application obtained its values. In particular, it must not read HTTP headers, authentication records, databases, thread locals, or process defaults itself.
  4. Web adapters, background jobs, message consumers, tests, and federation entry points initialize the same UserContext contract rather than introducing transport-specific translation paths.
  5. A localized sentence must never replace the structured code, message key, typed arguments, and field path.
  6. Missing, malformed, unsupported, or remotely forbidden localization input must be handled explicitly; it must not silently select a broader or machine-dependent fallback.
  7. Runtime-specific convenience APIs are acceptable only when they preserve the canonical six-runtime semantics and pass the shared conformance corpus.

Code review should reject a change that makes a single call site convenient by weakening these invariants. The preferred correction is to improve UserContext initialization, a runtime extension point, the portable contract, or the shared fixture—not to add another source of localization truth.

These rules are intentionally written as a design baseline first. Once the contract is accepted, the operational subset will also be copied into the code-generator repository's maintained AGENTS.md rules so coding agents receive the constraint before generating or modifying runtime APIs.

Six-runtime conformance suite

The contract will be backed by one shared corpus:

i18n-contract/
schema/
locale-context.schema.json
message-ref.schema.json
catalog.schema.json
resolution-result.schema.json
fixtures/
catalogs/
cases.json
expected/
canonical-results.json

The same cases will run in Java, Rust, Go, Python, C#/.NET, and TypeScript. Coverage must include:

  • locale normalization and deterministic fallback;
  • missing and malformed catalogs;
  • named argument validation;
  • plural and ordinal categories;
  • selection and terms;
  • numbers, dates, times, currencies, and time zones;
  • validation paths and domain labels;
  • human and non-human predicates;
  • catalog overrides and cache invalidation;
  • trusted-context protection;
  • direct and federated semantic parity;
  • pseudolocalization and right-to-left text.

Passing one Java test suite does not make the feature available. Release requires the supported subset to pass in all six runtimes.

Proposed delivery stages

  1. Publish the language-neutral schemas, catalog precedence, and conformance corpus.
  2. Implement English, Simplified Chinese, and Traditional Chinese catalogs as the first reference set.
  3. Implement Java and Rust adapters and verify identical canonical results.
  4. Implement Go, Python, C#/.NET, and TypeScript adapters.
  5. Generate domain descriptors and integrate structured validation messages.
  6. Add federation parity, catalog tooling, extraction, linting, and pseudolocalization.
  7. Publish stable runtime APIs and remove the development warning from this page.

Non-goals for the first release

  • translating arbitrary database content automatically;
  • accepting locale or catalog policy from unrestricted dynamic JSON;
  • translating SQL, entity identifiers, audit facts, or stable error codes;
  • silently guessing a missing translation;
  • promising every ICU or MessageFormat feature before it is covered by the six-runtime corpus;
  • restoring the former Java classes unchanged.

Current status

This document is the review baseline for the implementation. No public TeaQL version currently guarantees the contract described here. Until release evidence is linked from this page, applications should continue to own their localization layer and treat any runtime-specific integration as application code rather than portable TeaQL functionality.