Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
set and use locales
March 23, 2021
8:38, EET
Avatar
Ank
Member
Members
Forum Posts: 3
Member Since:
February 4, 2021
sp_UserOfflineSmall Offline

Hi Team,

I am using the prosys Opc Ua Java SDK for opc Ua server developement and UaExpert as my client .
I would like to know if it is possible to add Locales -setting localized text from server end. I can see a method “addLocale” in server.
Also, In OpcUaSessionManager’s session I see setLocalIds method.
session.getSessionDiagnostics().snapshot().setLocaleIds(“en“);

Could you please clarify what purpose does it serve and is it recommended to set locale from server side. What should be done from client end.

March 23, 2021
9:38, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1026
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hi,

I do not understand what you mean by “set the locale from the server side”, please clarify. An UA Client will request locales in the ActivateSession: https://reference.opcfoundation.org/v104/Core/docs/Part4/5.6.3/ (no idea if UaExpert supports this). Then if the UA Server has a matching localized data over the “generic non-localized data” it should return that one instead. The server “cannot set the locale” specification-wise, but it will return the generic “null-locale” i.e. “invariant locale” text if it wont have a match.

There might be a way for testing purposes, but it is a bit complicated (would need to override parts of the SDK) and as said, no real Server application should try to change the info client gave. So I’ll skip that in this post at least.

The “session.getSessionDiagnostics().snapshot()” is used internally by the SDK (thus ignore that) in order to get the session diagnostics data from the Session object in a form that can be shown in the AddressSpace. I wont go into details, but basically the way it is specified is that the same data has to be a bit differently in like 6 different places, thus it was more convinient to store it in the Session as sort of “non-UA data”, update it once and then transform it to the 6 places from it.

Generally speaking, I’m not personally aware that localization features of OPC UA would have been used that much, thus the support might not be that great yet.

Anyway, on the server side of our SDK, for Attributes that are of type LocalizedText, you can just call e.g. UaNode.setDisplayName(LocalizedText) and it would behave as ruled (as-if it were a Write) in https://reference.opcfoundation.org/v104/Core/docs/Part4/5.10.4/:
“If a Server allows writing of Attributes with the DataType LocalizedText, the Client can add or overwrite the text for a locale by writing the text with the associated LocaleId. Writing a null String for the text for a locale shall delete the String for that locale. Writing a null String for the locale and a non-null String for the text is setting the text for an invariant locale. Writing a null String for the text and a null String for the locale shall delete the entries for all locales. “

However, it should be noted, that this will work currently only for the “simple types”. If a LocalizedText is part of a Structure field, that cannot be localized. You can however return a completely different Structure java-instance with the proper locale, assuming you make required IoManagerListeners etc. I hope that in the future we can improve this (but since the same Structure class is shared in the client side, where you always just have a single LocalizedText vs. the LocalizedTextMap we use as the backing field in the server side for LocalizedText-type’d Attributes it is a bit more complicated case). Anyawy, in IoManagerListener (and many others) you will get a ServiceContext parameter, from there you can get the Session and the Locales the UA Client gave, thus it is sort of possible to support every possibe case (that I can think of quickly), but it might be a bit more complicated if you must have Structures with localized data.

Does this clarify enough?

March 23, 2021
11:30, EET
Avatar
Ank
Member
Members
Forum Posts: 3
Member Since:
February 4, 2021
sp_UserOfflineSmall Offline

Thanks Bjarne.

I am able to get the locale set by Client using ServiceContext .
What I would like to do is translate the node descriptions as per the locales set by the client. I can set description and see it from UAExpert as well but I would like to translate it.
node.setDescription(new LocalizedText(“This is a description”, “de”));

Please suggest if there is a way to achieve this.

March 23, 2021
13:01, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1026
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

I do not understand what you mean by “translate it”? You just did that? The code you shown should work as-is?

And as a sidenote, you can only “translate” LocalizedText-datatype’d Attributes. Or I gues technically any data that is of String you can chose to have in the locale you want (though, then then it is locked to just that one locale).

If you e.g. put the following code in the MyNodeManager where the MyLevel node is created:

myLevel.setDescription(new LocalizedText("testen", "de"));

and then in SampleConsoleClient after the UaClient has been constructed call:
client.setLocale(Locale.GERMAN);

and the connect to the SampleConsoleServer and make a Read to the Description of MyLevel, you should see:

*** Connected to: opc.tcp://localhost:52520/OPCUA/SampleConsoleServer

*** Current Node: Root: FolderType (ID: i=84)

——————————————————-
– Enter x to close client
——————————————————-
– Enter 0 to start discovery –
– Enter 1 to connect to server –
– Enter 2 to disconnect from server –
– Enter 3 to browse the server address space –
– Enter 4 to read values –
– Enter 5 to write values –
– Enter 6 to register nodes –
– Enter 7 to unregister nodes –
– Enter 8 to create a subscription –
– Enter 9 to call a method –
– Enter 10 to read history –
——————————————————-
3
*** Current Node: Root: FolderType (ID: i=84)

0 – Objects: FolderType (ReferenceType=Organizes, BrowseName=Objects)
1 – Types: FolderType (ReferenceType=Organizes, BrowseName=Types)
2 – Views: FolderType (ReferenceType=Organizes, BrowseName=Views)
——————————————————-
– Enter node number to browse into that
– Enter a to show/hide all references
– Enter r to browse back to the root node
– Enter t to translate a BrowsePath to NodeId
– Enter x to select the current node and return to previous menu
——————————————————-
0
*** Current Node: Objects: FolderType (ID: i=85)

0 – Server: ServerType (ReferenceType=Organizes, BrowseName=Server)
1 – Aliases: AliasNameCategoryType (ReferenceType=Organizes, BrowseName=Aliases)
2 – MyObjects: FolderType (ReferenceType=Organizes, BrowseName=2:MyObjects)
3 – ComplianceNodes: FolderType (ReferenceType=Organizes, BrowseName=3:ComplianceNodes)
4 – NonUaNodeComplianceTest: FolderType (ReferenceType=Organizes, BrowseName=4:NonUaNodeComplianceTest)
5 – MyBigNodeManager: FolderType (ReferenceType=Organizes, BrowseName=5:MyBigNodeManager)
——————————————————-
– Enter node number to browse into that
– Enter a to show/hide all references
– Enter b to browse back to the previous node (Root)
– Enter u to browse up to the ‘parent’ node
– Enter r to browse back to the root node
– Enter t to translate a BrowsePath to NodeId
– Enter x to select the current node and return to previous menu
——————————————————-
2
*** Current Node: MyObjects: FolderType (ID: ns=2;s=MyObjectsFolder)

0 – MyDevice: MyDeviceType (ReferenceType=HasComponent, BrowseName=2:MyDevice)
1 – MyDevice: MyDeviceType (ReferenceType=HasNotifier, BrowseName=2:MyDevice)
——————————————————-
– Enter node number to browse into that
– Enter a to show/hide all references
– Enter b to browse back to the previous node (Objects)
– Enter u to browse up to the ‘parent’ node
– Enter r to browse back to the root node
– Enter t to translate a BrowsePath to NodeId
– Enter x to select the current node and return to previous menu
——————————————————-
1
*** Current Node: MyDevice: MyDeviceType (ID: ns=2;s=MyDevice)

0 – MyEnumObject: BaseDataVariableType (ReferenceType=HasComponent, BrowseName=2:MyEnumObject)
1 – MyLevel: MyLevelType (ReferenceType=HasEventSource, BrowseName=2:MyLevel)
2 – MyLevel: MyLevelType (ReferenceType=HasComponent, BrowseName=2:MyLevel)
3 – MyLevelAlarm: ExclusiveLevelAlarmType (ReferenceType=HasComponent, BrowseName=2:MyLevelAlarm)
4 – MyMethod: [Method] (ReferenceType=HasComponent, BrowseName=2:MyMethod)
5 – MyNestedStructure: BaseVariableType (ReferenceType=Organizes, BrowseName=2:MyNestedStructure)
6 – MyStructure: BaseVariableType (ReferenceType=Organizes, BrowseName=2:MyStructure)
7 – MySwitch: BaseDataVariableType (ReferenceType=HasComponent, BrowseName=2:MySwitch)
——————————————————-
– Enter node number to browse into that
– Enter a to show/hide all references
– Enter b to browse back to the previous node (MyObjects)
– Enter u to browse up to the ‘parent’ node
– Enter r to browse back to the root node
– Enter t to translate a BrowsePath to NodeId
– Enter x to select the current node and return to previous menu
——————————————————-
1
*** Current Node: MyLevel: MyLevelType (ID: ns=2;s=MyLevel)

0 – HA Configuration: HistoricalDataConfigurationType (ReferenceType=HasHistoricalConfiguration, BrowseName=2:HA Configuration)
——————————————————-
– Enter node number to browse into that
– Enter a to show/hide all references
– Enter b to browse back to the previous node (MyDevice)
– Enter u to browse up to the ‘parent’ node
– Enter r to browse back to the root node
– Enter t to translate a BrowsePath to NodeId
– Enter x to select the current node and return to previous menu
——————————————————-
x

*** Connected to: opc.tcp://localhost:52520/OPCUA/SampleConsoleServer

*** Current Node: MyLevel: MyLevelType (ID: ns=2;s=MyLevel)

——————————————————-
– Enter x to close client
——————————————————-
– Enter 0 to start discovery –
– Enter 1 to connect to server –
– Enter 2 to disconnect from server –
– Enter 3 to browse the server address space –
– Enter 4 to read values –
– Enter 5 to write values –
– Enter 6 to register nodes –
– Enter 7 to unregister nodes –
– Enter 8 to create a subscription –
– Enter 9 to call a method –
– Enter 10 to read history –
——————————————————-
4
read node ns=2;s=MyLevel
Select the node attribute.
1 – NodeId
2 – NodeClass
3 – BrowseName
4 – DisplayName
5 – Description
6 – WriteMask
7 – UserWriteMask
8 – IsAbstract
9 – Symmetric
10 – InverseName
11 – ContainsNoLoops
12 – EventNotifier
13 – Value
14 – DataType
15 – ValueRank
16 – ArrayDimensions
17 – AccessLevel
18 – UserAccessLevel
19 – MinimumSamplingInterval
20 – Historizing
21 – Executable
5
attribute: Description
Node: ns=2;s=MyLevel.Description | Status: GOOD (0x00000000) “” | Value: (de) testen | ServerTimestamp: 2021 Mar 23 (EET) 12:55:48.590

March 23, 2021
21:50, EET
Avatar
Ank
Member
Members
Forum Posts: 3
Member Since:
February 4, 2021
sp_UserOfflineSmall Offline

I am able to see the description “as-is” in UAExpert.
Maybe my understanding is wrong here. What I was expecting is a translated text to the locale. In my case, I would like to translate my string “This is a description”, to German locale “de”.like “Dies ist eine Beschreibung” which should be visible to the client.

Basically, What I would like to do is:
1)Specify single/multiple locale for a node’s description in UAModeler.
Generate it’s corresponding xml where I would expect something like:
(not able to write xml data correctly)
>Description Locale=”en”>The TemperatureZone describes one control loop for an heating>/Description>
>Translaton>
>Description Locale=”de-DE”>Die TemperaturZone beschreibt einen Regelkreis einer Heizung>/Description>
>/Translation>

2)Now In the server code, get the localeId specified by the Client using SessionContext and verify if the locale is available at server side(from the UAModeler generated code)
3)If the corresponding translation is available, return translated description string for that node to the Client.

Kindly suggest
1) Is there a way to add single/Multiple locale Ids for Description/DisplayName or any other LocalizedText-datatype’d Attributes in UAModeler?Please suggest how to achieve this.
If locales can be added to UAmodeler, will the generated code have translated text like above assumption?
2)If locales cannot be added to the UAModeler, how can I translate any LocalizedText-datatype’d Attributes to locale specified by Client.In such case who should be responsible for performing translations?

I hope I am able to make my requirement clear here.

March 24, 2021
10:37, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1026
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Ok, now I understand what you mean.

Unfortunately the answer is that we cannot load such models yet. How important this would be for you? And in what timeframe.

Please see, https://forum.prosysopc.com/forum/opc-ua-java-sdk/translation-of-descriptions-displayname-etc-noenumconstant/ I believe the linked forum thread was the first ever to ask so you are the second one.

Anyway, I think you got the Translation XML block sort of wrong, see https://reference.opcfoundation.org/v104/Core/docs/Part6/F.10/, it only applies for the Value Attribute. For non-Value, you should just be able to repeat the Description/DisplayName elements multiple times with different locales (see the linked thread).

For the “Kindly suggest” questions:

1.
I cannot yet answer for the Modeler, since I have never used any “translation” or custom locales in a model (i.e. in general, that has not just been something that would have been done in any model so far, there is a lot of OPC UA features that no-one uses nor anyone has implemented).

Note that the generated code wont have any translations, since well, they are not part of the type data which we generate. Basically any localized data is “informative only” sort of. That is to say that e.g. TranslateBrowsePathsToNodeIds service operates on BrowseName Attribute, which is not localizable (and cannot be). Thus basically the get/set/nodeget methods we generate operate on the BrowseNames only. The codegen output is sort of “syntax sugar” on top of the UaNode model, and basically it only does more specific UaNode implementations of loaded or instantiated nodes.

2.
Basically the answer is that I sort of have no idea. In general, so far nothing has been like translated in OPC UA, as far as I have seen things. I’m not sure the NodeSet would be the best place for that data, since if you would need more than 1-2 localizations, it could get huge. Since we basically just implement the specification (or well, parts of it, as it continuously grows..), the question might be better suited for: https://opcfoundation.org/forum/. In general, I believe the translations are on the responsiblity of whoever makes the server. And while I do recognize valid cases for localization, the BrowseNames will still be basically in English, no can do.

Thus any workaround at the moment would have to involve custom code that somehow loads the localization information from somewhere, at puts it to the UaNodes (and this part should work). I do realize, that this is not optimal and is something we need to improve.

Forum Timezone: Europe/Helsinki

Most Users Ever Online: 1919

Currently Online:
17 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

Heikki Tahvanainen: 402

hbrackel: 144

rocket science: 88

pramanj: 86

Francesco Zambon: 83

Ibrahim: 78

Sabari: 62

kapsl: 57

gjevremovic: 49

Xavier: 43

Member Stats:

Guest Posters: 0

Members: 735

Moderators: 7

Admins: 1

Forum Stats:

Groups: 3

Forums: 15

Topics: 1523

Posts: 6449

Newest Members:

rust, christamcdowall, redaahern07571, nigelbdhmp, travistimmons, AnnelCib, dalenegettinger, howardkennerley, Thomassnism, biancacraft16

Moderators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1026, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0

Administrators: admin: 1