FluentLocalizer.Store.Json
1.0.0
dotnet add package FluentLocalizer.Store.Json --version 1.0.0
NuGet\Install-Package FluentLocalizer.Store.Json -Version 1.0.0
<PackageReference Include="FluentLocalizer.Store.Json" Version="1.0.0" />
<PackageVersion Include="FluentLocalizer.Store.Json" Version="1.0.0" />
<PackageReference Include="FluentLocalizer.Store.Json" />
paket add FluentLocalizer.Store.Json --version 1.0.0
#r "nuget: FluentLocalizer.Store.Json, 1.0.0"
#:package FluentLocalizer.Store.Json@1.0.0
#addin nuget:?package=FluentLocalizer.Store.Json&version=1.0.0
#tool nuget:?package=FluentLocalizer.Store.Json&version=1.0.0
FluentLocalizer JSON stores
FluentLocalizer.Store.Json contains three ITranslationStore implementations for JSON translation files: JsonFileStore, EmbeddedJsonStore, and HttpJsonStore. They share culture fallback, custom file mappings, nested-key lookup, and JSON parsing behavior.
Install
dotnet add package FluentLocalizer.Store.Json
Install FluentLocalizer.Extensions.DependencyInjection separately when you want IServiceCollection integration.
JSON format and keys
Keep translation files as readable JSON. Nested object properties are addressed with colon-separated keys. The filesystem store reads each needed document on demand and caches its parsed contents until a file change invalidates the cache or the store is disposed.
{
"Welcome": "Hello {name}!",
"Notifications": {
"MessageCount": "You have {quantity} unread messages."
}
}
The Notifications:MessageCount key resolves to the nested value. FluentLocalizer then formats the returned template using the requested culture.
JsonFileStore and HttpJsonStore support these layouts for either a short culture (it) or a regional culture (it-IT):
| Layout | Example | Key |
|---|---|---|
| Combined file | it-IT.json or it-IT/it-IT.json |
Notifications:MessageCount |
| Culture then namespace | it-IT.common.json |
common:Notifications:MessageCount |
| Namespace then culture | common.it-IT.json |
common:Notifications:MessageCount |
| Culture folder | it-IT/common.json |
common:Notifications:MessageCount |
Namespace files contain the nested section directly; combined files contain the namespace as a top-level JSON object. For a key, the mapped file is tried first, followed by culture/namespace files, the combined file and then the configured fallback culture.
An exact culture wins. A regional request such as it-IT may use a short it catalog. A short request such as en uses its own catalog when available; otherwise it selects the alphabetically first regional variant in the catalog, such as en-GB before en-US. A missing regional variant does not silently use a sibling: if only en-US exists, requesting en-GB throws FileNotFoundException. When no catalog for the requested language exists, the configured fallback culture is still used. FileMappings lets a culture use a custom relative JSON path.
Local files
Configure the consuming application to copy its JSON files to the output and publish directories. The package does not add build rules to the application project:
<ItemGroup>
<Content Include="Locales\**\*.json"
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
Relative ResourcesPath values use the application base directory. The store scans that directory recursively for *.json files. JsonFileStore requires filesystem access and is not supported in browser applications; use EmbeddedJsonStore or HttpJsonStore in the browser.
Locales/
en-US.json
it-IT.json
it-IT.common.json
it/
common.json
using FluentLocalizer;
using FluentLocalizer.Store.Json;
using var store = new JsonFileStore(new JsonFileStoreOptions
{
ResourcesPath = "Locales",
FallbackCulture = "en-US",
ReloadOnChange = true,
ThrowOnMissingStore = true
});
var translator = new Translator(store);
var greeting = translator.Get("Welcome").WithCulture("it-IT").WithArg("name", "Ada").Resolve();
ReloadOnChange watches filesystem files and is disabled by default. A file event invalidates only that document; a watcher error triggers a new scan and full cache invalidation. The store rejects symbolic links and reparse points in the configured resource directory and matching file paths; keep the directory writable only by trusted processes because a concurrent link replacement cannot be ruled out by a path check. Dispose the store when finished to release the watcher.
Embedded resources
Embed the locale files in the application assembly. The default resource folder filter is Locales; set ResourceAssembly when the files are in another assembly.
<ItemGroup>
<EmbeddedResource Include="Locales\**\*.json" />
</ItemGroup>
The store selects manifest resource names containing the ResourcesPath folder (default Locales) and recognizes culture files by their final filename, such as en-US.json.
using var store = new EmbeddedJsonStore(new EmbeddedJsonStoreOptions
{
ResourceAssembly = typeof(Program).Assembly,
ResourcesPath = "Locales",
FallbackCulture = "en-US"
});
Embedded resources work in browser applications because they are read from the assembly rather than the filesystem.
HTTP
Publish the locale files as static assets on the server, such as under wwwroot/locales in an ASP.NET Core or Blazor WebAssembly app. HttpJsonStore requests {ResourcesPath}/{culture}.json below HttpClient.BaseAddress and keeps parsed documents in memory. It does not own the supplied HttpClient.
using FluentLocalizer;
using FluentLocalizer.Store.Json;
var httpClient = new HttpClient { BaseAddress = new Uri("https://example.com/") };
using var store = new HttpJsonStore(httpClient, new HttpJsonStoreOptions
{
ResourcesPath = "locales",
FallbackCulture = "en-US",
ThrowOnMissingStore = true
});
await store.LoadAsync(["it-IT", "en-US"]); // preload for synchronous Resolve()
var translator = new Translator(store);
var message = await translator.Get("Welcome").WithCulture("it-IT").ResolveAsync();
await store.RefreshStoreAsync();
ResolveAsync() loads the required files on demand and stops downloading when it finds the key. To let HTTP discover available regional variants and preload every namespace for synchronous Resolve(), publish a manifest.json next to the locale files. It is a JSON array of relative paths:
["en-US.json", "en-US.common.json", "checkout.en-US.json", "it-IT/common.json"]
The manifest is optional for existing servers. Without it, the store probes conventional filenames directly, and LoadAsync() preloads combined files only. In that mode a short culture cannot discover an arbitrary regional variant, and namespace-only files must first be loaded by ResolveAsync(). With a manifest, LoadAsync() preloads every listed file for the requested cultures and their fallback; subsequent synchronous lookups require no network. Manifest paths are validated and cannot escape ResourcesPath.
RefreshStoreAsync() rechecks the manifest and files already loaded, including newly listed files. It sends Cache-Control: no-cache and, when supplied by the server, If-None-Match/If-Modified-Since; a 304 Not Modified keeps the existing parsed document. The refreshed manifest and all loaded cultures are published together only after every response parses successfully.
Keep source files as ordinary JSON. Configure gzip or Brotli Content-Encoding on the server or CDN to reduce transfer size. On desktop/server .NET, configure the caller-owned HttpClientHandler.AutomaticDecompression for the desired encodings; on WebAssembly, configure compression in the web server/browser path, since that handler property is not supported in the browser. The store receives decoded JSON from the HTTP stack. The store does not refresh on a timer; call RefreshStoreAsync() when the application needs newer values, and use normal HTTP cache headers for the deployment's freshness policy. A preload only covers files chosen by the application and does not make the first browser visit work offline.
The repository's Blazor WebAssembly sample preloads English and Italian at startup. Its + and − buttons update the plural count in component state, so the localized message changes on each click; the language selector changes the rendered locale.
Shared settings
All three store options inherit JsonStoreSettings:
FallbackCultureselects the fallback culture; defaults toen-US.FileMappingsmaps culture names to custom JSON file names.- Mapping values must be relative
.jsonpaths insideResourcesPath; traversal and absolute paths are rejected. HTTPResourcesPathmust be a relative URL path. ThrowOnMissingStoremakes missing translation files throw. When disabled, file and embedded-resource stores skip individual read or parse errors. The HTTP store always throws for failed requests and invalid JSON; when missing files are allowed, lookups with no value returnnull.MaxDocumentByteslimits each JSON file and HTTP response, includingmanifest.json. The default0disables the limit; configure a positive value when catalog files are not fully trusted.
The stores are separate classes so filesystem watching, assembly resource selection, and asynchronous HTTP loading remain explicit. They share the same fallback and JSON key resolution.
Treat translation JSON as deployment data. The stores return text; applications should render it through their UI framework's normal text escaping, not insert it as raw HTML. Large or hostile JSON can still consume substantial memory and formatting time, so deployments accepting untrusted catalogs should enforce response-size budgets at the server or HTTP client boundary.
Migration from the separate HTTP package
Replace the FluentLocalizer.Store.Http package reference with FluentLocalizer.Store.Json, and change using FluentLocalizer.Store.Http; to using FluentLocalizer.Store.Json;. The HttpJsonStore and HttpJsonStoreOptions types keep their names. JsonStore and JsonStoreOptions are deprecated; migrate to JsonFileStore or EmbeddedJsonStore and their corresponding options types.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- FluentLocalizer (>= 1.0.0)
- System.Text.Json (>= 10.0.12)
-
net10.0
- FluentLocalizer (>= 1.0.0)
-
net8.0
- FluentLocalizer (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 83 | 10/2/2026 |
| 0.1.0-alpha | 84 | 9/30/2026 |
| 0.0.1 | 131 | 7/30/2026 |