Configuration
Translify uses a translify.config.ts (or .js, .json) at your project root.
Config file locations
Translify searches for config files in this order:
translify.config.tstranslify.config.jstranslify.config.mjstranslify.config.cjstranslify.config.jsonconfig/translify.config.*.config/translify.config.*
Config style
The generated config is a plain default export, so it works even when Translify is installed globally and not in your project dependencies:
export default {
// ...
};For editor autocomplete, install @ndnci/translify in the project and add a JSDoc type comment:
// /** @type {import('@ndnci/translify/config').TranslifyConfig} */
export default {
// ...
};defineConfig is still supported for existing projects, but it is no longer required.
Full config reference
// /** @type {import('@ndnci/translify/config').TranslifyConfig} */
export default {
// ── Source ─────────────────────────────────────────────────────────────
source: {
// Glob patterns for source files to scan
include: ['src/**/*.{ts,tsx,js,jsx}', 'app/**/*.{ts,tsx,js,jsx}'],
// Files to exclude
exclude: ['**/*.test.*', '**/*.spec.*', '**/node_modules/**', '**/dist/**'],
},
// ── Translations ────────────────────────────────────────────────────────
translations: {
// BCP 47 tag of your reference language
default_language: 'en',
// Glob patterns pointing to JSON translation files. Recursive globs support
// both `messages/en.json` and split files like `messages/en/auth.json`.
files: ['messages/**/*.json'],
// Used by `translify split-translations` and by missing-key routing in split projects.
split: {
// Group by the first dot-key segment by default.
depth: 1,
// Strings are shorthand for `{ name: 'tools', match: ['tools'] }`.
// Object groups can match several substrings or regex patterns.
groups: [{ name: 'tools', match: ['tool'] }, 'auth'],
// Custom group matching can inspect keys, values, or both.
group_match: 'keys',
// Supported placeholders: `{language}` and `{group}`.
output_pattern: 'messages/{language}/{group}.json',
},
},
// ── Localized URLs ─────────────────────────────────────────────────────
routing: {
locales: ['en', 'fr'],
// 'always': /en/about and /fr/a-propos
// 'as-needed': /about and /fr/a-propos
// 'never': /about and /a-propos
locale_prefix: 'as-needed',
// Cookie first, then the HTTP Accept-Language header/browser preferences.
locale_detection: true,
locale_cookie: {
name: 'translify_locale',
max_age: 31536000,
same_site: 'lax',
secure: false,
},
// Dynamic parameters keep the same name in every locale.
pathnames: {
'/about': { en: '/about', fr: '/a-propos' },
'/blog/[slug]': {
en: '/blog/[slug]',
fr: '/actualites/[slug]',
},
},
base_path: '',
trailing_slash: 'preserve',
},
// ── Application runtime ────────────────────────────────────────────────
runtime: {
// Detect from the browser/request, or use a fixed initial locale.
locale: 'auto',
missing_message: 'key', // 'key', 'empty', or 'throw'
time_zone: 'Europe/Paris',
// Browser-safe configs can import JSON catalogues and centralize them:
// messages: { en, fr },
},
// ── Extraction ──────────────────────────────────────────────────────────
extraction: {
// Function names/expressions to treat as translation calls
translation_functions: ['t', 'i18n.t', 'translate', '$t'],
// Namespace-hook functions. A variable bound to one of these calls with a
// static namespace prefixes every translation call made through it, e.g.
// `const t = useTranslations("CommonMessage")` then `t("save")` extracts
// the key `CommonMessage.save` instead of just `save`. Add your own
// custom wrapper hooks here too (e.g. `useFeatureI18n`) — Translify resolves
// the hook's own definition (relative imports and tsconfig path aliases)
// to figure out each returned function's real namespace, even when a
// single hook returns several functions bound to different namespaces.
namespace_functions: ['useTranslations', 'getTranslations'],
// Exact words to never flag as translation keys or hardcoded text
ignored_words: ['OK', 'API', 'ID'],
// Regex patterns — strings matching any of these are ignored
ignored_patterns: ['^v[0-9]+$'],
// Your own extra patterns
custom_regex_patterns: [],
// Include JSDoc comments in reports
include_comments: false,
},
// ── Detection ───────────────────────────────────────────────────────────
detection: {
// Ignore files whose content contains any of these
ignore_files_containing: ['@generated'],
// Ignore files whose path contains any of these
ignore_paths_containing: ['__mocks__'],
// Ignore files whose name matches any of these regex patterns
ignore_filenames_matching: ['\\.stories\\.'],
},
// ── AI Translation ──────────────────────────────────────────────────────
ai_translation: {
enabled: false,
provider: 'openai', // 'openai' or 'openrouter'
openai_api_key: process.env.OPENAI_API_KEY,
openrouter_api_key: process.env.OPENROUTER_API_KEY,
model: 'gpt-5.6-luna',
temperature: 0,
batch_size: 50,
verify: false,
verify_model: undefined,
values_only: false,
},
};The example uses the recommended direct OpenAI model. For the lowest-cost OpenRouter starting point, switch the provider and use deepseek/deepseek-v4-flash. See Choosing an AI model.
Environment variables
| Variable | Description |
|---|---|
OPENAI_API_KEY | OpenAI API key for AI translation |
OPENROUTER_API_KEY | OpenRouter API key for AI translation |
Translify loads .env, .env.local, .env.{NODE_ENV}, and .env.{NODE_ENV}.local before evaluating translify.config.*, so process.env.OPENAI_API_KEY and process.env.OPENROUTER_API_KEY work from project env files. Variables already exported in your shell take priority over values from those files.
Upgrading existing configs
When Translify adds new config keys, run:
translify config-upgradeIt adds missing defaults such as ai_translation.openrouter_api_key, verify, and values_only without overwriting existing values.
Validation
All config values are validated with Zod. Errors are reported with clear, human-readable messages pointing to the exact field that failed. Unknown keys are rejected too, so typos like translation.files instead of translations.files are caught early.
Run validation directly with:
translify check-configExample error:
✗ Invalid Translify configuration
• ai_translation.openai_api_key: openai_api_key is required when provider
is "openai" and ai_translation is enabled.
Set it via process.env.OPENAI_API_KEY or directly in your config.Runtime reuse
The application runtimes reuse translations.default_language, routing, and runtime from this same file. createI18n(config) is the shortest browser-safe setup; per-instance values override only matching config keys. Set useConfig: false for an intentionally standalone runtime. The Node/server entry discovers this file automatically. Do not import a config that reads private environment variables into a client bundle. See the Application Runtime guide.
