From f342e1cd41ddcfc9e3cb9421a0686780b84c883d Mon Sep 17 00:00:00 2001 From: Peter Kurhajec <61538034+PTKu@users.noreply.github.com> Date: Thu, 29 Jan 2026 11:54:21 +0100 Subject: [PATCH 1/3] Enhance localization support by updating SetLocalizationResource method to accept target assembly and improving label retrieval for culture awareness --- .../Templates/TemplateBase.razor.cs | 3 ++- .../src/ixc/Properties/launchSettings.json | 4 ++++ .../src/AXSharp.Connector/Localizations/Translator.cs | 7 ++++++- .../Localizations/TranslatorExtensionTests.cs | 7 ++++--- .../Localizations/TranslatorTests.cs | 11 ++++++----- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/AXSharp.blazor/src/AXSharp.Presentation.Blazor.Controls/Templates/TemplateBase.razor.cs b/src/AXSharp.blazor/src/AXSharp.Presentation.Blazor.Controls/Templates/TemplateBase.razor.cs index 804e7b8b..f2b7af3d 100644 --- a/src/AXSharp.blazor/src/AXSharp.Presentation.Blazor.Controls/Templates/TemplateBase.razor.cs +++ b/src/AXSharp.blazor/src/AXSharp.Presentation.Blazor.Controls/Templates/TemplateBase.razor.cs @@ -120,7 +120,8 @@ protected override Task OnInitializedAsync() /// protected string GetLabel() { - return Onliner.GetAttributeName(CultureInfo.CurrentUICulture) + (string.IsNullOrWhiteSpace(Onliner.AttributeUnits) ? null : $" [{Onliner.AttributeUnits}]"); + var retVal = Onliner.GetAttributeName(CultureInfo.CurrentUICulture) + (string.IsNullOrWhiteSpace(Onliner.AttributeUnits) ? null : $" [{Onliner.AttributeUnits}]"); + return retVal; } } } diff --git a/src/AXSharp.compiler/src/ixc/Properties/launchSettings.json b/src/AXSharp.compiler/src/ixc/Properties/launchSettings.json index ac0f0bfa..594fce4a 100644 --- a/src/AXSharp.compiler/src/ixc/Properties/launchSettings.json +++ b/src/AXSharp.compiler/src/ixc/Properties/launchSettings.json @@ -65,6 +65,10 @@ "commandName": "Project", "commandLineArgs": "--skip-deps", "workingDirectory": "c:\\W\\Develop\\gh\\inxton\\simatic-ax\\ppppppsjsjsjs\\MTS258585\\ax\\" + }, + "axopen-traversal-in-tepmplates": { + "commandName": "Project", + "workingDirectory": "C:\\W\\Develop\\gh\\inxton\\simatic-ax\\axopen.templates\\axopen\\src\\traversals\\apax" } } } \ No newline at end of file diff --git a/src/AXSharp.connectors/src/AXSharp.Connector/Localizations/Translator.cs b/src/AXSharp.connectors/src/AXSharp.Connector/Localizations/Translator.cs index 0e59580f..97891c54 100644 --- a/src/AXSharp.connectors/src/AXSharp.Connector/Localizations/Translator.cs +++ b/src/AXSharp.connectors/src/AXSharp.Connector/Localizations/Translator.cs @@ -52,7 +52,8 @@ public string Translate(string originalString, ITwinElement twin, CultureInfo cu /// Sets the localization resource for this translator. /// /// Type of resource to be used. - public void SetLocalizationResource(Type resourceType) + /// + public void SetLocalizationResource(Type resourceType, Assembly targetAssembly = null) { if (resourceType != null) { @@ -61,6 +62,10 @@ public void SetLocalizationResource(Type resourceType) IgnoreCase = true }; } + else + { + Console.WriteLine($"No resource type provided for `{targetAssembly?.FullName}`"); + } } internal static IEnumerable GetTranslatable(string input, diff --git a/src/AXSharp.connectors/tests/AXSharp.ConnectorTests/AXSharp.ConnectorTests/Localizations/TranslatorExtensionTests.cs b/src/AXSharp.connectors/tests/AXSharp.ConnectorTests/AXSharp.ConnectorTests/Localizations/TranslatorExtensionTests.cs index d58f5afb..31c576a1 100644 --- a/src/AXSharp.connectors/tests/AXSharp.ConnectorTests/AXSharp.ConnectorTests/Localizations/TranslatorExtensionTests.cs +++ b/src/AXSharp.connectors/tests/AXSharp.ConnectorTests/AXSharp.ConnectorTests/Localizations/TranslatorExtensionTests.cs @@ -9,6 +9,7 @@ namespace AXSharp.ConnectorTests.Localizations using Xunit; using NSubstitute; using AXSharp.Connector; + using System.Reflection; public static class TranslatorExtensionTests { @@ -33,7 +34,7 @@ public static void Translate_localized_string_keep_default_translation() // Arrange var twin = Substitute.For(); var interpreter = new Translator(); - interpreter.SetLocalizationResource(typeof(AXSharp.ConnectorTests.Localizations.Resources.Dictionary)); + interpreter.SetLocalizationResource(typeof(AXSharp.ConnectorTests.Localizations.Resources.Dictionary), Assembly.GetExecutingAssembly()); twin.Interpreter.Returns(interpreter); var originalString = "<#In the middle of the night#>"; @@ -70,7 +71,7 @@ public static void Translate_partially_localized_string_translate_to_sk() // Arrange var twin = Substitute.For(); var interpreter = new Translator(); - interpreter.SetLocalizationResource(typeof(AXSharp.ConnectorTests.Localizations.Resources.Dictionary)); + interpreter.SetLocalizationResource(typeof(AXSharp.ConnectorTests.Localizations.Resources.Dictionary), Assembly.GetExecutingAssembly()); twin.Interpreter.Returns(interpreter); var originalString = "(A4)<#In the middle of the night#> 1.5"; var expected = "(A4)Uprostred noci 1.5"; @@ -110,7 +111,7 @@ public static void Translate_partially_localized_inexisting_translation() // Arrange var twin = Substitute.For(); var interpreter = new Translator(); - interpreter.SetLocalizationResource(typeof(AXSharp.ConnectorTests.Localizations.Resources.Dictionary)); + interpreter.SetLocalizationResource(typeof(AXSharp.ConnectorTests.Localizations.Resources.Dictionary), Assembly.GetExecutingAssembly()); twin.Interpreter.Returns(interpreter); var originalString = "(A4)<#In the middle of the night does not exist#> 1.5"; diff --git a/src/AXSharp.connectors/tests/AXSharp.ConnectorTests/AXSharp.ConnectorTests/Localizations/TranslatorTests.cs b/src/AXSharp.connectors/tests/AXSharp.ConnectorTests/AXSharp.ConnectorTests/Localizations/TranslatorTests.cs index f1e34c75..035e8d02 100644 --- a/src/AXSharp.connectors/tests/AXSharp.ConnectorTests/AXSharp.ConnectorTests/Localizations/TranslatorTests.cs +++ b/src/AXSharp.connectors/tests/AXSharp.ConnectorTests/AXSharp.ConnectorTests/Localizations/TranslatorTests.cs @@ -1,12 +1,13 @@ namespace AXSharp.ConnectorTests.Localizations { + using AXSharp.Connector; using AXSharp.Connector.Localizations; + using AXSharp.ConnectorTests.Localizations.Resources; + using NSubstitute; using System; using System.Globalization; + using System.Reflection; using Xunit; - using NSubstitute; - using AXSharp.Connector; - using AXSharp.ConnectorTests.Localizations.Resources; public class TranslatorTests { @@ -54,7 +55,7 @@ public void CanCallSetLocalizationResource() var resourceType = typeof(AXSharp.ConnectorTests.Localizations.Resources.Dictionary); // Act - _testClass.SetLocalizationResource(resourceType); + _testClass.SetLocalizationResource(resourceType, Assembly.GetExecutingAssembly()); } [Fact] @@ -80,7 +81,7 @@ public void Translate_falls_back_to_library_resource_when_primary_does_not_have_ // Arrange Translator.SetPrimaryTranslatorResource(typeof(OverrideApplication)); var translator = new Translator(); - translator.SetLocalizationResource(typeof(OverrideLibrary)); + translator.SetLocalizationResource(typeof(OverrideLibrary), Assembly.GetExecutingAssembly()); var twin = Substitute.For(); var originalString = "<#Library only#>"; From 12821686977775ef79b2ff75615b98e9da89638f Mon Sep 17 00:00:00 2001 From: Peter Kurhajec <61538034+PTKu@users.noreply.github.com> Date: Thu, 29 Jan 2026 13:32:17 +0100 Subject: [PATCH 2/3] Refactor localization resource handling to improve clarity and fallback logic for project root namespace --- .../src/AXSharp.Cs.Compiler/CsProject.cs | 37 +++++++++++++++++-- .../Localizations/Translator.cs | 6 +-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/CsProject.cs b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/CsProject.cs index 9d1fef09..0d1cceb9 100644 --- a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/CsProject.cs +++ b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/CsProject.cs @@ -35,7 +35,7 @@ public class CsProject : ITargetProject public CsProject(AXSharpProject AXSharpProject) { AxSharpProject = AXSharpProject; - ProjectRootNamespace = MakeValidIdentifier(AXSharpProject.AxProject.ProjectInfo.Name); + ProjectRootNamespace = GetProjectRootNamespace(); } private AXSharpProject AxSharpProject { get; } @@ -97,6 +97,35 @@ private static string GetExecutingAssemblyPath() return assemblyPath!; } + /// + /// Gets the project root namespace from the csproj file if defined, otherwise uses the project name. + /// + /// The root namespace for the project + private string GetProjectRootNamespace() + { + try + { + if (File.Exists(CsProjectFile)) + { + var xDocument = XDocument.Load(CsProjectFile); + var rootNamespaceElement = xDocument.Descendants("RootNamespace").FirstOrDefault(); + + if (rootNamespaceElement != null && !string.IsNullOrWhiteSpace(rootNamespaceElement.Value)) + { + return rootNamespaceElement.Value; + } + } + } + catch (Exception ex) + { + // Log the error but continue with fallback + Log.Logger.Warning($"Failed to read RootNamespace from {CsProjectFile}: {ex.Message}"); + } + + // Fallback to csproj filename (without extension) if RootNamespace is not defined + return MakeValidIdentifier(Path.GetFileNameWithoutExtension(CsProjectFile)); + } + private string EnsureOutputFolder() { @@ -209,9 +238,9 @@ public static PlcTranslator Instance private PlcTranslator() {{ - var defaultResourceType = Assembly.GetAssembly(typeof({this.ProjectRootNamespace}.PlcTranslator)) - .GetType(""{this.ProjectRootNamespace}.Resources.PlcStringResources""); - this.SetLocalizationResource(defaultResourceType); + var assembly = Assembly.GetAssembly(typeof({this.ProjectRootNamespace}.PlcTranslator)); + var resource = assembly.GetType(""{this.ProjectRootNamespace}.Resources.PlcStringResources""); + this.SetLocalizationResource(resource, assembly); }} }} }}"; diff --git a/src/AXSharp.connectors/src/AXSharp.Connector/Localizations/Translator.cs b/src/AXSharp.connectors/src/AXSharp.Connector/Localizations/Translator.cs index 97891c54..bd8b045a 100644 --- a/src/AXSharp.connectors/src/AXSharp.Connector/Localizations/Translator.cs +++ b/src/AXSharp.connectors/src/AXSharp.Connector/Localizations/Translator.cs @@ -52,8 +52,8 @@ public string Translate(string originalString, ITwinElement twin, CultureInfo cu /// Sets the localization resource for this translator. /// /// Type of resource to be used. - /// - public void SetLocalizationResource(Type resourceType, Assembly targetAssembly = null) + /// + public void SetLocalizationResource(Type resourceType, Assembly originAssembly = null) { if (resourceType != null) { @@ -64,7 +64,7 @@ public void SetLocalizationResource(Type resourceType, Assembly targetAssembly = } else { - Console.WriteLine($"No resource type provided for `{targetAssembly?.FullName}`"); + Console.WriteLine($"No resource type provided for `{originAssembly?.FullName}`"); } } From 3788fbb5f1e1ff7aafa493a85167fdd1cda7ea30 Mon Sep 17 00:00:00 2001 From: Peter Kurhajec <61538034+PTKu@users.noreply.github.com> Date: Thu, 29 Jan 2026 14:08:13 +0100 Subject: [PATCH 3/3] Update PlcTranslator resource loading and add test docs Refactored PlcTranslator to pass both resource type and assembly to SetLocalizationResource, improving localization resource resolution. Added comments in integration test files to document relevant file paths for traceability; no changes to test logic. --- .../Integration.Cs/IxProjectTests.IntegrationCs.cs | 8 ++++++++ .../samples/units/expected/ax/.g/PlcResources.g.cs | 6 +++--- .../samples/units/expected/tia/.g/PlcResources.g.cs | 6 +++--- .../integration/expected/app/ix/.g/PlcResources.g.cs | 6 +++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Integration.Cs/IxProjectTests.IntegrationCs.cs b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Integration.Cs/IxProjectTests.IntegrationCs.cs index affc78de..46a8d493 100644 --- a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Integration.Cs/IxProjectTests.IntegrationCs.cs +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Integration.Cs/IxProjectTests.IntegrationCs.cs @@ -15,6 +15,10 @@ namespace AXSharp.CompilerTests.Integration.Cs; +/* + * C:\W\Develop\gh\inxton\simatic-ax\axsharp\src\AXSharp.compiler\tests\AXSharp.Compiler.CsTests\bin\Debug\net10.0\samples\units\samples\units\ix + * C:\W\Develop\gh\inxton\simatic-ax\axsharp\src\AXSharp.compiler\tests\AXSharp.Compiler.CsTests\samples\units\expected + */ public class IxProjectTestsAx : IxProjectTests { @@ -226,6 +230,10 @@ public void should_generate_all_even_when_fails_somewhere() [Fact] public void should_retrieve_dependencies_and_use_types_from_referenced_project() { + /* + * C:\W\Develop\gh\inxton\simatic-ax\axsharp\src\AXSharp.compiler\tests\integration\actual\app\samples\units\ix\ax\.g + * C:\W\Develop\gh\inxton\simatic-ax\axsharp\src\AXSharp.compiler\tests\integration\expected\app\ix\.g + */ var integrationProjectsPaths = new string[] { Path.GetFullPath(Path.Combine(testFolder, @"..\..\..\..\integration\actual\lib1")), diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/ax/.g/PlcResources.g.cs b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/ax/.g/PlcResources.g.cs index 6c88600c..1ba9627a 100644 --- a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/ax/.g/PlcResources.g.cs +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/ax/.g/PlcResources.g.cs @@ -18,9 +18,9 @@ public static PlcTranslator Instance private PlcTranslator() { - var defaultResourceType = Assembly.GetAssembly(typeof(units.PlcTranslator)) - .GetType("units.Resources.PlcStringResources"); - this.SetLocalizationResource(defaultResourceType); + var assembly = Assembly.GetAssembly(typeof(units.PlcTranslator)); + var resource = assembly.GetType("units.Resources.PlcStringResources"); + this.SetLocalizationResource(resource, assembly); } } } \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/tia/.g/PlcResources.g.cs b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/tia/.g/PlcResources.g.cs index 6c88600c..1ba9627a 100644 --- a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/tia/.g/PlcResources.g.cs +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/tia/.g/PlcResources.g.cs @@ -18,9 +18,9 @@ public static PlcTranslator Instance private PlcTranslator() { - var defaultResourceType = Assembly.GetAssembly(typeof(units.PlcTranslator)) - .GetType("units.Resources.PlcStringResources"); - this.SetLocalizationResource(defaultResourceType); + var assembly = Assembly.GetAssembly(typeof(units.PlcTranslator)); + var resource = assembly.GetType("units.Resources.PlcStringResources"); + this.SetLocalizationResource(resource, assembly); } } } \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/integration/expected/app/ix/.g/PlcResources.g.cs b/src/AXSharp.compiler/tests/integration/expected/app/ix/.g/PlcResources.g.cs index d8b3707d..19ebced9 100644 --- a/src/AXSharp.compiler/tests/integration/expected/app/ix/.g/PlcResources.g.cs +++ b/src/AXSharp.compiler/tests/integration/expected/app/ix/.g/PlcResources.g.cs @@ -18,9 +18,9 @@ public static PlcTranslator Instance private PlcTranslator() { - var defaultResourceType = Assembly.GetAssembly(typeof(app.PlcTranslator)) - .GetType("app.Resources.PlcStringResources"); - this.SetLocalizationResource(defaultResourceType); + var assembly = Assembly.GetAssembly(typeof(app.PlcTranslator)); + var resource = assembly.GetType("app.Resources.PlcStringResources"); + this.SetLocalizationResource(resource, assembly); } } } \ No newline at end of file