Locode Date field internationalization

Is there any way of making the DateTime fields showing different date format? It’s very confusing for Europeans to have the “wrong” order with date and month.

I did try with the [IntlDateTime(Locale = "nb_NO")] attribute, which displays correctly in the table view, but not for Create and Update views (I’ve added the same attributes for the properties in all three classes).

It’s also a bit cumbersome to have to add these attributes on every DateTime property on every type and DTO. Would it be possible to e.g. set it per user or some other convenient way?

Can you show a screenshot of Create/Update views? the Create/Update forms should be using the browsers native date Input controls.

Thanks for swift reply as always. Both here and at StackOverflow. Your customer service is beyond comparison.

Here are some screenshots and further explanation:

First the definition of the fields in the Update DTO and the Query DTO. I intentionally left the EndDate without locale, to see if there was any difference.

image

Query DTO (actually it is:
public class QueryEmployees : QueryDb<Employee>, IReturn<QueryResponse<Employee>>, IGet
and here is the Employee:

image

Query results:
image

Edit results:

And this is from the Request headers, when clicking Edit:

accept-language: nb,en;q=0.9,no;q=0.8,en-US;q=0.7,nb-NO;q=0.6,nn;q=0.5,en-GB;q=0.4,da;q=0.3,sv;q=0.2,de;q=0.1

The “nb” is Norwegian Bokmål, and later in the list you can see “nb-NO”, but it seems to come after “en-US”. This could be the culprit, as “nb” and “en” is probably disregarded, if it looks for those “a-B” style locales, where “en-US” comes first.

Here’s the settings in Chrome:

By moving Norwegian to the top, the one that was no. 3 in the screenshot, so both Norwegian Bokmål and Norwegian (generic one), the header changes to:

accept-language: no,nb;q=0.9,en;q=0.8,en-US;q=0.7,nb-NO;q=0.6,nn;q=0.5,en-GB;q=0.4,da;q=0.3,sv;q=0.2,de;q=0.1

We now see “no” and “nb” comes first, but still “en-US” comes before “nb-NO”.

Comment
I can say with certainty that at least half of people in Scandinavia will be using English user interface, but want the date format in the correct order. Same with 24H clock instead of AM/PM. Perhaps also comma vs. dot as decimal separator.
Many of us feel user interface in our native language looks weird, often due wonky translations.

When I read that you’re using the browser’s native UI elements for DateTime, my experience is that this will require fighting with the browser. And we can’t do that for each user, requiring them to change their browser settings etc. (and as you can see simple fixes don’t even work). It should be possible to do from the App. Like some user setting for language, date format, number format, time format. This is what will be required of me as a developer, so I need this to be possible with SS if I’m going the Locode route. Or I’ll have to already go for custom components this early in the process with Locode (which kind of defeats the purpose I think).

Would you consider, since Locode is Vue3 driven, to use a component instead of the browser’s built-in date-picker? And perhaps for some other typically localized inputs as well? That would make Locode so much better.

We’re always going to use the browser’s built-in Input controls whenever they’re available, but we’d be open if there’s something we can add to make it easier to configure them.

There is some support for specifying localization in formatted values which can be configured with:

appHost.AddToAppMetadata(meta =>
{
    meta.Ui.DefaultFormats.Locale = "nb-NO";
    meta.Ui.DefaultFormats.Date = new Intl(IntlFormat.DateTime)
    {
        Locale = "nb-NO",
        Date = DateStyle.Medium,
    }.ToFormat();
});

If you need to be able to include additional content in the Web Page, you can add custom files in:

/wwwroot/modules/locode

custom.js
custom.css
custom.html

Where they’ll be included in the Locode App, which you can use to override the built-in useFormattters() functions that the @servicestack/vue components use.

To include content in all built-in UIs you can add them in:

/wwwroot/modules/shared

custom-head.html
custom-body.html
custom-end.html 

E.g. you can add a custom-head.html to include additional meta tags, e.g. you may be able to set the language with:

<meta http-equiv="content-language" content="no">

I’m sorry to be argumentative, but I just got to say that at least to my understanding, Locode is marketed as “very little code”. Kind of works out of the box. Then add code when you really want to customize. I don’t consider having the correct date, time, etc. a customization, in contrast to e.g. relative date (x hours ago) which I would consider a customization.

To the suggestions:
Configuring the AppHost is not going to work for me, since my app will have users from different countries, so I can’t set a default for the app.

The “meta” tag is worth a try, if it can go through Razor. E.g. will custom-head.cshtml work?
Because then it can be dynamic per user. I’ll test first with the basic HTML header to see if it makes any difference.

OK - I’ve tested and it makes no difference:

Regarding formatters – does that work for input fields as well?

I’ve got a suggestion:
Is it possible to add properties to the input fields? I’d like to add “datepicker” for example. Not “data-datepicker” just “datepicker”.

That should allow me to add on https://flowbite.com/docs/plugins/datepicker/ using CDN only – no npm build step. It will attach to any input component as long as it has the datepicker attribute on it.

If you’d like to try, make sure to include these in footer.cshtml :

<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.6.3/flowbite.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.6.3/datepicker.min.js"></script>

And this in custom-head.html :

<link href="https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.6.3/flowbite.min.css" rel="stylesheet" />

Since I haven’t got this to work with Locode yet (need to add attribute), I just tested it in TodoMvc.cshtml:

<input datepicker type="text" datepicker-format="dd/mm/yyyy">

It’s hard to find what the actual questions are, but we’re always going to be using the browsers native Input controls which is affected by the browser configured language preferences.

Meta tags can be used to add HTTP Headers, but I don’t know if it will override the HTTP Headers. With navigator.language being a readonly property would suggest that the recommended approach is to return the appropriate Content-Language HTTP Response language based on the users preferred languages sent in Accept-Language - derived from the users browser configured language preferences.

The formatters are only for formatting values, they have no effect on browsers native Input controls.

Not with built-in C# Declarative UI [Input] attributes in Locode. They can be added when using the <TextInput> control directly where any additional attributes will be added to the underlying <input/> element.

It’s an advanced customization, but there is an opportunity of overriding the built-in TextInput component by adding a TextInput.mjs in /locode/components/TextInput.mjs where you should be able to override @servicestack/vue TextInput component with your own.

Yeah, I guess the questions got lost in trying out the alternatives and providing the unsuccessful results. I think it’s important to show that I have put effort into trying and to show what I did.

Really would like to get the Locode to work for my actual workplace, as it has so much potential. At least on the videos. But my real world is unfortunately different from the videos.

This far SS has been used most just fir the services. Now that you’re adding more value to the stack I’m very motivated to take out more value.

Question 1: could you add another parameter to the Input attribute which could be an array of key-value properties? Your doc already states that this attribute is used to add any attributes that are used with inputs, such as type, placeholder, min/max, so it would fit right in.
This would enable me and others to further customize Locode without making Locode more complex.

I’m thinking ‘[Input(props=List<string,object)>] or similar. That would result in the possibility to have added whatever attribute such as “datepicker” and “datepicker-format=dd-mm-yyyy” to the raw input element.

Question 2: Is Locode meant to be useful outside of en-US locale? If so what am I doing wrong? Even if I’m able with some effort to force my browser into full Norwegian mode, should every user have to go through the same hassle? Just to get date time on inputs correct? We have users from multiple countries (using the same back office program)

Question 3: for outputs, formatters seems to work, but so far I have added them to the DTO or Type including locale. But I dont want to hard code locale on the DTO. It will be different for differet users. I was thinking the same when I saw the video and you guys added Currency.USD right there on the DTO. Is there a way to make that more dynamic, e.g. currency format would probably be based on the actual currency which could reside in a different column, and the locale would be based on the logged in user.

Hi @specimen151, since I have my computer setup with en-AU, I thought I’d provide example of what I see with our deployed Vue-MJS template.

It might be worth double checking that the client machines are setup with the correct language/region in their OS as that is where the browser should be getting the info from to display the date and the date pickers. Since Locode is just using the browser default controls, this I think should come from the browser/OS information like it does on my machine (Australia also uses dd/MM/yyyy as the standard date format).

Yes, I’ve just enabled passing Options properties down to input controls so you can add datepicker and datepicker-format to the underlying <input type=date> HTML Input with:

[Input(Type="date",Options="{datepicker:true,'datepicker-format':'dd-mm-yyyy'}")]
public DateTime Date { get; set; }

Yes, but you’re issue is trying to fight against the Browser’s intended behavior and asking us to do the same. Users will have their browsers configured to their preferred locale which is what the native browser controls will respect. Users wouldn’t have to go any additional effort, they’ll get the same behavior as every other website they visit with the standard Browsers HTML Input controls respecting their preferences.

I’ve also added support for being able to dynamically specify the currency where your Method Options can resolve the currency to use based on another property in the same model which they can access from modelValue property, e.g:

[Format(FormatMethods.Currency,Options="{currency:modelValue.currency||'EUR'}")]
public decimal Cost { get; set; }

Note: you can also just as easily call your own formatting functions by registering them with useFomatters().

These changes are available from the latest v6.6.1+ that’s now available on MyGet.

1 Like

I’ve battled with this for a while now, trying to override the input element w. a JavaScript one, which I got half working.

Finally I’ve found what to adjust with Chrome and Firefox to get it to work:

Firefox – set language to whatever you want (the language of Firefox itself), then adjust language of web page. If you’d like English, but with DD/MM/YYYY, you can select UK English.

Chrome+Edge was harder. Here the setting for the web-page didn’t work, even setting it to UK English (or Norwegian for that matter) – the data format was always from (MM-DD-YYYY), until I tried to change the language of the UI. Setting the UI display language to English-UK, solves it.

I’ll still investigate if there’s a possibility to override individual input elements, while still getting the benefits of AutoForm. Perhaps adding a custom component and forcing AutoForm to use that one with an attribute…

Anyway, just wanted to update with the settings for the browser.

You can customize the HTML Input attributes but you can’t use an unknown component that the Vue Component Library doesn’t know about. You should be able to get more control with a Vue directive which you can use to script the Input element at different life cycles.

What is the custom Vue Input Component you want to use instead?

I’ll settle with the standard input=date for now, but to let you know what I was thinking:

There’s already the possibility to create a lot of custom UI for complete forms (NewBooking, UpdateBooking, examples), so perhaps one day there’ll be the example to create single input components in the same manner? By adding some file w. some Vue stuff in a folder.

Concretely I would then use this component https://flowbite.com/docs/plugins/datepicker/ (import both some CSS and some JS from CDNs).

If it was only for certain fields, I guess that could easily be selected with the Property attributes.

Perhaps another day.

This doesn’t look like a Vue Component? Don’t see how adding support for custom Input components would help? If you just want to add custom attributes to the <input> element you can do that already.

Just for the sake of discussion, what I mean is that just like Locode know that for NewBooking it will load the NewBooking page, with all it’s components and HTML, instead of the regular auto, one could do the same on a per-component level.

Let’s say I’d like a “slider” or something for certain integer inputs. I could then create a custom component (same as for NewBooking, UpdateBooking and the like) but just for that single input component, not a whole “page”.

So in these cases SS Locode would render <MyCoponent> instead of <Input>, with some convention as to the v-model used for the actual value.

I was looking for a real-world Vue Component that would’ve been used to replace an existing Input component.

Input components aren’t like normal components that just needs to be rendered, they’re tightly coupled with 2-way data binding down to multiple nested components which makes it a lot more difficult to support generically, something I wouldn’t waste time investigating without a real-world need & existing Vue Component to test it against.

I understand, “input” components are more special than “div” for example. Is there any reason though, that what is rendered must be an input component and not just any Vue component, which in turn can use whatever HTML elements, JS and CSS it prefers? As long as the Vue component (which could wrap any component off the net, or written from the ground up) follows some convention about where the input and output value would be, so that SS could use it easily.

Well, that’s just my thoughts/ideas. For now I’ve decided that “vanilla” Locode will be something to use in the POC stage only, then customize pretty quickly. I know where to fix the date-fields in the browser settings, which was my initial problem, and I put it into the discussion to help others.

We don’t need to continue this discussion. I’m concerned that I’m wasting everyone’s time. My problem is solved.

BTW: Here’s an example of plugin: https://vcalendar.io/
But it requires NPM which is what you’re trying to avoid, so I think it’s a dead-end for now.

FYI the latest v6.9 Release adds support for Custom Declarative Input Components

Where you can register custom components with the @servicestack/vue library:

import ServiceStackVue from "@servicestack/vue"
//...

ServiceStackVue.component('EmailInput', EmailInput)
ServiceStackVue.component('MarkdownEmailInput', MarkdownEmailInput)

That you can then reference in your Request DTOs:

[Description("Markdown Email")]
public class MarkdownEmail : CreateEmailBase, IPost, IReturn<MailMessage>
{
    [Input(Type="MarkdownEmailInput", Label="")]
    public string? Body { get; set; }
}

Which will use your custom component in ServiceStack Vue Auto UIs and Auto Form components. There’s examples of creating custom components in the release notes.

1 Like