rdfjs / shacl-ui

SHACL-driven UIs
https://rdf.js.org/shacl-ui/
11 stars 2 forks source link

Use case: Language tabs on top of a form and editing data that should be language specific but is not xsd:langString #19

Open danielbeeke opened 1 year ago

danielbeeke commented 1 year ago

When editing multilingual data it would be great to have something like the following UI:

Screenshot from 2023-08-23 12-32-55

This works quite fine for sh:datatype xsd:langString. But there is no predicate to indicate that a certain structure is language aware. How would we make the form so that the date is language specific?

Would the following work?

sh:property [
  sh:name "Date"@en ;
  sh:datatype xsd:date ;
  sh:path (schema:date schema:value);
  OUR_NAMESPACE:multilangual [
    OUR_NAMESPACE:languagePredicate schema:inLanguage ;
    OUR_NAMESPACE:valuePredicate schema:value ;
  ] ;
] ;
tpluscode commented 1 year ago

I really like that! Off the top of my head, maybe not much is needed to support such a UI.

Say you have two properties

  1. schema:name - text editor
  2. schema:category - instance selector
  3. schema:size - number input

The first one would be multilingual. Thus, selecting a language on top would switch the value between matching tagged literals

The second is essentially not multilingual because the actual values would be IRI. The display would need to reflect the language though, displaying translated labels of the items to choose from

Finally, language is irrelevant for the last one. The same control would be rendered for every selected language

Would the following work?

Why two sh:path?

danielbeeke commented 1 year ago

Sorry for the unclear example. I removed on of the sh:path.

The second is essentially not multilingual because the actual values would be IRI. The display would need to reflect the language though, displaying translated labels of the items to choose from

This is the use case that I think needs work. And which is referenced in the example.

tpluscode commented 1 year ago

I think that's concern for the components' interface. Hypothetically:

<dash-instances-select language="en">
</dash-instances-select>

Provided by the UI builder, the language property would have the component display the correct labels.

danielbeeke commented 1 year ago

I want to save the fact that an IRI was chosen for a specific language into the data. From my perspective I somehow need to let the UI builder know in what predicate to save my data and what predicate is responsible for the language.

What do you think?

danielbeeke commented 1 year ago

In my idea I would want to save for example a published boolean per language.

<http://ex.com/test>
  schema:published [
    schema:value true ;
    schema:inLanguage "en" ;
  ] [
    schema:value false ;
    schema:inLanguage "nl" ;
  ]
.
tpluscode commented 1 year ago

Thanks, now I understand why sh:datatype sh:langString is not enough.

I think we're on the border of data modeling, where you has a set of properties which are different depending on language. This may be similar to what I implemented on some occasions to create conditional forms to support sh:xone

<shape>
    sh1:discriminator <property> ;
    sh:property [ sh:path <property> ; sh:in ( "foo" "bar" ) ] ;
    sh:xone (
      [
        sh:property [
          sh:path <property> ;
          sh:hasValue "foo" ;
          dash:hidden true ;
        ] ;
        sh:property <foo1> , <foo2> , <foo3>;
      ]
      [
        sh:property [
          sh:path <property> ;
          sh:hasValue "bar" ;
          dash:hidden true ;
        ] ;
        sh:property <bar1> , <bar2> , <bar3>;
      ]
    )
 .

Depending on the value of <property>, the correct alternative is rendered.


Similarly, a language discriminator could be added. There are two major differences:

  1. the selected language is not a data property but a state of the form.
  2. for now let's assume that the set of properties is the same for every language
<>
  sh:property [
    sh:path schema:published ;
    ex:languageDiscriminator schema:inLanguage ;
    sh:node [
      sh:property [
        sh:path schema:inLanguage ;
      ] ;
      sh:property [ sh:path schema:value ; sh:datatype xsd:boolean ] ;
    ] ;
  ] ;
.

When you select language "nl", the form would implicitly create a node [ schema:inLanguage "nl" ] if it did not exist and keep the schema:inLanguage property hidden. Then, alternating between languages would render that node which matches the value of language discriminator property

Ultimately, the mechanics are not unlike tagged literals, where language tag acts as the discriminator

danielbeeke commented 1 year ago

I am starting to like this idea of preprocessing. Maybe ex:languageDiscriminator but also ex:isOrderedList could be predicates from our namespace that would have a defined way of transforming it to fully standard SHACL.

It could well be that there might be more properties that are doable but quite complex. Preprocessing might give us a way of simplifying the process of writing SHACL.

A bit similar to CSS and SCSS.

tpluscode commented 1 year ago

Just to be clear, I was not thinking about preprocessing in terms of modifying the SHACL triples. Only to define the behaviour of UI builders

danielbeeke commented 1 year ago

Yes, I know. I personally think there might be space for a pre-processor. Adding things to the SHACL spec might be more difficult than writing a pre-processor and adding some predicates and their defined behavior to this spec.

bergos commented 1 year ago

We should look at it from a different perspective. What problem needs to be solved? How can we identify the key for a tab? The key can be a property that holds the language, but it can also be any other property or multiple properties. If we add that information to the property shape, it can be used for the UI and validation. See the example below:

@prefix ex: <http://example.org/>.
@prefix sh: <http://www.w3.org/ns/shacl#>.

ex:peopleShape
  sh:targetClass ex:People;
  sh:property [
    sh:path ex:member;
    sh:node ex:personShape
  ].

ex:personShape
  sh:property [
    sh:path ex:givenName;
    ex:key true
  ], [
    sh:path ex:familyName;
    ex:key true
  ], [
    sh:path ex:height
  ].

Playground link

danielbeeke commented 1 year ago

Do I understand it correct that for this to work we need to create implementation to get the right labels etc?

I would like to show tabs with the labels of languages but I want to save bcp47 codes.

If I get it correct, I do like the idea of making it more generic.

tpluscode commented 1 year ago

I think I almost had the generic solution in mind earlier. It's not about tabs and it's not about languages.

The most generic approach I see is to support hiding and showing certain fields depending on annotated criteria. SHACL has one such annotation already which can be used: sh:group

@prefix ex: <http://example.org/>.
@prefix sh: <http://www.w3.org/ns/shacl#>.

ex:personShape
  sh:property [
    sh:path ex:givenName;
    sh:group group:names ;
  ], [
    sh:path ex:familyName;
    sh:group group:names ;
  ], [
    sh:path ex:height ;
    sh:group group:measures ;
  ].

I implement this in a very generic way in shaperone that implementors get to dynamically toggle a visibility flag of any given value. I implement this as tabs or accordion groups and only display properties belonging to a selected group.

Same method could be the used to dynamically set the visibilty of literals tagged with the same language, another property, or otherwise annotated, such as in the case of the sh:xone discriminator functionality.

Bottom line, I find this belonging to the component layer, where any given object (not just property) is explicitly hidden or visible

it can be used for the UI and validation

Can you elaborate on using this for validation @bergos ?

bergos commented 1 year ago

it can be used for the UI and validation

Can you elaborate on using this for validation @bergos ?

The validator could check if the combination of properties marked as key is unique. It would also be possible to mark a group as unique.

tpluscode commented 1 year ago

I see, thanks.

I think it makes sense but I it would be out of scope of this group IMO. Something to add to DASH @holgerknublauch? Like a dash:uniqueProperty ex:key constraint