Always encode CSV export in UTF-8

Browsers do not support the charset in Blob, so it is already always encoded in
UTF-8. But to help users on Windows, we add the UTF-8 BOM because Windows
programs use it as magic number to detect encoding.

issue9527
review290761002
This commit is contained in:
Cédric Krier
2020-09-12 18:30:11 +02:00
parent 2d3374b873
commit 5b674ad987
4 changed files with 92 additions and 88 deletions
+1
View File
@@ -1,3 +1,4 @@
* Always encode CSV export in UTF-8
* Use tempusdominus and Popper for date time picker
* Support PYSON comparison of date and datetime
* Customize bootstrap default style
+2
View File
@@ -336,6 +336,8 @@ var Sao = {};
};
Sao.i18n.locale = {};
Sao.BOM_UTF8 = '\uFEFF';
Sao.get_preferences = function() {
var session = Sao.Session.current_session;
return session.reload_context().then(function() {
+5 -3
View File
@@ -1304,19 +1304,21 @@
return Sao.Window.Export.format_row(row);
});
var delimiter = ',';
var encoding = 'utf-8';
if (navigator.platform &&
navigator.platform.slice(0, 3) == 'Win') {
delimiter = ';';
encoding = 'cp1252';
}
var csv = Papa.unparse(unparse_obj, {
quoteChar: '"',
delimiter: delimiter,
});
if (navigator.platform &&
navigator.platform.slice(0, 3) == 'Win') {
csv = Sao.BOM_UTF8 + csv;
}
Sao.common.download_file(
csv, export_.name + '.csv',
{'type': 'text/csv;charset=' + encoding});
{'type': 'text/csv;charset=utf-8'});
});
}.bind(this));
},
+84 -85
View File
@@ -3,6 +3,53 @@
(function() {
'use strict';
var ENCODINGS = ["866", "ansi_x3.4-1968", "arabic", "ascii",
"asmo-708", "big5", "big5-hkscs", "chinese", "cn-big5", "cp1250",
"cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256",
"cp1257", "cp1258", "cp819", "cp866", "csbig5", "cseuckr",
"cseucpkdfmtjapanese", "csgb2312", "csibm866", "csiso2022jp",
"csiso2022kr", "csiso58gb231280", "csiso88596e", "csiso88596i",
"csiso88598e", "csiso88598i", "csisolatin1", "csisolatin2",
"csisolatin3", "csisolatin4", "csisolatin5", "csisolatin6",
"csisolatin9", "csisolatinarabic", "csisolatincyrillic",
"csisolatingreek", "csisolatinhebrew", "cskoi8r", "csksc56011987",
"csmacintosh", "csshiftjis", "cyrillic", "dos-874", "ecma-114",
"ecma-118", "elot_928", "euc-jp", "euc-kr", "gb18030", "gb2312",
"gb_2312", "gb_2312-80", "gbk", "greek", "greek8", "hebrew",
"hz-gb-2312", "ibm819", "ibm866", "iso-2022-cn", "iso-2022-cn-ext",
"iso-2022-jp", "iso-2022-kr", "iso-8859-1", "iso-8859-10",
"iso-8859-11", "iso-8859-13", "iso-8859-14", "iso-8859-15",
"iso-8859-16", "iso-8859-2", "iso-8859-3", "iso-8859-4",
"iso-8859-5", "iso-8859-6", "iso-8859-6-e", "iso-8859-6-i",
"iso-8859-7", "iso-8859-8", "iso-8859-8-e", "iso-8859-8-i",
"iso-8859-9", "iso-ir-100", "iso-ir-101", "iso-ir-109",
"iso-ir-110", "iso-ir-126", "iso-ir-127", "iso-ir-138",
"iso-ir-144", "iso-ir-148", "iso-ir-149", "iso-ir-157", "iso-ir-58",
"iso8859-1", "iso8859-10", "iso8859-11", "iso8859-13", "iso8859-14",
"iso8859-15", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
"iso8859-6", "iso8859-7", "iso8859-8", "iso8859-9", "iso88591",
"iso885910", "iso885911", "iso885913", "iso885914", "iso885915",
"iso88592", "iso88593", "iso88594", "iso88595", "iso88596",
"iso88597", "iso88598", "iso88599", "iso_8859-1", "iso_8859-15",
"iso_8859-1:1987", "iso_8859-2", "iso_8859-2:1987", "iso_8859-3",
"iso_8859-3:1988", "iso_8859-4", "iso_8859-4:1988", "iso_8859-5",
"iso_8859-5:1988", "iso_8859-6", "iso_8859-6:1987", "iso_8859-7",
"iso_8859-7:1987", "iso_8859-8", "iso_8859-8:1988", "iso_8859-9",
"iso_8859-9:1989", "koi", "koi8", "koi8-r", "koi8-ru", "koi8-u",
"koi8_r", "korean", "ks_c_5601-1987", "ks_c_5601-1989", "ksc5601",
"ksc_5601", "l1", "l2", "l3", "l4", "l5", "l6", "l9", "latin1",
"latin2", "latin3", "latin4", "latin5", "latin6", "logical", "mac",
"macintosh", "ms932", "ms_kanji", "shift-jis", "shift_jis", "sjis",
"sun_eu_greek", "tis-620", "unicode-1-1-utf-8", "us-ascii",
"utf-16", "utf-16be", "utf-16le", "utf-8", "utf8", "visual",
"windows-1250", "windows-1251", "windows-1252", "windows-1253",
"windows-1254", "windows-1255", "windows-1256", "windows-1257",
"windows-1258", "windows-31j", "windows-874", "windows-949",
"x-cp1250", "x-cp1251", "x-cp1252", "x-cp1253", "x-cp1254",
"x-cp1255", "x-cp1256", "x-cp1257", "x-cp1258", "x-euc-jp", "x-gbk",
"x-mac-cyrillic", "x-mac-roman", "x-mac-ukrainian", "x-sjis",
"x-user-defined", "x-x-big5"];
Sao.Window = {};
Sao.Window.InfoBar = Sao.class_(Object, {
@@ -860,52 +907,6 @@
Sao.Window.CSV = Sao.class_(Object, {
init: function(title) {
this.encodings = ["866", "ansi_x3.4-1968", "arabic", "ascii",
"asmo-708", "big5", "big5-hkscs", "chinese", "cn-big5", "cp1250",
"cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256",
"cp1257", "cp1258", "cp819", "cp866", "csbig5", "cseuckr",
"cseucpkdfmtjapanese", "csgb2312", "csibm866", "csiso2022jp",
"csiso2022kr", "csiso58gb231280", "csiso88596e", "csiso88596i",
"csiso88598e", "csiso88598i", "csisolatin1", "csisolatin2",
"csisolatin3", "csisolatin4", "csisolatin5", "csisolatin6",
"csisolatin9", "csisolatinarabic", "csisolatincyrillic",
"csisolatingreek", "csisolatinhebrew", "cskoi8r", "csksc56011987",
"csmacintosh", "csshiftjis", "cyrillic", "dos-874", "ecma-114",
"ecma-118", "elot_928", "euc-jp", "euc-kr", "gb18030", "gb2312",
"gb_2312", "gb_2312-80", "gbk", "greek", "greek8", "hebrew",
"hz-gb-2312", "ibm819", "ibm866", "iso-2022-cn", "iso-2022-cn-ext",
"iso-2022-jp", "iso-2022-kr", "iso-8859-1", "iso-8859-10",
"iso-8859-11", "iso-8859-13", "iso-8859-14", "iso-8859-15",
"iso-8859-16", "iso-8859-2", "iso-8859-3", "iso-8859-4",
"iso-8859-5", "iso-8859-6", "iso-8859-6-e", "iso-8859-6-i",
"iso-8859-7", "iso-8859-8", "iso-8859-8-e", "iso-8859-8-i",
"iso-8859-9", "iso-ir-100", "iso-ir-101", "iso-ir-109",
"iso-ir-110", "iso-ir-126", "iso-ir-127", "iso-ir-138",
"iso-ir-144", "iso-ir-148", "iso-ir-149", "iso-ir-157", "iso-ir-58",
"iso8859-1", "iso8859-10", "iso8859-11", "iso8859-13", "iso8859-14",
"iso8859-15", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
"iso8859-6", "iso8859-7", "iso8859-8", "iso8859-9", "iso88591",
"iso885910", "iso885911", "iso885913", "iso885914", "iso885915",
"iso88592", "iso88593", "iso88594", "iso88595", "iso88596",
"iso88597", "iso88598", "iso88599", "iso_8859-1", "iso_8859-15",
"iso_8859-1:1987", "iso_8859-2", "iso_8859-2:1987", "iso_8859-3",
"iso_8859-3:1988", "iso_8859-4", "iso_8859-4:1988", "iso_8859-5",
"iso_8859-5:1988", "iso_8859-6", "iso_8859-6:1987", "iso_8859-7",
"iso_8859-7:1987", "iso_8859-8", "iso_8859-8:1988", "iso_8859-9",
"iso_8859-9:1989", "koi", "koi8", "koi8-r", "koi8-ru", "koi8-u",
"koi8_r", "korean", "ks_c_5601-1987", "ks_c_5601-1989", "ksc5601",
"ksc_5601", "l1", "l2", "l3", "l4", "l5", "l6", "l9", "latin1",
"latin2", "latin3", "latin4", "latin5", "latin6", "logical", "mac",
"macintosh", "ms932", "ms_kanji", "shift-jis", "shift_jis", "sjis",
"sun_eu_greek", "tis-620", "unicode-1-1-utf-8", "us-ascii",
"utf-16", "utf-16be", "utf-16le", "utf-8", "utf8", "visual",
"windows-1250", "windows-1251", "windows-1252", "windows-1253",
"windows-1254", "windows-1255", "windows-1256", "windows-1257",
"windows-1258", "windows-31j", "windows-874", "windows-949",
"x-cp1250", "x-cp1251", "x-cp1252", "x-cp1253", "x-cp1254",
"x-cp1255", "x-cp1256", "x-cp1257", "x-cp1258", "x-euc-jp", "x-gbk",
"x-mac-cyrillic", "x-mac-roman", "x-mac-ukrainian", "x-sjis",
"x-user-defined", "x-x-big5"];
this.dialog = new Sao.Dialog(title, 'csv', 'lg');
this.el = this.dialog.modal;
@@ -1078,38 +1079,6 @@
.appendTo(this.expander_csv);
this.expander_csv.append(' ');
var encoding_label = jQuery('<label/>', {
'text': Sao.i18n.gettext('Encoding:'),
'class': 'control-label',
'for': 'input-encoding'
});
this.el_csv_encoding = jQuery('<select/>', {
'class': 'form-control',
'id': 'input-encoding'
});
for(var i=0; i<this.encodings.length; i++) {
jQuery('<option/>', {
'val': this.encodings[i]
}).append(this.encodings[i]).appendTo(this.el_csv_encoding);
}
var enc = 'utf-8';
if (navigator.platform &&
navigator.platform.slice(0, 3) == 'Win') {
enc = 'cp1252';
}
this.el_csv_encoding.children('option[value="' + enc + '"]')
.attr('selected', 'selected');
jQuery('<div/>', {
'class': 'form-group'
}).append(encoding_label)
.append(this.el_csv_encoding)
.appendTo(this.expander_csv);
this.expander_csv.append(' ');
this.el.modal('show');
this.el.on('hidden.bs.modal', function() {
jQuery(this).remove();
@@ -1169,6 +1138,38 @@
}).append(this.file_input))
.appendTo(this.chooser_form);
var encoding_label = jQuery('<label/>', {
'text': Sao.i18n.gettext('Encoding:'),
'class': 'control-label',
'for': 'input-encoding'
});
this.el_csv_encoding = jQuery('<select/>', {
'class': 'form-control',
'id': 'input-encoding'
});
for(var i=0; i < ENCODINGS.length; i++) {
jQuery('<option/>', {
'val': ENCODINGS[i]
}).append(ENCODINGS[i]).appendTo(this.el_csv_encoding);
}
var enc = 'utf-8';
if (navigator.platform &&
navigator.platform.slice(0, 3) == 'Win') {
enc = 'cp1252';
}
this.el_csv_encoding.children('option[value="' + enc + '"]')
.attr('selected', 'selected');
jQuery('<div/>', {
'class': 'form-group'
}).append(encoding_label)
.append(this.el_csv_encoding)
.appendTo(this.expander_csv);
this.expander_csv.append(' ');
var skip_label = jQuery('<label/>', {
'text': Sao.i18n.gettext('Lines to Skip:'),
'class': 'control-label',
@@ -1870,7 +1871,6 @@
}
},
export_csv: function(fields, data) {
var encoding = this.el_csv_encoding.val();
var locale_format = this.el_csv_locale.prop('checked');
var unparse_obj = {};
unparse_obj.data = data.map(function(row) {
@@ -1883,8 +1883,12 @@
quoteChar: this.el_csv_quotechar.val(),
delimiter: this.el_csv_delimiter.val()
});
if (navigator.platform &&
navigator.platform.slice(0, 3) == 'Win') {
csv = Sao.BOM_UTF8 + csv;
}
Sao.common.download_file(
csv, this.name + '.csv', {type: 'text/csv;charset=' + encoding});
csv, this.name + '.csv', {type: 'text/csv;charset=utf-8'});
return Sao.common.message.run(
Sao.i18n.ngettext('%1 record saved', '%1 records saved',
data.length));
@@ -1926,11 +1930,6 @@
query_string.push(['f', field.getAttribute('path')]);
});
var encoding = this.el_csv_encoding.val();
if (encoding) {
query_string.push(['enc', encoding]);
}
query_string.push(['dl', this.el_csv_delimiter.val()]);
query_string.push(['qc', this.el_csv_quotechar.val()]);