vue-i18n: Wrong date format for e.g. Norwegian - vue.js

I'm using vue-i18n (version 8.24.2) in my app, and everything works as expected except when rendering dates using locale = nb-NO (Norwegian). Expected format: dd.MM.yyyy. Actual format: MM/dd/yyyy. When switching locale to German, which is using the same date format as Norwegian, correct date format is applied.
This open issue would probably solve my issue:
https://github.com/kazupon/vue-i18n/issues/625
I've spent a couple of hours investigating this issue, but I'm currently stuck, hence any help will be highly appreciated.
My i18n.ts (I left out config for languages not related to this issue)
import Vue from "vue";
import VueI18n from "vue-i18n";
enum Locales {
NO = "nb-NO"
}
const LOCALES = [
{ value: Locales.NO, caption: "Norsk" }
];
import nb_NO from "./locales/nb-NO.json";
export const messages = {
[Locales.NO]: nb_NO
};
const defaultLocale = Locales.NO;
const dateTimeFormats = {
"nb-NO": {
short: {
year: "numeric",
month: "2-digit",
day: "2-digit",
},
long: {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
hour12: false,
},
},
} as VueI18n.DateTimeFormats;
Vue.use(VueI18n);
// Create VueI18n instance with options
const i18n = new VueI18n({
locale: navigator.language.split('-')[0] || process.env.VUE_APP_I18N_LOCALE || defaultLocale,
fallbackLocale: defaultLocale,
messages,
dateTimeFormats: dateTimeFormats,
silentTranslationWarn: true,
});
const translate = (key: string): string => {
if (!key) {
return "";
}
return i18n.t(key) as string;
};
export { i18n, translate }; //export above method

vue-i18n simply forwards the date localization to Intl.DateTimeFormat(locale).format(date).
It seems the result is only incorrect in Chrome as of v92 (Issue 1233509). This bug is fixed in Chrome Canary v94.
As a workaround, you can modify the vue-i18n instance's _dateTimeFormatters to use the Danish (da) locale's formatter for nb-NO:
const i18n = new VueI18n({/*...*/});
i18n._dateTimeFormatters[Locales.NO + '__short'] =
new Intl.DateTimeFormat('da', dateTimeFormats[Locales.NO].short);
i18n._dateTimeFormatters[Locales.NO + '__long'] =
new Intl.DateTimeFormat('da', dateTimeFormats[Locales.NO].long);
demo

Related

Configure el-date-picker

Does someone know, how to configure a el-date-picker in element-plus to set the first day of week.
The docs say it configurable via day.js but not to use configure day.js in element.
I have done this so far.
import de from 'element-plus/es/locale/lang/de';
const i18n = createI18n({
legacy: false,
locale: 'de',
messages: {
'de': messagesDe
},
datetimeFormats: {
'de': {
short: {
year: 'numeric',
month: '2-digit',
day: '2-digit'
},
long: {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}
}
},
});
app.use(ElementPlus, {
locale: de,
});
app.use(i18n);
Thank you for your help.
The workaround described in dayjs#215 also works for Element Plus.
For example, to set Monday as the first day of the week for the de locale, create a de object off of dayjs.Ls, and set weekStart=1:
// main.js
import dayjs from 'dayjs'
dayjs.Ls.de ??= {}
dayjs.Ls.de.weekStart = 1
demo

Can rollup-plugins access the AST created by previous plugins in the plugin chain?

We use multiple rollup-plugins that parse their input to an AST. As they run on the same files, each file is parsed multiple times. Can this be optimized, so that each file is parsed only once? Minimal example:
// rollup.config.js
import {createFilter} from '#rollup/pluginutils';
import {simple} from 'acorn-walk';
import {attachComments} from 'astravel';
import {generate} from 'astring';
export default {
input: 'src/main.js',
output: {file: 'bundle.js', format: 'cjs'},
plugins: [{
name: 'plugin1',
transform(code, id) {
const comments = [];
const ast = this.parse(code, {onComment: comments});
attachComments(ast, comments);
simple(ast, {
Identifier(n) {
// rewrite wrong to right
if (n.name === 'wrong') n.name = 'right';
}
});
return {
code: generate(ast, {comments: true}),
ast,
map: null /* minimal example, won't create a source map here */
};
}
}, {
name: 'plugin2',
transform(code, id) {
const comments = [];
const ast = this.parse(code, {onComment: comments});
attachComments(ast, comments);
simple(ast, {
CallExpression(n) {
// rewrite mylog(...) to console.log(...)
if (n.callee.type === 'Identifier' && n.callee.name === 'mylog') {
n.callee = {
type: 'MemberExpression',
object: {type: 'Identifier', name: 'console', start: n.start, end: n.end},
property: {type: 'Identifier', name: 'log', start: n.start, end: n.end},
computed: false,
start: n.start,
end: n.end
}
}
}
});
return {
code: generate(ast, {comments: true}),
ast,
map: null /* minimal example, won't create a source map here */
};
}
}]
};
Now I understand that transform() can return an AST, so that parsing doesn't have to happen twice. And I understand that this.parse() uses the rollup-internal acorn instance. My simple mind thought that this.parse() could return the AST created by previous transform() calls, if available. But I assume that all sorts of demons await on that road, e.g. when this.parse() was called with different options.
Is there a different way achieve what I described? A different hook maybe?
I would love to not have all plugins in one and switching them on and off via options (I see that this would be a solution, but a really cumbersome one).

Vuejs: how to implement reactively disable datepicker

im newbie here. I want control the datepicker to be disabled automatically based on the existing api. I using the vuejs-datepicker library. I've seen the documentation and managed to implement it statically, but having problems when implementing it reactively.
This is my previous view:
<datepicker
:disabled-dates="state.disabledDates">
</datepicker>
And, my previous static value of datepicker, especially for the day:
data() {
var year = (new Date()).getFullYear()
var month = (new Date()).getMonth()
var dDate = (new Date()).getDate()
var state = {
disabledDates: {
to: new Date(year, month, dDate), // Disable all dates up to specific date
// from: new Date(2020, 0, 26), // Disable all dates after specific date
days: [0,1], // Disable Saturday's and Sunday's
}
}
return {
state: state,
day: '',
}
},
For now, here my view:
<datepicker
:disabled-dates="disabledDates">
</datepicker>
Console output:
My script:
<script>
data() {
return {
day: '',
year : (new Date()).getFullYear(),
month : (new Date()).getMonth(),
dDate : (new Date()).getDate(),
}
},
computed:{
// reactive
disabledDates: {
to: new Date(year, month, dDate), // Disable all dates up to specific date, 2020,8,8
days: [day], // Disable day, 0,1
}
},
watch: {
'day': function(day){
console.log('day: '+day)
return this.day
},
},
</script>
Thank you.
I'm pretty sure your only problem is that your syntax for computed properties is wrong. They should be functions, since they need to be run. Their dependencies are automatically determined by Vue, and when those change, the function is re-run. So, try this:
data: function() {
return {
day: '',
year: (new Date()).getFullYear(),
month: (new Date()).getMonth(),
dDate: (new Date()).getDate()
};
},
computed: {
// Here. This should be a function.
disabledDates: function() {
return {
// Make sure to use 'this.' when in a component
to: new Date(this.year, this.month, this.dDate),
days: [ this.day ]
};
}
},
watch: {
day: function(day) {
console.log(`Day: ${day}`);
return value;
}
}

v-currency how to remove symbol from model value?

I am using v-currency for vuetify
<v-text-field
v-model.trim="$v.service.manual_cost_per_slot.$model"
v-currency="{
currency: service.currency,
locale: locale,
allowNegative: false,
masked: false
}"
:label="$t('service.manual_cost_per_slot')"
class="purple-input"
/>
The value is saved into the model along with the currency symbol and thousands separator.
How can I prevent from this? what I want to achieve is to still see the symbol and separator on the form but the value in model should be a number with no symbol or separator. I am sure I am missing something obvious here...
Well, as the documentation of the module says:
... the v-currency
directive always emits the formatted string instead of the number
value when used with v-model. To get the number value you can use the
parseCurrency method.
There's an example there on the page. If you want the parsed value without symbols, use that numberValue computed property:
import { CurrencyDirective, parseCurrency } from 'vue-currency-input'
export default {
directives: {
currency: CurrencyDirective
},
data: () => ({
value: '$1,234.50',
locale: 'en',
currency: 'USD'
}),
computed: {
options () {
return {
locale: this.locale,
currency: this.currency
}
},
numberValue () {
return parseCurrency(this.value, this.options)
// OR using the instance method:
// return this.$parseCurrency(this.value, this.options)
}
}
}

using tcomb form native in react native

I am using tcomb to build a form in react-native, a field in my form is birthDate: t.maybe(t.Date), but it appears to have no style
const formRegistration = t.struct({
// other fields
birthDate: t.maybe(t.Date)
});
I have also added config down the options:
const options = {
fields : {
birthDate: {
label: 'Birth Date',
mode: 'date',
config: {
format: (date) => myFormatFunction('DD MM YYYY', date),
dialogMode: 'spinner'
}
}
}
}
};
Looking at this: https://github.com/gcanti/tcomb-form-native/blob/master/lib/stylesheets/bootstrap.js
The style for the date is in dateValue at line 196
so this is what I did to style it according to the need:
const Form = t.form.Form;
Form.stylesheet.dateValue.normal.borderColor = '#d0d2d3';
Form.stylesheet.dateValue.normal.backgroundColor = '#f0f1f1';
Form.stylesheet.dateValue.normal.borderWidth = 1;
you follow the same way to style other key parts in tcomb (e.g: labels: Form.stylesheet.controlLabel.normal.fontSize = 14;)