How Archify Handles Localization and Supports Multiple Languages

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.

// 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.

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.

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.

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.

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.

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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →