# How Archify Handles Localization and Supports Multiple Languages

> Learn how Archify uses type-safe localization and a tuple-based i18n module for robust multi-language support. Ensure complete translations with compile-time validation.

- Repository: [tt-a1i/archify](https://github.com/tt-a1i/archify)
- Tags: internals
- Published: 2026-09-08

---

**Archify implements type-safe localization through a tuple-based i18n module in `archify/renderers/shared/i18n.mjs`, using compile-time validation to ensure every supported locale has a complete translation set.**

Archify's approach to internationalization centers on a deterministic, validation-enforced system that prevents missing translations at build time. The `archify/renderers/shared/i18n.mjs` module exports helper functions that handle runtime interpolation, pluralization, and HTML template localization, while a comprehensive test suite in `archify/test/i18n.test.mjs` verifies completeness across all supported languages.

## The Core Architecture of Archify Localization

### Type-Safe Message Tuples

All UI strings are stored in `MESSAGE_PAIRS`, a map that associates stable keys (such as `'viewer.export.button'`) with **two-element arrays** representing `[English, Chinese]` translations. This tuple design is intentionally strict: a validation loop iterates through every entry to ensure each contains exactly one translation per supported locale, throwing a build error if any tuple is incomplete or malformed.

```javascript
// Conceptual structure of MESSAGE_PAIRS
const MESSAGE_PAIRS = {
  'viewer.export.button': ['Export', '导出'],
  'viewer.export.button.title': ['Export to file', '导出到文件']
};

```

### Locale Resolution and Fallback

The module declares supported locales in `SUPPORTED_LOCALES` (`['en', 'zh-CN']`) and defines a default fallback (`'en'`). The `resolveLocale` function checks incoming locale strings against this list, automatically returning the default when an unsupported locale is requested.

```javascript
import { resolveLocale } from './archify/renderers/shared/i18n.mjs';

const userLocale = resolveLocale('fr-FR'); 
// Returns 'en' because French is not in SUPPORTED_LOCALES

```

At module load time, Archify constructs `CATALOGS`, an object keyed by locale that maps each i18n key to its appropriate string for rapid runtime lookup.

## Runtime Translation APIs

### translateMessage and String Interpolation

The `translateMessage(locale, key, values)` function resolves the target locale, retrieves the string from `CATALOGS`, and interpolates any `{placeholder}` tokens using the internal `formatMessage` helper.

```javascript
import { translateMessage } from './archify/renderers/shared/i18n.mjs';

const locale = 'zh-CN';
const exportLabel = translateMessage(locale, 'viewer.export.button');
// Returns: '导出'

const dynamicLabel = translateMessage('en', 'viewer.export.status', { filename: 'report.pdf' });
// If MESSAGE_PAIRS contains 'Exporting {filename}...', returns 'Exporting report.pdf...'

```

### Pluralization with translateCount

For count-dependent strings, `translateCount(locale, key, count, values)` automatically appends plural suffixes (`.one` or `.other`) to the base key based on the count value. This eliminates manual conditional logic in consuming code.

```javascript
import { translateCount } from './archify/renderers/shared/i18n.mjs';

const nodes = 3;
const msg = translateCount('en', 'viewer.export.card.node', nodes);
// Looks up 'viewer.export.card.node.other', returns '3 nodes'

const singleNode = translateCount('en', 'viewer.export.card.node', 1);
// Looks up 'viewer.export.card.node.one', returns '1 node'

```

### Scoped Catalogs via viewerCatalog

The `viewerCatalog(locale)` helper returns a subset of the full catalog containing only keys prefixed with `'viewer.'`. This is optimized for rendering UI components that need the complete set of viewer-related strings without loading unrelated translation keys.

```javascript
import { viewerCatalog } from './archify/renderers/shared/i18n.mjs';

const uiStrings = viewerCatalog('zh-CN');
// uiStrings['viewer.export.button'] === '导出'
// Pass uiStrings directly to components as a props object

```

## Template Localization

HTML templates can embed localization markers using the `{{i18n:key}}` syntax. The `localizeTemplate` function scans template strings, replaces these markers with the correctly escaped translations for the specified locale, and returns the processed HTML ready for injection.

```javascript
import { localizeTemplate } from './archify/renderers/shared/i18n.mjs';

const template = `
  <button title="{{i18n:viewer.export.button.title}}">{{i18n:viewer.export.button}}</button>
`;
const localizedHtml = localizeTemplate(template, 'zh-CN');
// Result: <button title="导出到文件">导出</button>

```

## Validation and Testing

The module includes a validation loop that executes during initialization, verifying that `MESSAGE_PAIRS` contains complete translations for every key across **all** supported locales. This compile-time checking ensures that developers cannot accidentally ship builds with missing strings.

The `archify/test/i18n.test.mjs` suite validates:
- Correct behavior of `resolveLocale` for known and unknown locales
- Completeness of all message tuples in `MESSAGE_PAIRS`
- Successful translation without errors for every supported locale
- Proper functioning of pluralization rules and placeholder interpolation

## Summary

- **Tuple-based storage**: Translations are stored as arrays in `MESSAGE_PAIRS`, enforcing a 1:1 ratio between supported locales and translation strings.
- **Strict validation**: A build-time check guarantees no translation keys are missing for any supported locale.
- **Flexible runtime APIs**: `translateMessage`, `translateCount`, and `viewerCatalog` provide targeted access to localized strings with interpolation and pluralization support.
- **Template integration**: The `localizeTemplate` function enables declarative localization within HTML templates using `{{i18n:key}}` markers.
- **Fallback safety**: `resolveLocale` ensures graceful degradation to English (`'en'`) when encountering unsupported locale codes.

## Frequently Asked Questions

### How does Archify ensure translations are not missing at runtime?

Archify validates the `MESSAGE_PAIRS` object at module initialization, iterating through every key to verify it contains exactly one string per locale defined in `SUPPORTED_LOCALES`. If any tuple is incomplete, the validation throws an error immediately, preventing the application from starting with missing translations.

### What is the process for adding a new language to Archify?

To add support for a new language, developers must update `SUPPORTED_LOCALES` in `archify/renderers/shared/i18n.mjs` to include the new locale code, then append the corresponding translation string to every array in `MESSAGE_PAIRS`. The existing validation loop will automatically enforce that all future message additions include the new language.

### Does Archify support complex pluralization rules beyond one/other?

Currently, the `translateCount` function in `archify/renderers/shared/i18n.mjs` implements a binary pluralization strategy using `.one` and `.other` suffixes. While this covers English and Chinese requirements, languages with more complex plural forms (such as those requiring zero, few, or many categories) would require extending the `translateCount` implementation to handle additional suffix mappings.

### How can I use Archify's localization system in a custom renderer?

Import the `viewerCatalog` or `translateMessage` functions from `archify/renderers/shared/i18n.mjs`. For full UI components, `viewerCatalog(locale)` provides a complete key-value map of viewer-specific strings. For individual labels or dynamic content, use `translateMessage` with optional placeholder values for interpolation.