Translation

Learn how to translate your Spiderly app using JSON files and IStringLocalizer.

Overview

Spiderly uses a runtime, JSON-based translation system powered by .NET's IStringLocalizer. Translation files are flat key-value JSON files stored in your project, and IStringLocalizer is automatically injected into all generated services and controllers.

Key features:

  • JSON files in Backend\YourAppName.Shared\Translations\ named by language tag (e.g., en.json, sr-Latn-RS.json)
  • Automatic injection — generated services and controllers receive IStringLocalizer via constructor injection
  • Graceful fallback — if no translations are configured, the app still works (keys are returned as-is)

Registration

Enable translations in your Program.cs using the SpiderlyBuilder:

services.AddSpiderly<YourDbContext>(spiderly =>
{
    spiderly.UsePostgreSQL(); // or UseSQLServer()

    // Enable the built-in JSON file-based localizer
    spiderly.UseTranslations();

    // Set the default culture (English by default)
    spiderly.UseCulture("sr-Latn-RS");
});

UseTranslations

Two overloads are available:

  • spiderly.UseTranslations() — Registers the built-in JsonStringLocalizer, which loads {culture}.json files from the Translations directory at runtime.
  • spiderly.UseTranslations<TLocalizer>() — Registers a custom IStringLocalizer implementation (e.g., database-backed translations).

If neither is called, Spiderly registers a PassthroughStringLocalizer that returns the key itself as the value — so the app works without any translation configuration.

UseCulture

// Single language:
spiderly.UseCulture("sr-Latn-RS");

// Multiple languages (first = default):
spiderly.UseCulture("sr-Latn-RS", "en");

When multiple cultures are provided, per-request culture resolution is enabled via:

  • Accept-Language header
  • Query string: ?culture=sr-Latn-RS
  • Cookie

Translation Keys

Spiderly uses the following key conventions for entities and properties:

Entity Keys

Key patternPurposeExample
{EntityName}Singular name (forms, labels)"Product"
{EntityName}ListPlural name (table titles)"ProductList"
{EntityName}ExcelExportNameExcel export filename"ProductExcelExportName"

Property Keys

Key patternPurposeExample
{PropertyName}Input labels, validation messages"Name", "CreatedAt"

When you run spiderly init, the CLI seeds an en.json file with framework keys (Name, Description, CreatedAt, ModifiedAt, etc.). You only need to add translations for your own entities and properties.

Example

Given this entity:

public class UserExtended : BusinessObject<long>
{
    public string Email { get; set; }
}

Create Backend\YourAppName.Shared\Translations\en.json:

{
  "Email": "Email address",
  "UserExtended": "User",
  "UserExtendedExcelExportName": "Users",
  "UserExtendedList": "Users"
}

And Backend\YourAppName.Shared\Translations\sr-Latn-RS.json:

{
  "Email": "Email adresa",
  "UserExtended": "Korisnik",
  "UserExtendedExcelExportName": "Korisnici",
  "UserExtendedList": "Korisnici"
}

Adding a New Language

Create a new file, e.g., Backend\YourAppName.Shared\Translations\de.json, add your translations, and register the culture:

spiderly.UseCulture("en", "sr-Latn-RS", "de");

Using Translations in Backend Code

IStringLocalizer is automatically injected into all generated services and controllers. In your custom code, inject it via the constructor:

public class ProductService
{
    private readonly IStringLocalizer _localizer;

    public ProductService(IStringLocalizer localizer)
    {
        _localizer = localizer;
    }

    public string GetProductLabel()
    {
        // Returns translated value, or the key itself if not found
        return _localizer.Translate("Product");
    }
}

Helper Extensions

Spiderly provides two extension methods on IStringLocalizer:

MethodDescription
_localizer.Translate(key)Returns the translated value, or the key itself if not found
_localizer.GetExcelTranslation(excelKey, pluralKey)Tries the Excel-specific key first, falls back to the plural key
// Translate a key
string label = _localizer.Translate("Product");

// Excel filename with fallback
string filename = _localizer.GetExcelTranslation("ProductExcelExportName", "ProductList");
// Returns "Proizvodi" if ProductExcelExportName has a translation,
// otherwise falls back to the ProductList translation

Excel Export

The ExcelService.FillReportTemplateAsync method accepts IStringLocalizer for translating column headers. Generated Excel export endpoints automatically pass the injected localizer:

return File(
    fileContent,
    SettingsProvider.Current.ExcelContentType,
    Uri.EscapeDataString($"{_localizer.GetExcelTranslation("ProductExcelExportName", "ProductList")}.xlsx")
);

The {EntityName}ExcelExportName key controls the filename. If left empty, it falls back to {EntityName}List. If that's also empty, the key is used as-is.

FluentValidation Integration

When translations are enabled, FluentValidation automatically uses IStringLocalizer to resolve property display names. For example, if "BirthDate" is translated to "Birth Date", validation messages will say "Birth Date is required" instead of "BirthDate is required".

This is handled by the generated TranslatePropertiesConfiguration class — no manual setup needed.

Changing Default Language

To change the default language, call UseCulture() in your builder (see Registration). Then update the Angular frontend in Frontend\src\app\app.config.ts to match:

provideTransloco({
  config: {
    availableLangs: ['sr-Latn-RS'],
    defaultLang: 'sr-Latn-RS',
    reRenderOnLangChange: true,
  },
  loader: SpiderlyTranslocoLoader
}),

Custom Frontend Translations

You only need to add custom frontend translations if your app supports multiple languages. If you're only using a single language, you can simply use hardcoded strings.

Add a Translation Key-Value Pair

Open the appropriate language file under Frontend\src\assets\i18n folder, for example: en.json.

Then, add a new key-value entry like this anywhere in the file: "KeyForTranslation": "Translated text".

You can now reference this key in your TypeScript or HTML files.

Use Translation in TypeScript (.ts)

Inject the TranslocoService and use its translate method:

// ... other imports
import { TranslocoService } from '@jsverse/transloco';

@Component({
  templateUrl: './your.component.html',
})
export class YourComponent {

  constructor(
    // ... other injections
    private translocoService: TranslocoService
  ) {}

  ngOnInit() {
    const translatedText = this.translocoService.translate('KeyForTranslation');
  }
}

Use Translation in HTML (.html)

Add TranslocoDirective into Angular component imports:

@Component({
  templateUrl: './your.component.html',
  imports: [
    // ... other imports
    TranslocoDirective,
  ],
})
export class YourComponent {
  // ...
}

Use the directive with Angular's *transloco syntax:

<ng-container *transloco="let t">
    {{t('KeyForTranslation')}}
</ng-container>

Custom Backend Translations

You only need to add custom backend translations if your app supports multiple languages. If you're only using a single language, you can simply use hardcoded strings.

To use custom backend translations, add your keys to the JSON translation files and resolve them with IStringLocalizer:

// Add to en.json: "YourExceptionKey": "Your exception message."
// Add to sr-Latn-RS.json: "YourExceptionKey": "Vaša poruka o grešci."

throw new Exception(_localizer.Translate("YourExceptionKey"));

Spiderly automatically resolves the correct translation based on the active culture.