A presentation at JSConfEU in in Berlin, Germany by Jayne Mast
Calendar / Kalender / ميوقت (aka, the fun of locali[zs]ation) mìosachan kalendá ř رڊنيلئڪ календарь
í2 רַאדנעלַאק ປະຕiທiນ 'ISjaH
Paul Verbeek-Mast
Calendar / Kalender / ميوقت (aka, the fun of locali[zs]ation) mìosachan kalendá ř رڊنيلئڪ календарь
í2 רַאדנעלַאק ປະຕiທiນ 'ISjaH
Step 1 – implementation
http://infiniteundo.com/post/25326999628/falsehoods-programmers- believe-about-time http://infiniteundo.com/post/25509354022/more-falsehoods- programmers-believe-about-time F alsehoods programmers believe about time More f alsehoods programmers believe about time
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 4 May 2017 dd-mm-yyyy Fro m dd-mm-yyyy To Price € Save
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 4 May 2017 dd-mm-yyyy Fro m dd-mm-yyyy To Price € Save
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 31 May 2017 mm-dd-yyyy Fro m mm-dd-yyyy To Price $ Save
May 2017 Fro m To Price $ Save moment . localeData (). firstDayOfWeek (); // 0-6 (Sunday to Saturday)
moment . localeData (). weekdaysMin (); //["Su", "Mo", "Tu", "We", "Th", "Fr", “ Sa"]
May 2017 Fro m To Price $ Save Mo Tu We Th Fr Sa Su var calMoment = moment (); calMoment. startOf ( 'month' ). startOf ( 'week' ). date (); // 31 31
May 2017 Fro m To Price $ Save Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 31 calMoment. add ( 1 , 'd' ). date (); // 2 calMoment. isSame ( moment (). endOf ( 'month' ). endOf ( 'week' ). startOf ( 'day' ));
May 2017 Fro m To Price $ Save Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 31 ??-??-?? ??-??-?? moment . localeData ()._longDateFormat[ 'L' ]; // 'MM/DD/YYYY'
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 31 May 2017 MM/DD/YYYY Fro m MM/DD/YYYY To Price $ Save
Step 2 – testing
RTL
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 4 May 2017 dd-mm-yyyy Fro m dd-mm-yyyy To Price € Save
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 4 May 2017 dd-mm-yyyy Fro m dd-mm-yyyy To Price € Save
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 4 May 2017 dd-mm-yyyy Fro m dd-mm-yyyy To Price € Save
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 4 30 31 1 2 3 May 2017 dd-mm-yyyy Fro m dd-mm-yyyy To Price € Save
Step 2 – testing
“ ❤ the new interface!” “I can finally find my reservations!” “Looks a lot better, just like {popular rental website for apartments}’s calendar!” “much better overview”
“hate it, bring the old one back” “who made this " ? ”
“Reservations aren’t showing up” “the date selection is not working” “The prices aren’t showing properly” “All reservations are a day off” “Why are closed dates red?”
Step 3 – Bug fixing
“the date selection is not working” “Reservations aren’t showing up” “The prices aren’t showing properly” “All reservations are a day off” “Why are closed dates red?”
dd-mm-yyyy Fro m dd-mm-yyyy To
05/07/2017 moment.localeData()._longDateFormat['L']; MM/DD/YYYY $.datepicker.parseDate('MM/DD/YYYY', '05/07/2017'); $.datepicker.parseDate('mm/dd/yy ', '05/07/2017');
function convertToJQueryUI() { var format = moment().localeData()._longDateFormat['L']; var dateDelimiterRegEx = /[-/ ]/; var delimiter = (dateDelimiterRegEx.exec(format) || '')[0]; var dateTransform = { 'YYYY': 'yy', … 'D': 'd' }; function getTransformedDatePart(part) { return dateTransform[part] || part; } return format .split(dateDelimiterRegEx) .map(getTransformedDatePart) .join(delimiter); };
function convertToJQueryUI() { var format = moment().localeData()._longDateFormat['L']; var dateDelimiterRegEx = /[-/ ]/; var delimiter = (dateDelimiterRegEx.exec(format) || '')[0]; var dateTransform = { 'YYYY': 'yy', … 'D': 'd' }; function getTransformedDatePart(part) { return dateTransform[part] || part; } return format .split(dateDelimiterRegEx) .map(getTransformedDatePart) .join(delimiter); };
function convertToJQueryUI() { var format = moment().localeData()._longDateFormat['L']; var dateDelimiterRegEx = /[-/ ]/; var delimiter = (dateDelimiterRegEx.exec(format) || '')[0]; var dateTransform = { 'YYYY': 'yy', … 'D': 'd' }; function getTransformedDatePart(part) { return dateTransform[part] || part; } return format .split(dateDelimiterRegEx) .map(getTransformedDatePart) .join(delimiter); };
function convertToJQueryUI() { var format = moment().localeData()._longDateFormat['L'];
var dateDelimiterRegEx = /[-/]/;
var delimiter = (dateDelimiterRegEx.exec(format) || '')[0]; var dateTransform = { 'YYYY': 'yy', … 'D': 'd' }; function getTransformedDatePart(part) { return dateTransform[part] || part; } return format .split(dateDelimiterRegEx) .map(getTransformedDatePart) .join(delimiter); };
function convertToJQueryUI() { var format = moment().localeData()._longDateFormat['L'];
var dateDelimiterRegEx = /[-/]/;
var delimiter = (dateDelimiterRegEx.exec(format) || '')[0];
var dateTransform = {
'YYYY': 'yy',
…
'D': 'd'
};
function getTransformedDatePart(part) {
return dateTransform[part] || part;
}
return format
.split(dateDelimiterRegEx)
.map(getTransformedDatePart)
.join(delimiter);
};
function convertToJQueryUI() { var format = moment().localeData()._longDateFormat['L'];
var dateDelimiterRegEx = /[-/]/;
var delimiter = (dateDelimiterRegEx.exec(format) || '')[0];
var dateTransform = { 'YYYY': 'yy', … 'D': 'd' };
function getTransformedDatePart(part) { return dateTransform[part] || part; } return format .split(dateDelimiterRegEx) .map(getTransformedDatePart) .join(delimiter); };
function convertToJQueryUI() { var format = moment().localeData()._longDateFormat['L'];
var dateDelimiterRegEx = /[-/]/;
var delimiter = (dateDelimiterRegEx.exec(format) || '')[0];
var dateTransform = { 'YYYY': 'yy', … 'D': 'd' }; function getTransformedDatePart(part) { return dateTransform[part] || part; }
return format .split(dateDelimiterRegEx) .map(getTransformedDatePart) .join(delimiter); };
function convertToJQueryUI() { var format = moment().localeData()._longDateFormat['L']; var dateDelimiterRegEx = /[-/ ]/; var delimiter = (dateDelimiterRegEx.exec(format) || '')[0]; var dateTransform = { 'YYYY': 'yy', … 'D': 'd' }; function getTransformedDatePart(part) { return dateTransform[part] || part; } return format .split(dateDelimiterRegEx) .map(getTransformedDatePart) .join(delimiter); };
var dateDelimiterRegEx = /[-/ ]/;
var dateDelimiterRegEx = /[-/. ]/;
var dateDelimiterRegEx = /\W /;
Sloven č ina
DD. MM. YYYY var dateDelimiterRegEx = /\W /; var dateDelimiterRegEx = /\W+ /;
“Reservations aren’t showing up” “the date selection is not working” “The prices aren’t showing properly” “All reservations are a day off” “Why are closed dates red?”
Mo Tu We Th Fr Sa Su
Mo Tu We Th Fr Sa Su
https://en.wikipedia.org/wiki/Time_in_Brazil
dayA.startOf('day').add(1, 'd').isSame(dayB.startOf('day'))
dayA.add(1, 'd').startOf('day').isSame(dayB.startOf('day'))
“All reservations are a day off” “Reservations aren’t showing up” “the date selection is not working” “The prices aren’t showing properly” “Why are closed dates red?”
Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 4 May 2017 dd-mm-yyyy Fro m dd-mm-yyyy To Price € Save
“Why are closed dates red?” “Reservations aren’t showing up” “the date selection is not working” “The prices aren’t showing properly” “All reservations are a day off”
23
“The prices aren’t showing properly” “Reservations aren’t showing up” “the date selection is not working” “All reservations are a day off” “Why are closed dates red?”
23 € 125
23 Rp 1,813, 351
Conclusion
Do not make any assumptions
Localization is not just about date & time
Ask users for feedback
Save relevant data
Bugs will be there
Bugfixing =
@_paulverbeek @fronteersconf paul.verbeek@spronq .com 705649555
Questions?
For the past few months, I’ve been creating a calendar for our partners at Booking.com. Months? Yes, months. Creating a calendar that works correctly all across the world for 42 different languages and even more locales, is not something that you do in a week. In this talk, I will talk to you about the weird things I learned. From Brazilian Summer Time to Slovakian date formatting. And how to avoid the many (many!) mistakes I made.