Skip to content

Commit

Permalink
feat: support number format with locale opts
Browse files Browse the repository at this point in the history
  • Loading branch information
fudali113 committed May 6, 2023
1 parent 203c6e5 commit ddb0f66
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 10 deletions.
27 changes: 20 additions & 7 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -1336,13 +1336,26 @@ func (f *File) getCellStringFunc(sheet, cell string, fn func(x *xlsxWorksheet, c
return "", nil
}

// applyBuiltInNumFmt provides a function to returns a value after formatted
// with built-in number format code, or specified sort date format code.
func (f *File) applyBuiltInNumFmt(c *xlsxC, fmtCode string, numFmtID int, date1904 bool, cellType CellType) string {
// getBuiltInNumFmtCode provides a function to returns a value
// with built-in number format code, or locale base built-in number format code,
// or specified sort date format code.
func (f *File) getBuiltInNumFmtCode(numFmtID int) (fmtCode string, ok bool) {
if numFmtID == 14 && f.options != nil && f.options.ShortDateFmtCode != "" {
fmtCode = f.options.ShortDateFmtCode
fmtCode, ok = f.options.ShortDateFmtCode, true
return
}
var locale string
if f.options != nil {
locale = f.options.Locale
}
if locale != "" {
fmtCode, ok = langNumFmt[locale][numFmtID]
if ok { // if in langNumFmt, use langNumFmt result
return
}
}
return format(c.V, fmtCode, date1904, cellType, f.options)
fmtCode, ok = builtInNumFmt[numFmtID]
return
}

// formattedValue provides a function to returns a value after formatted. If
Expand Down Expand Up @@ -1374,8 +1387,8 @@ func (f *File) formattedValue(c *xlsxC, raw bool, cellType CellType) (string, er
if wb != nil && wb.WorkbookPr != nil {
date1904 = wb.WorkbookPr.Date1904
}
if fmtCode, ok := builtInNumFmt[numFmtID]; ok {
return f.applyBuiltInNumFmt(c, fmtCode, numFmtID, date1904, cellType), err
if fmtCode, ok := f.getBuiltInNumFmtCode(numFmtID); ok {
return format(c.V, fmtCode, date1904, cellType, f.options), err
}
if styleSheet.NumFmts == nil {
return c.V, err
Expand Down
74 changes: 74 additions & 0 deletions cell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,62 @@ func TestFormattedValue(t *testing.T) {

assert.Equal(t, "0_0", format("0_0", "", false, CellTypeNumber, nil))

// Test format value with built-in number format zh-cn
originalFileOptions := f.options
f.options = &Options{
Locale: "zh-CN",
}
styleID31, err := f.NewStyle(&Style{
NumFmt: 31,
Lang: "zh-cn",
})
assert.NoError(t, err)
styleID57, err := f.NewStyle(&Style{
NumFmt: 57,
Lang: "zh-cn",
})
assert.NoError(t, err)
result, err = f.formattedValue(&xlsxC{S: styleID31, V: "43528"}, false, CellTypeNumber)
assert.NoError(t, err)
assert.Equal(t, "2019年3月4日", result)
result, err = f.formattedValue(&xlsxC{S: styleID57, V: "43528"}, false, CellTypeNumber)
assert.NoError(t, err)
assert.Equal(t, "2019年3月", result)
f.options = originalFileOptions

// Test format value with system opts
originalFileOptions = f.options
f.options = &Options{
Locale: "zh-CN",
ShortDateFmtCode: "yyyy/m/d",
LongDateFmtCode: "[$-804]yyyy\"\"m\"\"d\"\"",
LongTimeFmtCode: "[$-804]hh:mm:ss",
}
styleID14, err := f.NewStyle(&Style{
NumFmt: 14,
})
assert.NoError(t, err)
shortDateStr := "[$-F800]dddd, mmmm dd, yyyy"
styleIDSystemShortDate, err := f.NewStyle(&Style{
CustomNumFmt: &shortDateStr,
})
assert.NoError(t, err)
systemTimeStr := "[$-F400]h:mm:ss AM/PM"
styleIDSystemTime, err := f.NewStyle(&Style{
CustomNumFmt: &systemTimeStr,
})
assert.NoError(t, err)
result, err = f.formattedValue(&xlsxC{S: styleID14, V: "43528"}, false, CellTypeNumber)
assert.NoError(t, err)
assert.Equal(t, "2019/3/4", result)
result, err = f.formattedValue(&xlsxC{S: styleIDSystemShortDate, V: "43528"}, false, CellTypeNumber)
assert.NoError(t, err)
assert.Equal(t, "2019年3月4日", result)
result, err = f.formattedValue(&xlsxC{S: styleIDSystemTime, V: "43528"}, false, CellTypeNumber)
assert.NoError(t, err)
assert.Equal(t, "00:00:00", result)
f.options = originalFileOptions

// Test format value with unsupported charset workbook
f.WorkBook = nil
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
Expand All @@ -890,6 +946,24 @@ func TestFormattedValue(t *testing.T) {
assert.Equal(t, "text", format("text", "0", false, CellTypeNumber, nil))
}

func TestFormattedValueNotSupportLocale(t *testing.T) {
// Set the Locale options to not support value and verify that the formattedValue
f := NewFile(Options{Locale: "notSupportLocale"})
styleID31, err := f.NewStyle(&Style{
NumFmt: 31,
})
result, err := f.formattedValue(&xlsxC{S: styleID31, V: "43528"}, false, CellTypeNumber)
assert.NoError(t, err)
assert.Equal(t, "43528", result)
styleID14, err := f.NewStyle(&Style{
NumFmt: 14,
})
result, err = f.formattedValue(&xlsxC{S: styleID14, V: "43528"}, false, CellTypeNumber)
assert.NoError(t, err)
assert.Equal(t, "03-04-19", result)

}

func TestFormattedValueNilXfs(t *testing.T) {
// Set the CellXfs to nil and verify that the formattedValue function does not crash
f := NewFile()
Expand Down
4 changes: 4 additions & 0 deletions excelize.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ type charsetTranscoderFn func(charset string, input io.Reader) (rdr io.Reader, e
// should be less than or equal to UnzipSizeLimit, the default value is
// 16MB.
//
// Locale specifies the file parse locale, The resolution of the locale
// in the file will be affected;
//
// ShortDateFmtCode specifies the short date number format code. In the
// spreadsheet applications, date formats display date and time serial numbers
// as date values. Date formats that begin with an asterisk (*) respond to
Expand All @@ -97,6 +100,7 @@ type Options struct {
RawCellValue bool
UnzipSizeLimit int64
UnzipXMLSizeLimit int64
Locale string
ShortDateFmtCode string
LongDateFmtCode string
LongTimeFmtCode string
Expand Down
6 changes: 3 additions & 3 deletions styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -1815,7 +1815,7 @@ func (f *File) NewStyle(style *Style) (int, error) {
return cellXfsID, err
}

numFmtID := newNumFmt(s, fs)
numFmtID := f.newNumFmt(s, fs)

if fs.Font != nil {
fontID, _ = f.getFontID(s, fs)
Expand Down Expand Up @@ -2113,7 +2113,7 @@ func getNumFmtID(styleSheet *xlsxStyleSheet, style *Style) (numFmtID int) {

// newNumFmt provides a function to check if number format code in the range
// of built-in values.
func newNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
func (f *File) newNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
dp := "0."
numFmtID := 164 // Default custom number format code from 164.
if style.DecimalPlaces < 0 || style.DecimalPlaces > 30 {
Expand All @@ -2128,7 +2128,7 @@ func newNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
}
return setCustomNumFmt(styleSheet, style)
}
_, ok := builtInNumFmt[style.NumFmt]
_, ok := f.getBuiltInNumFmtCode(style.NumFmt)
if !ok {
fc, currency := currencyNumFmt[style.NumFmt]
if !currency {
Expand Down

0 comments on commit ddb0f66

Please sign in to comment.