Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(func): add locale argument support #2522

Merged
merged 4 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 132 additions & 2 deletions docs/en_US/sqls/functions/string_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,137 @@ Returns the uppercase version of the given string.
## FORMAT

```text
format(col,D)
format(col,D[,locale])
```

Formats the number X to a format like '#######.##', rounded to D decimal places, and returns the result as a string.
Formats the number X to a format like '#######.##', rounded to D decimal places, and returns the result as a string,
The optional third parameter enables a locale to be specified to be used for the result number's decimal point.

```sql
SELECT format(12332.1234567, 4,"en_US");
-> '12,332.1235'
```

Depending on the region, the display format of numbers can vary greatly. For example, here are examples to format the number 123456.78 specifically for certain regions:

| **Locale Value** | **Format** |
|------------------|------------|
| en_US | 123,456.78 |
| de_DE | 123.456,78 |
| de_CH | 123'456.78 |

More regional options:

| Locale Value | Meaning |
|--------------|------------------------------|
| ar_AE | Arabic - United Arab Emirates|
| ar_BH | Arabic - Bahrain |
| ar_DZ | Arabic - Algeria |
| ar_EG | Arabic - Egypt |
| ar_IN | Arabic - India |
| ar_IQ | Arabic - Iraq |
| ar_JO | Arabic - Jordan |
| ar_KW | Arabic - Kuwait |
| ar_LB | Arabic - Lebanon |
| ar_LY | Arabic - Libya |
| ar_MA | Arabic - Morocco |
| ar_OM | Arabic - Oman |
| ar_QA | Arabic - Qatar |
| ar_SA | Arabic - Saudi Arabia |
| ar_SD | Arabic - Sudan |
| ar_SY | Arabic - Syria |
| ar_TN | Arabic - Tunisia |
| ar_YE | Arabic - Yemen |
| be_BY | Belarusian - Belarus |
| bg_BG | Bulgarian - Bulgaria |
| ca_ES | Catalan - Spain |
| cs_CZ | Czech - Czech Republic |
| da_DK | Danish - Denmark |
| de_AT | German - Austria |
| de_BE | German - Belgium |
| de_CH | German - Switzerland |
| de_DE | German - Germany |
| de_LU | German - Luxembourg |
| el_GR | Greek - Greece |
| en_AU | English - Australia |
| en_CA | English - Canada |
| en_GB | English - United Kingdom |
| en_IN | English - India |
| en_NZ | English - New Zealand |
| en_PH | English - Philippines |
| en_US | English - United States |
| en_ZA | English - South Africa |
| en_ZW | English - Zimbabwe |
| es_AR | Spanish - Argentina |
| es_BO | Spanish - Bolivia |
| es_CL | Spanish - Chile |
| es_CO | Spanish - Colombia |
| es_CR | Spanish - Costa Rica |
| es_DO | Spanish - Dominican Republic |
| es_EC | Spanish - Ecuador |
| es_ES | Spanish - Spain |
| es_GT | Spanish - Guatemala |
| es_HN | Spanish - Honduras |
| es_MX | Spanish - Mexico |
| es_NI | Spanish - Nicaragua |
| es_PA | Spanish - Panama |
| es_PE | Spanish - Peru |
| es_PR | Spanish - Puerto Rico |
| es_PY | Spanish - Paraguay |
| es_SV | Spanish - El Salvador |
| es_US | Spanish - United States |
| es_UY | Spanish - Uruguay |
| es_VE | Spanish - Venezuela |
| et_EE | Estonian - Estonia |
| eu_ES | Basque - Spain |
| fi_FI | Finnish - Finland |
| fo_FO | Faroese - Faroe Islands |
| fr_BE | French - Belgium |
| fr_CA | French - Canada |
| fr_CH | French - Switzerland |
| fr_FR | French - France |
| fr_LU | French - Luxembourg |
| gl_ES | Galician - Spain |
| gu_IN | Gujarati - India |
| he_IL | Hebrew - Israel |
| hi_IN | Hindi - India |
| hr_HR | Croatian - Croatia |
| hu_HU | Hungarian - Hungary |
| id_ID | Indonesian - Indonesia |
| is_IS | Icelandic - Iceland |
| it_CH | Italian - Switzerland |
| it_IT | Italian - Italy |
| ja_JP | Japanese - Japan |
| ko_KR | Korean - Republic of Korea |
| lt_LT | Lithuanian - Lithuania |
| lv_LV | Latvian - Latvia |
| mk_MK | Macedonian - North Macedonia |
| mn_MN | Mongolia - Mongolian |
| ms_MY | Malay - Malaysia |
| nb_NO | Norwegian(Bokmål) - Norway |
| nl_BE | Dutch - Belgium |
| nl_NL | Dutch - The Netherlands |
| no_NO | Norwegian - Norway |
| pl_PL | Polish - Poland |
| pt_BR | Portugese - Brazil |
| pt_PT | Portugese - Portugal |
| rm_CH | Romansh - Switzerland |
| ro_RO | Romanian - Romania |
| ru_RU | Russian - Russia |
| ru_UA | Russian - Ukraine |
| sk_SK | Slovak - Slovakia |
| sl_SI | Slovenian - Slovenia |
| sq_AL | Albanian - Albania |
| sr_RS | Serbian - Serbia |
| sv_FI | Swedish - Finland |
| sv_SE | Swedish - Sweden |
| ta_IN | Tamil - India |
| te_IN | Telugu - India |
| th_TH | Thai - Thailand |
| tr_TR | Turkish - Turkey |
| uk_UA | Ukrainian - Ukraine |
| ur_PK | Urdu - Pakistan |
| vi_VN | Vietnamese - Vietnam |
| zh_CN | Chinese - China |
| zh_HK | Chinese - Hong Kong |
| zh_TW | Chinese - Taiwan |
134 changes: 132 additions & 2 deletions docs/zh_CN/sqls/functions/string_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,137 @@ upper(col)
## FORMAT

```text
format(col,D)
format(col,D[,locale])
```

将数字X格式化为类似'#######.##'的格式,四舍五入保留D位小数,并将结果作为字符串返回。
将数字X格式化为类似'#######.##'的格式,四舍五入保留D位小数,并将结果作为字符串返回。可选的第三个参数允许指定要用于结果数字小数点的
地区设置。

```sql
SELECT format(12332.1234567, 4,"en_US");
-> '12,332.1235'
```

根据区域的不同,数值的显示格式也大不相同。例如,以下是针对特定区域设置对数字 123456.78 进行格式设置的例子:

| **区域** | **数字格式** |
|--------|------------|
| en_US | 123,456.78 |
| de_DE | 123.456,78 |
| de_CH | 123'456.78 |

更多地区选项:

| 地区值 | 含义 |
|-------|-----------------|
| ar_AE | 阿拉伯语 - 阿拉伯联合酋长国 |
| ar_BH | 阿拉伯语 - 巴林 |
| ar_DZ | 阿拉伯语 - 阿尔及利亚 |
| ar_EG | 阿拉伯语 - 埃及 |
| ar_IN | 阿拉伯语 - 印度 |
| ar_IQ | 阿拉伯语 - 伊拉克 |
| ar_JO | 阿拉伯语 - 约旦 |
| ar_KW | 阿拉伯语 - 科威特 |
| ar_LB | 阿拉伯语 - 黎巴嫩 |
| ar_LY | 阿拉伯语 - 利比亚 |
| ar_MA | 阿拉伯语 - 摩洛哥 |
| ar_OM | 阿拉伯语 - 阿曼 |
| ar_QA | 阿拉伯语 - 卡塔尔 |
| ar_SA | 阿拉伯语 - 沙特阿拉伯 |
| ar_SD | 阿拉伯语 - 苏丹 |
| ar_SY | 阿拉伯语 - 叙利亚 |
| ar_TN | 阿拉伯语 - 突尼斯 |
| ar_YE | 阿拉伯语 - 也门 |
| be_BY | 白俄罗斯语 - 白俄罗斯 |
| bg_BG | 保加利亚语 - 保加利亚 |
| ca_ES | 加泰罗尼亚语 - 西班牙 |
| cs_CZ | 捷克语 - 捷克共和国 |
| da_DK | 丹麦语 - 丹麦 |
| de_AT | 德语 - 奥地利 |
| de_BE | 德语 - 比利时 |
| de_CH | 德语 - 瑞士 |
| de_DE | 德语 - 德国 |
| de_LU | 德语 - 卢森堡 |
| el_GR | 希腊语 - 希腊 |
| en_AU | 英语 - 澳大利亚 |
| en_CA | 英语 - 加拿大 |
| en_GB | 英语 - 英国 |
| en_IN | 英语 - 印度 |
| en_NZ | 英语 - 新西兰 |
| en_PH | 英语 - 菲律宾 |
| en_US | 英语 - 美国 |
| en_ZA | 英语 - 南非 |
| en_ZW | 英语 - 津巴布韦 |
| es_AR | 西班牙语 - 阿根廷 |
| es_BO | 西班牙语 - 玻利维亚 |
| es_CL | 西班牙语 - 智利 |
| es_CO | 西班牙语 - 哥伦比亚 |
| es_CR | 西班牙语 - 哥斯达黎加 |
| es_DO | 西班牙语 - 多米尼加共和国 |
| es_EC | 西班牙语 - 厄瓜多尔 |
| es_ES | 西班牙语 - 西班牙 |
| es_GT | 西班牙语 - 危地马拉 |
| es_HN | 西班牙语 - 洪都拉斯 |
| es_MX | 西班牙语 - 墨西哥 |
| es_NI | 西班牙语 - 尼加拉瓜 |
| es_PA | 西班牙语 - 巴拿马 |
| es_PE | 西班牙语 - 秘鲁 |
| es_PR | 西班牙语 - 波多黎各 |
| es_PY | 西班牙语 - 巴拉圭 |
| es_SV | 西班牙语 - 萨尔瓦多 |
| es_US | 西班牙语 - 美国 |
| es_UY | 西班牙语 - 乌拉圭 |
| es_VE | 西班牙语 - 委内瑞拉 |
| et_EE | 爱沙尼亚语 - 爱沙尼亚 |
| eu_ES | 巴斯克语 - 西班牙 |
| fi_FI | 芬兰语 - 芬兰 |
| fo_FO | 法罗语 - 法罗群岛 |
| fr_BE | 法语 - 比利时 |
| fr_CA | 法语 - 加拿大 |
| fr_CH | 法语 - 瑞士 |
| fr_FR | 法语 - 法国 |
| fr_LU | 法语 - 卢森堡 |
| gl_ES | 加利西亚语 - 西班牙 |
| gu_IN | 古吉拉特语 - 印度 |
| he_IL | 希伯来语 - 以色列 |
| hi_IN | 印地语 - 印度 |
| hr_HR | 克罗地亚语 - 克罗地亚 |
| hu_HU | 匈牙利语 - 匈牙利 |
| id_ID | 印度尼西亚语 - 印度尼西亚 |
| is_IS | 冰岛语 - 冰岛 |
| it_CH | 意大利语 - 瑞士 |
| it_IT | 意大利语 - 意大利 |
| ja_JP | 日语 - 日本 |
| ko_KR | 朝鲜语 - 韩国 |
| lt_LT | 立陶宛语 - 立陶宛 |
| lv_LV | 拉脱维亚语 - 拉脱维亚 |
| mk_MK | 马其顿语 - 北马其顿 |
| mn_MN | 蒙古语 - 蒙古 |
| ms_MY | 马来语 - 马来西亚 |
| nb_NO | 挪威语(书面) - 挪威 |
| nl_BE | 荷兰语 - 比利时 |
| nl_NL | 荷兰语 - 荷兰 |
| no_NO | 挪威语 - 挪威 |
| pl_PL | 波兰语 - 波兰 |
| pt_BR | 葡萄牙语 - 巴西 |
| pt_PT | 葡萄牙语 - 葡萄牙 |
| rm_CH | 罗曼什语 - 瑞士 |
| ro_RO | 罗马尼亚语 - 罗马尼亚 |
| ru_RU | 俄语 - 俄罗斯 |
| ru_UA | 俄语 - 乌克兰 |
| sk_SK | 斯洛伐克语 - 斯洛伐克 |
| sl_SI | 斯洛文尼亚语 - 斯洛文尼亚 |
| sq_AL | 阿尔巴尼亚语 - 阿尔巴尼亚 |
| sr_RS | 塞尔维亚语 - 塞尔维亚 |
| sv_FI | 瑞典语 - 芬兰 |
| sv_SE | 瑞典语 - 瑞典 |
| ta_IN | 泰米尔语 - 印度 |
| te_IN | 泰卢固语 - 印度 |
| th_TH | 泰语 - 泰国 |
| tr_TR | 土耳其语 - 土耳其 |
| uk_UA | 乌克兰语 - 乌克兰 |
| ur_PK | 乌尔都语 - 巴基斯坦 |
| vi_VN | 越南语 - 越南 |
| zh_CN | 中文 - 中国 |
| zh_HK | 中文 - 香港 |
| zh_TW | 中文 - 台湾 |
54 changes: 39 additions & 15 deletions internal/binder/function/funcs_str.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ import (
"errors"
"fmt"
"regexp"
"strconv"
"strings"
"unicode"
"unicode/utf8"

"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/number"

"github.com/lf-edge/ekuiper/pkg/api"
"github.com/lf-edge/ekuiper/pkg/ast"
"github.com/lf-edge/ekuiper/pkg/cast"
Expand Down Expand Up @@ -346,24 +349,45 @@ func registerStrFunc() {
exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
var v1 float64
var v2 int
var e error
if v1, e = cast.ToFloat64(args[0], cast.CONVERT_SAMEKIND); e != nil {
return e, false
}
if v2, e = cast.ToInt(args[1], cast.STRICT); e != nil {
return e, false
}

v1, _ = cast.ToFloat64(args[0], cast.CONVERT_SAMEKIND)
v2, _ = cast.ToInt(args[1], cast.STRICT)
if v2 < 0 {
return errors.New("the decimal places must greater or equal than 0"), false
}
return formatNumber(v1, v2), true
if len(args) == 3 {
v3 := cast.ToStringAlways(args[2])

tag, err := language.Parse(v3)
if err != nil {
return errors.New("not support for the specific locale:" + v3), false
}
_, _, r := tag.Raw()
if !r.IsCountry() {
return errors.New("not support for the specific locale:" + v3), false
}
p := message.NewPrinter(tag)
return p.Sprint(number.Decimal(v1, number.Scale(v2))), true
} else {
p := message.NewPrinter(language.MustParse("en"))
return p.Sprint(number.Decimal(v1, number.Scale(v2), number.NoSeparator())), true
}
},
val: func(_ api.FunctionContext, args []ast.Expr) error {
if err := ValidateAtLeast(2, len(args)); err != nil {
return err
}
if !ast.IsNumericArg(args[0]) {
return ProduceErrInfo(0, "numeric")
}
if !ast.IsIntegerArg(args[1]) {
return ProduceErrInfo(1, "integer")
}
if len(args) == 3 && !ast.IsStringArg(args[2]) {
return ProduceErrInfo(2, "string")
}
return nil
},
val: ValidateTwoNumberArg,
check: returnNilIfHasAnyNil,
}
}

func formatNumber(x float64, d int) string {
format := "%." + strconv.Itoa(d) + "f"
return fmt.Sprintf(format, x)
}
Loading