kli.Localize 2.0.4

dotnet add package kli.Localize --version 2.0.4
                    
NuGet\Install-Package kli.Localize -Version 2.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="kli.Localize" Version="2.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="kli.Localize" Version="2.0.4" />
                    
Directory.Packages.props
<PackageReference Include="kli.Localize" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add kli.Localize --version 2.0.4
                    
#r "nuget: kli.Localize, 2.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package kli.Localize@2.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=kli.Localize&version=2.0.4
                    
Install as a Cake Addin
#tool nuget:?package=kli.Localize&version=2.0.4
                    
Install as a Cake Tool

Localize

Simple package to localize strings from json files via static source code generation.

Implemented via C# source generators

CI\CD

Usage

Also see example project

Install the nuget package

Add a Nuget package reference to the project file in the project you want to localize:

<PackageReference Include="kli.Localize" Version="<version>" />

Create *.json files for your localized texts.

Example:

{
    "SampleText": "FooBar",
    "Other": "Text42",
    "NestedItems": {
      "Are": "also supported"
    }
}

Name your localization files, including the culture according to the pattern: <FileName>_<CultureInfo.Name>.json (e.g. Locale_de.json). For other cultures follow the same pattern (e.g. Locale_en-US.json for American English or Locale_en.json for English).
You have to specify which given culture is the neutral culture (the fallback used if there is no localization found for a specific culture) via the NeutralCulture attribute on the Localize element.

locale_files image

Add json files to csproj

In an ItemGroup in your csproj file add an Localize element for each localization json file, include other cultures via glob pattern. Set the Include attribute to the path of the file and specify the neutral culture via the NeutralCulture attribute

Example:

<Project Sdk="Microsoft.NET.Sdk">
    <ItemGroup>
        <PackageReference Include="kli.Localize" Version="1.0.*" />

        <Localize Include="TestLocalizations\Locale_*.json" NeutralCulture="en"/>
    </ItemGroup>
</Project>

This means: if you have a Locale_en.json and a Locale_en-US.json add Locale_*.json as <Localize>, and specify either en or en_US as NeutralCulture.
Add other files the same way in another Localize element.

Use it in your code

Now you should be able to locate the generated source code in your project under Dependencies/Analyzers.
Of course you can also view and debug the generated source code.

generated_1 image

<details> <summary>Generated code example</summary>

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by kli.Localize.Generator.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace kli.Localize.Example.Localizations
{
    using System;
    using System.Globalization;
    using System.Collections.Generic;
    using Translations = System.Collections.Generic.Dictionary<string, string>;

    public sealed class Locale
    {
        private static readonly LocalizationProvider provider = new LocalizationProvider();
        public static IDictionary<string, string> GetAll(CultureInfo cultureInfo = null) => provider.GetValues(cultureInfo ?? CultureInfo.CurrentUICulture);
        public static string GetString(string key, CultureInfo cultureInfo = null) => provider.GetValue(key, cultureInfo ?? CultureInfo.CurrentUICulture);
        ///<summary>Similar to: Hallo Welt (German)</summary>
        public static string MyText => provider.GetValue(nameof(MyText), CultureInfo.CurrentUICulture);
        private class LocalizationProvider
        {
            delegate bool SelectorFunc<T>(Translations translations, out T arg);
            internal string GetValue(string key, CultureInfo cultureInfo)
            {
                bool ValueSelector(Translations translations, out string value)
                {
                    if (translations.TryGetValue(key, out value))
                        return true;
                    value = key;
                    return false;
                }

                return TraverseCultures<string>(cultureInfo, ValueSelector);
            }

            internal IDictionary<string, string> GetValues(CultureInfo cultureInfo)
            {
                bool ValueSelector(Translations translations, out Translations value)
                {
                    value = translations;
                    return true;
                }

                return TraverseCultures<Translations>(cultureInfo, ValueSelector);
            }

            private T TraverseCultures<T>(CultureInfo cultureInfo, SelectorFunc<T> selectorFunc)
            {
                if (resources.TryGetValue(cultureInfo, out Translations translations))
                {
                    if (selectorFunc(translations, out T result) || cultureInfo == CultureInfo.InvariantCulture)
                        return result;
                }

                return TraverseCultures<T>(cultureInfo.Parent, selectorFunc);
            }

            private static readonly Translations invariant = new()
            {{"MyText", "Hallo Welt (German)"}, };
            private static readonly Translations en = new()
            {{"MyText", "Hello World (English)"}, };
            private static readonly Dictionary<CultureInfo, Translations> resources = new()
            {{CultureInfo.InvariantCulture, invariant}, {new CultureInfo("en"), en}, };
        }
    }
}

</details>

Import the namespace where you put your *.json files and use the generated code to access your localizations.
Access is based on CultureInfo.CurrentUICulture

useit image

Namespace generation

The namespace is generated using the following pattern:
rootnamespace + relative directory structure

This behaviour can be overridden with the NamespaceName attribute on the Localize element.

Class naming

The default class name in the generated code is the filename without the culture.

This behaviour can be overridden with the ClassName attribute on the Localize element.

Changelog

Help! Why is no code generated?

Directly after including the package sometimes the tooling (Visual Studio) gets stuck. If you encounter any problems with source generation try to restart Visual Studio and/or check the build log for warnings/errors.

Need help? Problems?

Feel free to create an Issue

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

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
2.0.4 1,160 10/1/2025
1.0.7 5,394 4/10/2025
1.0.6 4,043 9/17/2024
0.8.3 13,991 2/27/2023
0.7.14 1,922 3/31/2022
0.7.13 629 12/15/2021
0.7.9 3,083 8/4/2021