{"id":25066799,"url":"https://github.com/codingseb/localization","last_synced_at":"2025-10-11T17:23:04.703Z","repository":{"id":108935045,"uuid":"225412375","full_name":"codingseb/Localization","owner":"codingseb","description":"A suite to localize C# and WPF projects easily based on file format you choose.","archived":false,"fork":false,"pushed_at":"2025-05-16T13:24:53.000Z","size":493,"stargazers_count":41,"open_issues_count":5,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-04T12:33:36.077Z","etag":null,"topics":["csharp","json","language","localization","localize","localizer","markup","translate","translation","wpf","xaml","yaml"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codingseb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-12-02T15:49:44.000Z","updated_at":"2025-06-23T03:07:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"f23bb2be-051a-45bc-a6b8-a0ba802c0d9e","html_url":"https://github.com/codingseb/Localization","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/codingseb/Localization","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingseb%2FLocalization","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingseb%2FLocalization/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingseb%2FLocalization/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingseb%2FLocalization/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codingseb","download_url":"https://codeload.github.com/codingseb/Localization/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingseb%2FLocalization/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279008117,"owners_count":26084396,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","json","language","localization","localize","localizer","markup","translate","translation","wpf","xaml","yaml"],"created_at":"2025-02-06T20:27:59.654Z","updated_at":"2025-10-11T17:23:04.669Z","avatar_url":"https://github.com/codingseb.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Localization \nA suit of libs to localize C# and WPF projects easily based on file format you choose.\n\n__Replace the archived [TranslateMe](https://github.com/codingseb/TranslateMe) lib__\n\n|Nuget|Version|\n|---|---|\n|CodingSeb.Localization|[![NuGet Status](http://img.shields.io/nuget/v/CodingSeb.Localization.svg?style=flat\u0026max-age=86400)](https://www.nuget.org/packages/CodingSeb.Localization/)|\n|CodingSeb.Localization.JsonFileLoader|[![NuGet Status](http://img.shields.io/nuget/v/CodingSeb.Localization.JsonFileLoader.svg?style=flat\u0026max-age=86400)](https://www.nuget.org/packages/CodingSeb.Localization.JsonFileLoader/)|\n|CodingSeb.Localization.YamlFileLoader|[![NuGet Status](http://img.shields.io/nuget/v/CodingSeb.Localization.YamlFileLoader.svg?style=flat\u0026max-age=86400)](https://www.nuget.org/packages/CodingSeb.Localization.YamlFileLoader/)|\n|CodingSeb.Localization.WPF|[![NuGet Status](http://img.shields.io/nuget/v/CodingSeb.Localization.WPF.svg?style=flat\u0026max-age=86400)](https://www.nuget.org/packages/CodingSeb.Localization.WPF/)|\n|CodingSebLocalization.Fody|[![NuGet Status](http://img.shields.io/nuget/v/CodingSebLocalization.Fody.svg?style=flat\u0026max-age=86400)](https://www.nuget.org/packages/CodingSebLocalization.Fody/)|\n\n## The differents parts of the project\nThe library is composed of 4 parts :  \n\n  1. The part \"Core\" : Nuget \"CodingSeb.Localization\" Contains the dictionnary of all translations for a \"TextId\" in C#.  \n\t\n  2. A part \"FileLoader\" : Allow to open a type of file that contains translations to load in the dictionnary of the \"Core\" part.  \n  \n  3. The part to translate (localize) XAML (WPF) \"CodingSeb.Localization.WPF\". Provide `Tr` and `MultiTr` markups and some converters to use in Bindings. It use the \"Core\" in backend.  \n  \n  4. The part to translate ViewModel (`INotifyPropertyChanged`). Provide `Localize` attribute to put on ViewModel properties that are localized\n\n## Installation\n\n### With Nuget\n\n__For Simple C# projects__\n```\nPM\u003e Install-Package CodingSeb.Localization.JsonFileLoader\n```  \nor\n```\nPM\u003e Install-Package CodingSeb.Localization.YamlFileLoader\n```  \nor\n```\nPM\u003e Install-Package CodingSeb.Localization\n``` \nand implement your own [FileLoader](#implement-your-own-file-format).\n\n__For WPF projects__  \nAdd this :\n```\nPM\u003e Install-Package CodingSeb.Localization.WPF\n```\nand\n```\nPM\u003e Install-Package CodingSebLocalization.Fody\n```\n\n## Use it in C# :\n\n__To localize a text__\n\n```csharp\nusing CodingSeb.Localization\n/// ...\n\n// To translate a text in the current language\n// Loc.Tr(\"TextId\");\nLoc.Tr(\"SayHello\");\n// To show a default text if the text is not localized in the current language\n// Loc.Tr(\"TextId\", \"DefaultText\")\nLoc.Tr(\"SayHello\", \"Not localized\");\n// To Translate a text in fixed language\n// Loc.Tr(\"TextId\",\"DefaultText\" \"LanguageId\");\nLoc.Tr(\"SayHello\", null, \"fr\");\n\n```\n\n__To Change the current language__\n```csharp\nLoc.Instance.CurrentLanguage = \"en\";\nLoc.Instance.CurrentLanguage = \"fr\";\nLoc.Instance.CurrentLanguage = \"es\";\n// ...\n// To get availables languages\nCollection\u003cstring\u003e languages = Loc.Instance.AvailableLanguages;\n```\n\n### Use it In XAML (WPF) :\n(no xmlns needed Tr Markup is available as soon as CodingSeb.Localization.WPF is in project's references)\n\n__Simple localization with the Markup `Tr`__\n```xml\n\u003cTextBlock Text=\"{Tr 'SayHello'}\"/\u003e\n\u003cTextBlock Text=\"{Tr 'SayHello', DefaultText='Not localized'}\"/\u003e\n\u003cTextBlock Text=\"{Tr 'SayHello', LanguageId='fr'}\"/\u003e\n```\n\n_In general use XML escape to escape special characters. For single quote use ```[apos]``` to escape. XML escape does'nt work in this case for inline Tr markup. Or use the following format :_\n\n```xml\n\u003c!-- textId can be automatically calculate (with x:Name and the context of the element) --\u003e\n\u003cLabel x:Name=\"lbMyLabel\" \u003e\n  \u003cLabel.Content\u003e\n    \u003cTr DefaultText=\"Text with a ' here\" /\u003e\n  \u003c/Label.Content\u003e\n\u003c/Label\u003e\n```\n\n__To Translate with Bindings__\n\n```xml\n\u003c!-- To use the Binding as flexible TextId --\u003e\n    \u003cTextBlock Text=\"{Tr {Binding MyPropertyAsTextId}, DefaultText='Not localized'}\"/\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock Text=\"{Tr TextIdBinding={Binding MyPropertyAsTextId}, DefaultText='Not localized'}\"/\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock Text=\"{Binding MyPropertyAsTextId, Converter={TrTextIdConverter DefaultText='Not localized'}\"/\u003e\n\u003c!-- With StringFormat of the TextId (for enum for example) --\u003e\n    \u003cTextBlock Text=\"{Tr {Binding MyPropertyAsPartOfTextId}, TextIdStringFormat='MyEnum{0}'}\"/\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock Text=\"{Tr TextIdBinding={Binding MyPropertyAsPartOfTextId}, TextIdStringFormat='MyEnum{0}'}\"/\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock Text=\"{Binding MyPropertyAsPartOfTextId, Converter={TrTextIdConverter TextIdStringFormat='MyEnum{0}'}\"/\u003e\n\n\u003c!-- To use the Binding as flexible LanguageId --\u003e\n   \u003cTextBlock Text=\"{Binding MyPropertyAsLanguageId, Converter={TrLanguageIdConverter TextId='SayHello'}\" /\u003e\n\n\u003c!-- To use the Binding as a value to inject in the localized text --\u003e\n\n    \u003c!-- The translation would be \"Hello {0}\" or \"Bonjour {0}\"  --\u003e\n    \u003cTextBlock Text=\"{Tr SayHello, {Binding FirstName}}\" /\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock Text=\"{Tr SayHello, StringFormatArgBinding={Binding FirstName}}\" /\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock Text=\"{Binding FirstName, Converter={TrStringFormatConverter TextId='SayHello'}\" /\u003e\n\n\u003c!-- The translation would be \"Hello {0} {1}\" or \"Bonjour {0} {1}\"  --\u003e\n    \u003cTextBlock Text=\"{Tr SayHello, {Binding FirstName}, {Binding LastName}}\" /\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock\u003e\n        \u003cTextBlock.Text\u003e\n            \u003cTr TextId=\"SayHello\"\u003e\n\t        \u003cTr.StringFormatArgsBindings\u003e\n                    \u003cBinding Path=\"FirstName\" /\u003e\n                    \u003cBinding Path=\"LastName\" /\u003e\n\t\t\u003c/Tr.StringFormatArgBinding\u003e\n            \u003c/Tr\u003e\n        \u003c/TextBlock.Text\u003e\n    \u003c/TextBlock\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock\u003e\n        \u003cTextBlock.Text\u003e\n            \u003cMultiBinding Converter=\"{TrStringFormatMultiValuesConverter TextId='SayHello'}\"\u003e\n                \u003cBinding Path=\"FirstName\" /\u003e\n                \u003cBinding Path=\"LastName\" /\u003e\n            \u003c/MultiBinding\u003e\n        \u003c/TextBlock.Text\u003e\n    \u003c/TextBlock\u003e\n\n```\n\n__To concatenate some translations__\n```xml\n\u003cTextBlock\u003e\n    \u003cTextBlock.Text\u003e\n        \u003cMultiTr\u003e\n            \u003cTr TextId=TextId1 /\u003e\n            \u003cTr TextId=TextId2 /\u003e\n\t    \u003c!-- ... --\u003e\n        \u003c/MultiTr\u003e\n    \u003c/TextBlock.Text\u003e\n\u003c/TextBlock\u003e\n\u003c!-- or simpler syntax --\u003e\n\u003cTextBlock Text=\"{MultiTr {Tr TextId1}, {Tr TextId2}}\" /\u003e\n\u003c!-- or even simpler --\u003e\n\u003cTextBlock Text=\"{MultiTr TextId1, TextId2}\" /\u003e\n\n\u003c!-- To specify the way it concatenate (by default separate by a space) --\u003e\n    \u003cTextBlock Text=\"{MultiTr TextId1, TextId2, Separator=' - '}\" /\u003e\n    \u003c!-- or --\u003e\n    \u003cTextBlock Text=\"{MultiTr TextId1, TextId2, StringFormat='{0}, {1}.'}\" /\u003e\n```\n\n*Remark : By default the translation made in the XAML are automatically updated when current language changed.*  \n*In templates (`DataTemplate`, `ControlTemplate`) Bindings with TrConverters do not update when language change. Prefer to use `Tr` Markup with bindings in templates*\n\n__To Change the current language from the xaml__\n\n```xml\n\u003c!-- to add in the root tag of the xaml file  : \nxmlns:loc=\"clr-namespace:Localization;assembly=Localization\" --\u003e\n\u003cComboBox ItemsSource=\"{Binding AvailableLanguages, Source={x:Static loc:Loc.Instance}}\"\n          SelectedItem=\"{Binding CurrentLanguage, Source={x:Static loc:Loc.Instance}}\"/\u003e\n\n```\n\n### Use it In ViewModel (Fody) :\n\nYou can use the Property attibute `Localize` to automatically generate the PropertyChanged event for the property when CurrentLanguageChanged.\n\n```c#\npublic class LocalizedWithFodyClass : INotifyPropertyChanged\n{\n    [Localize]\n    public string TestProperty =\u003e Loc.Tr(\"TestLabel\");\n\n    [Localize(nameof(TextIdInAttribute))]\n    public string TextIdInAttribute { get; set; }\n\n    // ...\n\n    public event PropertyChangedEventHandler PropertyChanged;\n\n    public void NotifyPropertyChanged(string propertyName)\n    {\n        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n    }\n}\n```\n\nThe specific code is injected at compile time thanks to [Fody](https://github.com/Fody/Fody).\nIt is compatible with [PropertyChanged.Fody](https://github.com/Fody/PropertyChanged) or other similar fody addins like [ReactiveUI.Fody](https://github.com/kswoll/ReactiveUI.Fody). Just ensure that CodingSebLocalization is defined after in the `FodyWeavers.xml` file.\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cWeavers xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"FodyWeavers.xsd\"\u003e\n  \u003cPropertyChanged /\u003e\n  \u003c!-- or --\u003e\n  \u003cReactiveUI /\u003e\n  \u003c!-- ... --\u003e\n  \u003cCodingSebLocalization /\u003e\t\n\u003c/Weavers\u003e\n```\n\n## OK But... ...How I define my translations ?\n### JsonFileLoader\nWith the default JsonFileLoader, Translations are defined in JSON files with the extension \"*.loc.json\".\n\nHere an example :\n\n```json\n{\n  \"LanguageName\": {\n    \"en\": \"English\",\n    \"es\": \"Español\",\n    \"fr\": \"Français\"\n  },\n  \"[Localization.Examples.MainWindow].lblCurrentLanguage[Label].Content\": {\n    \"en\": \"Current language\",\n    \"es\": \"Lenguaje actual\",\n    \"fr\": \"Langue courrante\"\n  },\n  \"[Localization.Examples.MainWindow].lblHelloInCurrentLanguage[Label].Content\": {\n    \"en\": \"Hello\",\n    \"es\": \"Hola\",\n    \"fr\": \"Bonjour\"\n  },\n  \"HelloInCurrentLanguage\": {\n    \"en\": \"Hello in the current language\",\n    \"es\": \"Hola en la lengua actual\",\n    \"fr\": \"Bonjour dans la langue actuelle\"\n  },\n  \"[Localization.Examples.MainWindow].lblHelloInCurrentLanguage[Label].ToolTip\": {\n    \"en\": \"In english\",\n    \"es\": \"En español\",\n    \"fr\": \"En français\"\n  }\n}\n```\n\nIt's also possible to create a hierarchy :\n\n```json\n{\n    \"AppName\": {\n        \"MainMenu\": {\n          \"FileMenuItem\": {\n            \"Header\": {\n              \"en\": \"_File\",\n              \"fr\": \"_Fichier\"\n            },\n            \"NewMenuItem\": {\n              \"Header\": {\n                \"en\": \"_New\",\n                \"fr\": \"_Nouveau\"\n              }\n            },\n            \"OpenMenuItem\": {\n              \"Header\": {\n                \"en\": \"_Open\",\n                \"fr\": \"_Ouvrir\"\n              }\n            },\n            \"...\"\n        }\n    }\n}\n```\n\nTo use like this : \n\n```csharp\nLoc.Tr(\"AppName.MainMenu.FileMenuItem.Header\");\nLoc.Tr(\"AppName.MainMenu.FileMenuItem.NewMenuItem.Header\");\nLoc.Tr(\"AppName.MainMenu.FileMenuItem.OpenMenuItem.Header\");\n```\n\nor like this in XAML :\n```xml\n\u003cMenu\u003e\n    \u003cMenuItem Header=\"{Tr 'AppName.MainMenu.FileMenuItem.Header', DefaultText='_File'}\"\u003e\n        \u003cMenuItem Header=\"{Tr 'AppName.MainMenu.FileMenuItem.NewMenuItem.Header', DefaultText='_New'}\" \n                  Command=\"ApplicationCommands.New\" /\u003e\n        \u003cMenuItem Header=\"{Tr 'AppName.MainMenu.FileMenuItem.OpenMenuItem.Header', DefaultText='_Open'}\" \n                  Command=\"ApplicationCommands.Open\" /\u003e\n        \u003c!-- ... --\u003e\n\n``` \n\nAnd to load these files :\n\n```csharp\nusing CodingSeb.Localization.Loaders;\n// You need first to add the specific fileLoader \nLocalizationLoader.Instance.FileLanguageLoaders.Add(new JsonFileLoader());\n\n// ...\n\n// And then you can add your localization file\nLocalizationLoader.Instance.AddFile(@\"PathToTheFile\\Example1.loc.json\");\n// or load directly a directory with multiple \"*.loc.json\" files.\nLocalizationLoader.Instance.AddDirectory(@\"PathToTheDirectory\");\n```\n\nSo you can change the text of your app or translate it in a new language without recompile all your application.\n\n```csharp\n// or you can also load a translation by code (textId, languageId, value)\nLocalizationLoader.Instance.AddTranslation(\"SayHello\", \"en\", \"Hello\" );\nLocalizationLoader.Instance.AddTranslation(\"SayHello\", \"es\", \"Hola\" );\nLocalizationLoader.Instance.AddTranslation(\"SayHello\", \"fr\", \"Bonjour\" );\n```\n\nOr if you have a custom `Loc` instance\n\n```csharp\nvar customLocInstance = new Loc();\nvar loaderForCustomLoc = new LocalizationLoader(customLocInstance);\nloaderForCustomLoc.AddFile(@\"path\\to\\your\\file.loc.json\");\nloaderForCustomLoc.AddFolder(@\"path\\to\\your\\folder\");\nloaderForCustomLoc.AddTranslation(\"SayHello\", \"en\", \"Hello\" );\nloaderForCustomLoc.AddTranslation(\"SayHello\", \"es\", \"Hola\" );\nloaderForCustomLoc.AddTranslation(\"SayHello\", \"fr\", \"Bonjour\" );\n\n### YamlFileLoader\nFor Yaml format of localization files \"*.loc.yaml\" it's working the same way as the Json\n\n### Implement your own file format\nIf you want to support an other format than json or yaml, you can create your custom FileLanguageLoader.\nSimply create a class that implement the ILocalizationFileLoader interface and add an instance of your class in the LocalizationLoader :\n\n```csharp\nLocalizationLoader.Instance.FileLanguageLoaders.Add(new YouCustomClassImplementingILocalizationFileLoader());\n```\n\n## Find Missing Translations\nYou can activate an option to be notify when a translation is missing. \n\n```csharp\n// with all TextId and LanguageId that are missing when you trying to translate them.\nLoc.Instance.LogOutMissingTranslations = true;\nLoc.Instance.MissingTranslationFound += Loc_MissingTranslationFound;\n```\n\nIf you want to log it automatically in a json file you can also use the class `JsonMissingTranslationsLogger` in the \"CodingSeb.Localization.JsonFileLoader\" package.\n\n```csharp\nJsonMissingTranslationsLogger.EnableLogFor(Loc.Instance);\n// or\nJsonMissingTranslationsLogger.EnableLogFor(customLocInstance);\n```\n\n## Tr and WPF Styles\nThe `Tr`markup is usable in Styles. but if a Trigger is used the `Tr` markup only works if used in static mode : `\u003cTr IsDynamic=False ...`.\nIn dynamic mode the `Tr`markup create in backend a Binding and do not allow to be modified by a Datatrigger.\nTo do a localization in a same manner, prefer to use a binding with a `TrTextIdConverter` in place of a trigger.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodingseb%2Flocalization","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodingseb%2Flocalization","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodingseb%2Flocalization/lists"}