# How the i18n System Supports Multiple Languages in the Page Agent Panel UI

> Discover how the alibaba/page-agent i18n system enables instant language switching in the Panel UI with a type-safe layer for nested translations and parameter interpolation.

- Repository: [Alibaba/page-agent](https://github.com/alibaba/page-agent)
- Tags: internals
- Published: 2026-03-09

---

**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`](https://github.com/alibaba/page-agent/blob/main/locales.ts)

The single source of truth for supported languages resides in [`packages/ui/src/i18n/locales.ts`](https://github.com/alibaba/page-agent/blob/main/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.

```typescript
// 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`](https://github.com/alibaba/page-agent/blob/main/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

```typescript
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`](https://github.com/alibaba/page-agent/blob/main/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.

```typescript
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.

1. **Create the translation catalogue**: Add a new TypeScript file (e.g., [`fr-FR.ts`](https://github.com/alibaba/page-agent/blob/main/fr-FR.ts)) containing a complete translation object with the same structure as [`en-US.ts`](https://github.com/alibaba/page-agent/blob/main/en-US.ts).

2. **Register in the locales map**: Import the new catalogue into [`packages/ui/src/i18n/locales.ts`](https://github.com/alibaba/page-agent/blob/main/packages/ui/src/i18n/locales.ts) and append it to the `locales` object.

```typescript
// 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:

```typescript
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:**

```typescript
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:**

```typescript
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 `locales` object in [`packages/ui/src/i18n/locales.ts`](https://github.com/alibaba/page-agent/blob/main/packages/ui/src/i18n/locales.ts) generates the `SupportedLanguage` type from its keys, preventing invalid language selections at compile time.
- **Lightweight resolver**: The `I18n` class in [`packages/ui/src/i18n/index.ts`](https://github.com/alibaba/page-agent/blob/main/packages/ui/src/i18n/index.ts) provides a `t()` method for nested key lookups and parameter interpolation, falling back to keys when translations are absent.
- **Centralized consumption**: [`packages/ui/src/panel/Panel.ts`](https://github.com/alibaba/page-agent/blob/main/packages/ui/src/panel/Panel.ts) routes all UI strings through its private `#i18n` instance, 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`](https://github.com/alibaba/page-agent/blob/main/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.