Skip to content

Latest commit

 

History

History
406 lines (314 loc) · 12.7 KB

File metadata and controls

406 lines (314 loc) · 12.7 KB

Yaml.Localization

Yaml.Localization

Better to fall asleep on Elm Street than use Blazor localization.

A modern localization library for .NET applications that uses YAML files instead of traditional .resx files. Works with any .NET application where IStringLocalizer dependency injection is available - from console applications to Blazor platforms, with automatic RTL/LTR handling.

Yaml Localization

Core Features

  • YAML-based localization - Readable .yaml format instead of .resx files
  • Microsoft IStringLocalizer compatibility with standard .NET localization API
  • Embedded Resource integration with compile-time embedded translations
  • File System support for direct YAML file reading
  • Multi-platform Blazor support - same code across all Blazor platforms
  • Automatic culture management with platform-specific storage (localStorage/cookie)
  • RTL/LTR support for automatic right-to-left language handling
  • Bootstrap theme integration with automatic CSS switching between RTL/LTR
  • SEO-friendly rendering with static content + interactive componets

Platform Support

Platforms

  • Blazor GirCore - Linux desktop applications (WebKit + GTK4)
  • Blazor Maui - Cross-platform desktop/mobile (Windows, macOS, iOS, Android, Tizen)
  • Blazor WebAssembly - Standalone WebAssembly applications
  • Blazor Web App - Server-side Blazor applications
  • Blazor Web App Client - Hosted WebAssembly applications
  • Everything else - Any platform/app where IStringLocalizer dependency injection is available

System Requirements

  • .NET 8.0 or later

Installation

Install the NuGet package

dotnet add package Yaml.Localization --version 10.0.0-rc.1

Install the Blazor assets

libman install @blazor/assets@1.0.0 \
  --provider unpkg \
  --destination wwwroot \
  --files css/bootstrap.min.css \
  --files css/bootstrap.rtl.min.css \
  --files js/blazor.body.min.js \
  --files js/blazor.body.min.js.map \
  --files js/blazor.head.min.js \
  --files js/blazor.head.min.js.map \
  --files js/blazor.web.head.min.js \
  --files js/blazor.web.head.min.js.map \
  --files js/bootstrap.bundle.min.js \
  --files js/bootstrap.bundle.min.js.map

YAML File Structure

Basic File Structure

en.yaml

"Hello World": "Hello World"
"Welcome {0}": "Welcome {0}"
"Language ({0})": "Language ({0})"

hu.yaml

"Hello World": "Helló Világ"
"Welcome {0}": "Üdvözöljük {0}"
"Language ({0})": "Nyelv ({0})"

CultureSettings.yaml

Cultures:
  - Name: en-US
    Active: true
    Default: true
  - Name: hu
    Active: true
  - Name: de-DE
    Active: true
  - Name: es-ES
    Active: true
  - Name: ar
    Active: true
    Rtl: true
  - Name: he-IL
    Active: true
    Rtl: true

Selector:
  en-US: English
  hu: Magyar
  de-DE: Deutsch
  es-ES: Español
  ar: العربية
  he-IL: עברית

CookieName: .lang
RedirectEndpoint: culture/set

Embedded Resource Configuration

One file per language (recommended)

  <ItemGroup>
    <Content Remove="I18N\*.yaml" />
    <EmbeddedResource
      Exclude="I18N\cultures.yaml"
      Type="Non-Resx"
      WithCulture="false"
      Include="I18N\*.yaml"
      LogicalName="$(RootNamespace).Lang.%(Filename).yaml"
    />

    <Content Remove="I18N\cultures.yaml" />
    <EmbeddedResource
      Include="I18N\cultures.yaml"
      LogicalName="CultureSettings.yaml"
    />
  </ItemGroup>

Result per language file

  • I18N\en.yamlMyApp.Lang.en.yaml
  • I18N\hu.yamlMyApp.Lang.hu.yaml
  • I18N\cultures.yamlCultureSettings.yaml

Component-level

<ItemGroup>
  <EmbeddedResource
    Exclude="Components\cultures.yaml"
    Type="Non-Resx"
    WithCulture="false"
    Include="Components\**\*.razor*.yaml"
    LogicalName="$(RootNamespace).$([System.String]::Copy('%(RelativeDir)').Replace('\','.').Replace('/','.'))$([System.String]::Copy('%(Filename)').Replace('.razor','')).yaml" />

  <Content Remove="Components\cultures.yaml" />
    <EmbeddedResource
      Include="Components\cultures.yaml"
      LogicalName="CultureSettings.yaml"
    />
</ItemGroup>

Result per component file

  • Components\cultures.yamlCultureSettings.yaml
  • Components\Home.razor.en.yamlMyApp.Components.Home.en.yaml
  • Components\Home.razor.hu.yamlMyApp.Components.Home.hu.yaml

Embedded Resource Patterns

Documentation on using LocalName

Platform Services

See the IPlatformService interface for platform-specific services.

RenderMode mapping for interactive components

  • GirCore/Maui: default!
  • WebApp: InteractiveServer
  • WebApp WebAssembly: InteractiveWebAssembly
  • WebAssembly: InteractiveWebAssembly

Application and Blazor Integration

Service Registration

builder.Services
// GirCore
    .AddSingleton<IPlatformService, GirCorePlatformService>()
// Maui Desktop  
    .AddSingleton<IPlatformService, MauiPointerPlatformService>()
// Maui Mobile
    .AddSingleton<IPlatformService, MauiTouchPlatformService>()
// Standalone WebAssembly
    .AddScoped<IPlatformService, WebAssemblyPlatformService>()
// Blazor App
    .AddScoped<IPlatformService, WebAppPlatformService>()
// Blazor App WebAssembly
    .AddScoped<IPlatformService, WebAppWebAssemblyPlatformService>()
  
    .AddScoped<ChangeThemeStore>()
    .AddScoped<CultureSelectorStore>()
    .AddYamlEmbeddedResourceLocalization(typeof(BlazorShared.Lang).Assembly);

Blazor Web App Server-side Configuration

// immediately before calling MapRazorComponents.
app.SetWebAppYamlLocalization();

Component Usage

@inject IStringLocalizer<Lang> L

<h1>@L["Hello World"]</h1>
<p>@L["Welcome {0}", "User"]</p>

Platform-specific rendering

SEO-friendly static content

<NavLink href="counter">@L["Counter"]</NavLink>
<NavLink href="weather">@L["Weather"]</NavLink>
<p>@L["About"]</p>

Interactive components with platform-specific render mode

<CultureSelector @rendermode="PlatformService.RenderMode" />
<ChangeTheme @rendermode="PlatformService.RenderMode" />

RTL/LTR Support

Writing direction settings in CultureSettings.yaml

Cultures:
  - Name: en-US
    Active: true
    Default: true
  - Name: es-ES
    Active: true
  - Name: ar
    Active: true
    Rtl: true
  - Name: he-IL
    Active: true
    Rtl: true

Bootstrap CSS automatic switching

Blazor GirCore/Maui/WebAssembly index.html

<html lang="en" dir="ltr" data-bs-theme="auto">

  <link rel="stylesheet" href="css/bootstrap.min.css" id="ltr-css" disabled>
  <link rel="stylesheet" href="css/bootstrap.rtl.min.css" id="rtl-css" disabled>

  <script>
      window.BlazorLTRId = "ltr-css";
      window.BlazorRTLId = "rtl-css";
  </script>
  <script src="js/blazor.head.min.js"></script>
JavaScript Control - index.html - blazor.head.min.js
  1. Detects the active culture's RTL property
  2. Enable/disable the appropriate CSS file
  3. Updates the <html dir=""> attribute
  4. Saves the setting
    • GirCore/Maui localStorage
    • WebAssembly cookie

Blazor Web App App.razor

<html lang="@CultureInfo.CurrentUICulture.TwoLetterISOLanguageName"
      dir="@(CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft ? "rtl" : "ltr")">

  @if (CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft)
  {
      <link rel="stylesheet" href="css/bootstrap.rtl.min.css" />
  }
  else
  {
      <link rel="stylesheet" href="css/bootstrap.min.css" />
  }

  <script>
      window.BlazorLTRId = "ltr-css";
      window.BlazorRTLId = "rtl-css";
  </script>
  <script src="js/blazor.web.head.min.js"></script>

JavaScript Control - App.razor - blazor.web.head.min.js

  1. Saves the setting to a cookie

Examples

Full working examples can be found in the samples folder:

Shared Components

  • BlazorShared - Shared UI components and localization files

Multi Blazor localization

Desktop application

  • GirCoreApp - Native GTK4 application with localization

Samples contain

  • RTL/LTR language support (العربية, עברית, English, Magyar, Deutsch)
  • Dark/Light/Auto theme switching
  • Platform-specific culture handling
  • SEO-friendly rendering for Web App

Localization-related files in samples

License

This project is licensed under the MIT License.