How the i18n System Supports Multiple Languages in the Page Agent Panel UI
The Panel UI in alibaba/page-agent implements a lightweight, type-safe internationalization layer using an I18n class that resolves nested translation keys with parameter interpolation, enabling instant language switching through a statically typed locales registry.
The Page Agent project provides a browser automation toolkit with a dedicated UI package (@page-agent/ui) that ships with a built-in internationalization system. This system allows developers to render the Panel interface in multiple languages without external dependencies, leveraging TypeScript's type system to guarantee translation completeness at compile time.
Core Architecture
The i18n implementation consists of three tightly integrated components: a type-safe locale registry, a translation resolver class, and the Panel component that consumes translated strings.
Locale Definitions in locales.ts
The single source of truth for supported languages resides in packages/ui/src/i18n/locales.ts. This file exports a locales object that maps language identifiers (e.g., "en-US", "zh-CN") to their respective translation catalogues.
// packages/ui/src/i18n/locales.ts
export const locales = {
'en-US': enUS,
'zh-CN': zhCN,
} as const;
The SupportedLanguage type is automatically derived from the keys of this object using TypeScript's keyof typeof operators. This design ensures that only languages with a defined catalogue can be selected, providing compile-time safety when configuring the UI language.
The I18n Class Implementation
The translation engine is implemented in packages/ui/src/i18n/index.ts as the I18n class. When instantiated, the constructor accepts a SupportedLanguage value and stores the corresponding catalogue from the locales registry.
The class exposes a t(key, params?) method that performs three critical operations:
- Resolves nested keys using dot notation (e.g.,
"ui.panel.stop") - Interpolates parameters into translation strings (e.g.,
{ name: "Alice" }) - Falls back to the raw key if a translation is missing
import { I18n } from '@page-agent/ui';
const i18n = new I18n('en-US');
const message = i18n.t('ui.panel.greeting', { name: 'Alice' });
// Returns: "Hello, Alice!" (assuming the key exists)
Panel Integration
In packages/ui/src/panel/Panel.ts, the Panel class instantiates I18n during construction using the language specified in the UI configuration (config.language ?? 'en-US'). All user-facing strings—button titles, placeholders, status messages, and tool-specific texts—are retrieved exclusively through this.#i18n.t().
This centralized access pattern means the Panel remains agnostic to the specific language being displayed. Switching languages requires only passing a different SupportedLanguage value when creating the Panel instance.
import { Panel } from '@page-agent/ui';
import type { SupportedLanguage } from '@page-agent/ui';
const config = { language: 'zh-CN' as SupportedLanguage };
const panel = new Panel(config);
// Panel now renders all UI text using the zh-CN catalogue
Adding a New Language
Extending the i18n system to support additional languages involves two straightforward steps that require no changes to the Panel's rendering logic.
-
Create the translation catalogue: Add a new TypeScript file (e.g.,
fr-FR.ts) containing a complete translation object with the same structure asen-US.ts. -
Register in the locales map: Import the new catalogue into
packages/ui/src/i18n/locales.tsand append it to thelocalesobject.
// packages/ui/src/i18n/locales.ts
import { enUS } from './en-US';
import { zhCN } from './zh-CN';
import { frFR } from './fr-FR'; // New import
export const locales = {
'en-US': enUS,
'zh-CN': zhCN,
'fr-FR': frFR, // Registered
} as const;
Once registered, the SupportedLanguage type updates automatically, and the Panel can be instantiated with the new language identifier:
const panelFr = new Panel({ language: 'fr-FR' });
Usage Examples
The following patterns demonstrate how to leverage the i18n system in practice:
Instantiating the Panel with a specific language:
import { Panel, SupportedLanguage } from '@page-agent/ui';
const panel = new Panel({
language: 'zh-CN' as SupportedLanguage,
// additional config...
});
Using the I18n class independently for custom components:
import { I18n } from '@page-agent/ui';
const i18n = new I18n('en-US');
const stopLabel = i18n.t('ui.panel.stop');
const status = i18n.t('ui.panel.processing', { index: 3 });
Summary
- Type-safe registry: The
localesobject inpackages/ui/src/i18n/locales.tsgenerates theSupportedLanguagetype from its keys, preventing invalid language selections at compile time. - Lightweight resolver: The
I18nclass inpackages/ui/src/i18n/index.tsprovides at()method for nested key lookups and parameter interpolation, falling back to keys when translations are absent. - Centralized consumption:
packages/ui/src/panel/Panel.tsroutes all UI strings through its private#i18ninstance, making language switching a configuration-level concern. - Zero runtime overhead: The system relies on static TypeScript types and simple object lookups, requiring no additional runtime logic or external i18n libraries.
Frequently Asked Questions
What file defines the supported languages in the Page Agent Panel UI?
The supported languages are defined in packages/ui/src/i18n/locales.ts. This file exports a locales object that maps language identifiers to their translation catalogues, and the SupportedLanguage type is automatically derived from this object's keys. Adding a new language requires only importing the new catalogue and adding it to this map.
How does the i18n system handle missing translations?
When the t() method receives a key that does not exist in the current language catalogue, it returns the key itself as the fallback value. This behavior ensures that the UI remains functional even if specific translations are incomplete, while making missing strings immediately visible during development.
Can I use the i18n system outside of the Panel component?
Yes. The I18n class is exported independently from @page-agent/ui and can be instantiated directly in any component or utility function. Simply import the class, create an instance with a valid SupportedLanguage, and call the t() method to resolve translation keys.
Does the i18n system support runtime language switching?
The current implementation binds the language at instantiation time. To switch languages at runtime, you must create a new Panel instance (or I18n instance) with the desired language configuration. Because the system is lightweight and stateless, instantiation overhead is minimal, making this approach practical for most use cases.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →