Skip to main content

File Patterns

In Branchlate, the file pattern specified in your branchlate.json configuration determines how translation files are located and processed. By understanding and utilizing different file patterns, you can align Branchlate with your project's structure, whether it's a straightforward flat structure, divided into sub-projects, or a complex setup with nested directories and key prefixes.

Branchlate File Pattern
Diagram illustrating standard, sub-project, and key-prefixed file patterns.

The diagram above compares three common file patterns:

  1. Standard file pattern: Suitable for projects where all translations for a language are stored in a single file. Each language has its own file, making it easy to manage flat translation structures.
  2. Sub-project file pattern: Ideal for organizing translations into logical subsets, such as features or components. This pattern allows you to manage multiple translation files per language.
  3. Key-prefixed file pattern: Useful for more granular control, especially for content-heavy projects like Next.js, where individual files correspond to specific translation keys. This pattern supports nested directories and flexible key structures, allowing hierarchical keys like data.privacy-policy.

By understanding and leveraging these patterns, you can tailor Branchlate to fit your project's specific requirements while maintaining consistency and efficiency.


Standard file patterns​

The most common file pattern uses the {languageCode} placeholder to specify where your translation files are located. This is suitable for projects where each language's translations are stored in a single file.

Example​

Suppose your project has the following directory structure:

i18n/
├── en.json
├── fr.json
├── de.json
└── it.json

Each file (e.g., en.json) contains all the translation keys and values for that language.

Your branchlate.json configuration would be:

{
"projectId": "my-project",
"organisationId": "my-organisation",
"languageFilePattern": "i18n/{languageCode}.json",
"languages": ["en", "fr", "de", "it"]
}

In this configuration:

  • languageFilePattern is set to "i18n/{languageCode}.json".
  • languages specifies the list of languages used in the project. This helps Branchlate manage languages consistently and can create or remove translation files automatically.

This pattern is straightforward and works well for most projects with flat translation structures.


Sub-project file patterns​

For larger projects or those with distinct modules or features, you might want to organize your translations into sub-projects. Sub-projects allow you to split translations into logical sets, improving organization and maintainability.

Defining sub-projects using patterns​

You can define sub-projects using a file pattern that includes the {subProjectId} placeholder. This approach simplifies configuration, especially when you have many sub-projects.

Example​

Suppose your project has the following directory structure:

i18n/
├── common/
│ ├── en.json
│ ├── fr.json
│ ├── de.json
│ └── it.json
├── featureX/
│ ├── en.json
│ ├── fr.json
│ ├── de.json
│ └── it.json
└── featureY/
├── en.json
├── fr.json
├── de.json
└── it.json

Each sub-directory under i18n/ represents a sub-project (common, featureX, featureY), and contains translation files for each language.

Your branchlate.json configuration would be:

{
"projectId": "my-project",
"organisationId": "my-organisation",
"subProjects": "i18n/{subProjectId}/{languageCode}.json",
"languages": ["en", "fr", "de", "it"]
}

In this configuration:

  • subProjects is set to a pattern "i18n/{subProjectId}/{languageCode}.json".
  • Branchlate will automatically detect sub-projects based on the directories under i18n/.
  • languages specifies the list of languages used across all sub-projects.

How sub-projects are handled​

  • Branchlate identifies each sub-project by the folder name matching {subProjectId}.
  • For each sub-project, it syncs the translations found in the corresponding language files.
  • This pattern simplifies the configuration, especially when adding new sub-projects.

Alternative sub-project patterns​

If your directory structure places the language code before the sub-project, you can adjust the pattern accordingly.

Example​

Directory structure:

i18n/
├── en/
│ ├── common.json
│ ├── featureX.json
│ └── featureY.json
├── fr/
│ ├── common.json
│ ├── featureX.json
│ └── featureY.json
├── de/
│ ├── common.json
│ ├── featureX.json
│ └── featureY.json
└── it/
├── common.json
├── featureX.json
└── featureY.json

Configuration:

{
"projectId": "my-project",
"organisationId": "my-organisation",
"subProjects": "i18n/{languageCode}/{subProjectId}.json",
"languages": ["en", "fr", "de", "it"]
}

This pattern is flexible and can be adjusted to match your project's structure.

The {subProjectId} placeholder can also match part of a filename, which is useful when several translation file families share the same folder:

{
"projectId": "common",
"organisationId": "my-organisation",
"subProjects": "common/{subProjectId}-translations_{languageCode}.json"
}

With files like common/api-error-translations_en.json and common/common-form-translations_en.json, Branchlate detects the sub-projects api-error and common-form. You can also provide several patterns as an array of strings — see Sub-Projects for details.

Specifying sub-projects individually​

If you have sub-projects with different file formats or structures, you can specify each sub-project individually in an array.

Example​

{
"projectId": "my-project",
"organisationId": "my-organisation",
"subProjects": [
{
"subProjectId": "common",
"languageFilePattern": "i18n/common/{languageCode}.json",
"languages": ["en", "fr", "de", "it"]
},
{
"subProjectId": "emails",
"languageFilePattern": "i18n/emails/{languageCode}.txt",
"languages": ["en", "fr"]
}
]
}

In this configuration:

  • Sub-project common uses JSON files and includes four languages.
  • Sub-project emails uses text files and includes only English and French.

This approach provides flexibility when sub-projects have varying requirements.


Key-prefixed file patterns​

For projects with complex file structures, such as when each translation key corresponds to a separate file, you can use the {keyPrefix} placeholder in your file pattern. This is particularly useful for managing content like markdown files or Next.js pages.

Brief overview​

When you have a directory structure where each file represents a translation key, you can use {keyPrefix} in your languageFilePattern.

Example​

Directory structure:

markdown-files/
├── en/
│ ├── about-us.md
│ ├── contact.md
│ └── faq.md
└── fr/
├── a-propos-de-nous.md
├── contact.md
└── faq.md

Configuration:

{
"projectId": "my-project",
"organisationId": "my-organisation",
"languageFilePattern": "markdown-files/{languageCode}/{keyPrefix}.md",
"languages": ["en", "fr"]
}

In this configuration:

  • {keyPrefix} represents the filename without extension (e.g., about-us, contact).
  • Branchlate uses the keyPrefix as the translation key and the file content as the translation value.

For a detailed explanation of key prefixes and advanced features like keyPrefixMappings, refer to the Key Prefixes page.


How files are matched to a pattern​

Whenever Branchlate runs sync, status, or format, it lists the files that could belong to each pattern and decides which pattern each file belongs to. Two rules govern that decision.

{languageCode} only matches a real language code​

{languageCode} is not a wildcard. It matches a base subtag of 2 or 3 letters, optionally followed by script, region, or numeric subtags separated by - or _:

Filei18n/{languageCode}.jsonLanguage
i18n/en.json✅ matcheden
i18n/fil.json✅ matchedfil
i18n/pt-BR.json✅ matchedpt-BR
i18n/pt_BR.json✅ matchedpt_BR
i18n/zh-Hant-TW.json✅ matchedzh-Hant-TW
i18n/es-419.json✅ matchedes-419
i18n/config.json❌ ignored—
i18n/medication-request_de.json❌ ignored—

Files that sit next to your translations without being translations — a config.json, a settings.json — are therefore left alone. Branchlate reports them so that a genuine typo in a language code doesn't pass unnoticed:

⚠️  1 file(s) ignored, their name is not a language code: i18n/config.json

If one of your language files shows up in that list, its name is not a valid language code — rename it, or use a sub-project pattern that describes it.

Each file belongs to exactly one pattern​

When several patterns could match the same file, the first pattern considered wins, and the file is not handed to any later one. Patterns are considered in this order:

  1. the project's root languageFilePattern, if defined;
  2. then each entry of subProjects, in the order of the array.

So a generic pattern placed earlier claims the files of a more specific one placed later. In this configuration the checkout sub-project ends up with no file at all, because the root pattern already matched i18n/checkout_en.json:

branchlate.json — the checkout sub-project never receives a file
{
"projectId": "my-app",
"languageFilePattern": "i18n/{subProjectId}_{languageCode}.json",
"subProjects": [
{
"subProjectId": "checkout",
"languageFilePattern": "i18n/checkout_{languageCode}.json"
}
]
}

Branchlate reports it rather than translating the wrong set of keys:

2 file(s) match this pattern but were already claimed by "my-app",
declared before it. Move this entry before "my-app" in your branchlate.json.

To fix an overlap between two sub-projects, move the more specific entry earlier in the subProjects array. When the pattern that claimed the files is the project's root languageFilePattern (reported under the project id, my-app above), it cannot be moved after a sub-project — narrow it so that it no longer matches the sub-project's files, or turn it into a sub-project entry itself.

Two files, one language

If two files of the same pattern resolve to the same language — for example i18n/pt-BR.json and i18n/pt_BR.json — sync stops instead of silently merging them into one set of keys:

❌ 2 files resolve to the same language "pt-BR": i18n/pt-BR.json, i18n/pt_BR.json
Pattern "i18n/{languageCode}.json" cannot tell them apart.
Rename them or split them into separate sub-projects.

Comparing sub-projects and key prefixes​

While both sub-projects and key prefixes help organize translations, they serve different purposes and are suited for different scenarios.

Sub-projects​

  • Purpose: Organize translations into logical subsets, such as features or components.
  • Use case: When you have multiple translation files per language, each representing a distinct module or feature.
  • Advantages:
    • Improves organization and maintainability.
    • Allows for different configurations per sub-project (e.g., different languages, file formats).
  • Considerations:
    • Best when translations are grouped by logical sets.

Key prefixes​

  • Purpose: Generate translation keys based on file paths, suitable for granular control.
  • Use case: When each file corresponds to a translation key, often in content-heavy applications.
  • Advantages:
    • Simplifies key management by aligning keys with file structure.
    • Supports hierarchical keys through nested directories.
  • Considerations:
    • May require additional configuration for features like translated filenames.

When to use one over the other​

  • Use sub-projects when you have distinct modules or features that can be logically separated, and you prefer to manage translations in grouped files.
  • Use key prefixes when you need fine-grained control over individual translation keys, especially when dealing with numerous content files.

Next steps​

  • To learn more about sub-projects and how to configure them in detail, visit the Sub-Projects page.
  • For an in-depth explanation of key prefixes and advanced usage, refer to the Key Prefixes page.
  • To understand how to manage languages and key order, see the Languages and Key Order page.

By configuring the languageFilePattern appropriately, you can tailor Branchlate to fit the specific needs of your project, whether you're dealing with simple JSON files, organizing translations into sub-projects, or managing a complex hierarchy of content files. Leveraging these patterns helps:

  • Handle complex file structures with ease.
  • Automatically generate translation keys based on file paths.
  • Maintain consistency and organization in your translation management.
  • Integrate seamlessly with content-heavy applications or frameworks like Next.js.