config.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package views
  2. import (
  3. "fmt"
  4. "net/url"
  5. "reflect"
  6. "github.com/qor5/admin/activity"
  7. "github.com/qor5/admin/l10n"
  8. "github.com/qor5/admin/presets"
  9. "github.com/qor5/admin/utils"
  10. v "github.com/qor5/ui/vuetify"
  11. vx "github.com/qor5/ui/vuetifyx"
  12. "github.com/qor5/web"
  13. "github.com/sunfmin/reflectutils"
  14. h "github.com/theplant/htmlgo"
  15. "golang.org/x/text/language"
  16. "gorm.io/gorm"
  17. )
  18. const WrapHandlerKey = "l10nWrapHandlerKey"
  19. const MenuTopItemFunc = "l10nMenuTopItemFunc"
  20. func Configure(b *presets.Builder, db *gorm.DB, lb *l10n.Builder, ab *activity.ActivityBuilder, models ...*presets.ModelBuilder) {
  21. for _, m := range models {
  22. obj := m.NewModel()
  23. _ = obj.(presets.SlugEncoder)
  24. _ = obj.(presets.SlugDecoder)
  25. _ = obj.(l10n.L10nInterface)
  26. if l10nONModel, exist := obj.(l10n.L10nONInterface); exist {
  27. l10nONModel.L10nON()
  28. }
  29. m.Listing().Field("Locale")
  30. searcher := m.Listing().Searcher
  31. m.Listing().SearchFunc(func(model interface{}, params *presets.SearchParams, ctx *web.EventContext) (r interface{}, totalCount int, err error) {
  32. if localeCode := ctx.R.Context().Value(l10n.LocaleCode); localeCode != nil {
  33. con := presets.SQLCondition{
  34. Query: "locale_code = ?",
  35. Args: []interface{}{localeCode},
  36. }
  37. params.SQLConditions = append(params.SQLConditions, &con)
  38. }
  39. return searcher(model, params, ctx)
  40. })
  41. setter := m.Editing().Setter
  42. m.Editing().SetterFunc(func(obj interface{}, ctx *web.EventContext) {
  43. if ctx.R.FormValue(presets.ParamID) == "" {
  44. if localeCode := ctx.R.Context().Value(l10n.LocaleCode); localeCode != nil {
  45. if err := reflectutils.Set(obj, "LocaleCode", localeCode); err != nil {
  46. return
  47. }
  48. }
  49. }
  50. if setter != nil {
  51. setter(obj, ctx)
  52. }
  53. })
  54. rmb := m.Listing().RowMenu()
  55. rmb.RowMenuItem("Localize").ComponentFunc(localizeRowMenuItemFunc(m.Info(), "", url.Values{}))
  56. registerEventFuncs(db, m, lb, ab)
  57. }
  58. b.FieldDefaults(presets.LIST).
  59. FieldType(l10n.Locale{}).
  60. ComponentFunc(localeListFunc(db, lb))
  61. b.FieldDefaults(presets.WRITE).
  62. FieldType(l10n.Locale{}).
  63. ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
  64. return nil
  65. }).
  66. SetterFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) (err error) {
  67. return nil
  68. })
  69. b.AddWrapHandler(WrapHandlerKey, lb.EnsureLocale)
  70. b.AddMenuTopItemFunc(MenuTopItemFunc, runSwitchLocaleFunc(lb))
  71. b.I18n().
  72. RegisterForModule(language.English, I18nLocalizeKey, Messages_en_US).
  73. RegisterForModule(language.SimplifiedChinese, I18nLocalizeKey, Messages_zh_CN).
  74. RegisterForModule(language.Japanese, I18nLocalizeKey, Messages_ja_JP)
  75. }
  76. func localeListFunc(db *gorm.DB, lb *l10n.Builder) func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
  77. return func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
  78. id, err := reflectutils.Get(obj, "ID")
  79. if err != nil {
  80. return nil
  81. }
  82. fromLocale := lb.GetCorrectLocaleCode(ctx.R)
  83. objs := reflect.New(reflect.SliceOf(reflect.TypeOf(obj).Elem())).Interface()
  84. err = db.Distinct("locale_code").Where("id = ? AND locale_code <> ?", id, fromLocale).Find(objs).Error
  85. if err != nil {
  86. return nil
  87. }
  88. vo := reflect.ValueOf(objs).Elem()
  89. var existLocales []string
  90. for i := 0; i < vo.Len(); i++ {
  91. existLocales = append(existLocales, vo.Index(i).FieldByName("LocaleCode").String())
  92. }
  93. allLocales := lb.GetSupportLocaleCodesFromRequest(ctx.R)
  94. var otherLocales []string
  95. for _, locale := range allLocales {
  96. if utils.Contains(existLocales, locale) {
  97. otherLocales = append(otherLocales, locale)
  98. }
  99. }
  100. var chips []h.HTMLComponent
  101. chips = append(chips, v.VChip(h.Text(MustGetTranslation(ctx.R, lb.GetLocaleLabel(fromLocale)))).Color("green").TextColor("white").Label(true).Small(true))
  102. for _, locale := range otherLocales {
  103. chips = append(chips, v.VChip(h.Text(MustGetTranslation(ctx.R, lb.GetLocaleLabel(locale)))).Label(true).Small(true))
  104. }
  105. return h.Td(
  106. chips...,
  107. )
  108. }
  109. }
  110. func runSwitchLocaleFunc(lb *l10n.Builder) func(ctx *web.EventContext) (r h.HTMLComponent) {
  111. return func(ctx *web.EventContext) (r h.HTMLComponent) {
  112. var supportLocales = lb.GetSupportLocaleCodesFromRequest(ctx.R)
  113. if len(lb.GetSupportLocaleCodes()) <= 1 || len(supportLocales) == 0 {
  114. return nil
  115. }
  116. localeQueryName := lb.GetQueryName()
  117. if len(supportLocales) == 1 {
  118. return h.Template().Children(
  119. h.Div(
  120. v.VList(
  121. v.VListItem(
  122. v.VListItemIcon(
  123. v.VIcon("language").Small(true).Class("ml-1"),
  124. ).Attr("style", "margin-right: 16px"),
  125. v.VListItemContent(
  126. v.VListItemTitle(
  127. h.Div(h.Text(fmt.Sprintf("%s%s %s", MustGetTranslation(ctx.R, "Location"), MustGetTranslation(ctx.R, "Colon"), MustGetTranslation(ctx.R, lb.GetLocaleLabel(supportLocales[0]))))).Role("button"),
  128. ),
  129. ),
  130. ).Class("pa-0").Dense(true),
  131. ).Class("pa-0 ma-n4 mt-n6"),
  132. ).Attr("@click", web.Plaid().Query(localeQueryName, supportLocales[0]).Go()),
  133. )
  134. }
  135. locale := lb.GetCorrectLocaleCode(ctx.R)
  136. var locales []h.HTMLComponent
  137. for _, contry := range supportLocales {
  138. locales = append(locales,
  139. h.Div(
  140. v.VListItem(
  141. v.VListItemContent(
  142. v.VListItemTitle(
  143. h.Div(h.Text(MustGetTranslation(ctx.R, lb.GetLocaleLabel(contry)))),
  144. ),
  145. ),
  146. ).Attr("@click", web.Plaid().Query(localeQueryName, contry).Go()),
  147. ),
  148. )
  149. }
  150. return v.VMenu().OffsetY(true).Children(
  151. h.Template().Attr("v-slot:activator", "{on, attrs}").Children(
  152. h.Div(
  153. v.VList(
  154. v.VListItem(
  155. v.VListItemIcon(
  156. v.VIcon("language").Small(true).Class("ml-1"),
  157. ).Attr("style", "margin-right: 16px"),
  158. v.VListItemContent(
  159. v.VListItemTitle(
  160. h.Text(fmt.Sprintf("%s%s %s", MustGetTranslation(ctx.R, "Location"), MustGetTranslation(ctx.R, "Colon"), MustGetTranslation(ctx.R, lb.GetLocaleLabel(locale)))),
  161. ),
  162. ),
  163. v.VListItemIcon(
  164. v.VIcon("arrow_drop_down").Small(false).Class("mr-1"),
  165. ),
  166. ).Class("pa-0").Dense(true),
  167. ).Class("pa-0 ma-n4 mt-n6"),
  168. ).Attr("v-bind", "attrs").Attr("v-on", "on"),
  169. ),
  170. v.VList(
  171. locales...,
  172. ).Dense(true),
  173. )
  174. }
  175. }
  176. func localizeRowMenuItemFunc(mi *presets.ModelInfo, url string, editExtraParams url.Values) vx.RowMenuItemFunc {
  177. return func(obj interface{}, id string, ctx *web.EventContext) h.HTMLComponent {
  178. if mi.Verifier().Do(presets.PermUpdate).ObjectOn(obj).WithReq(ctx.R).IsAllowed() != nil {
  179. return nil
  180. }
  181. return v.VListItem(
  182. v.VListItemIcon(v.VIcon("language")),
  183. v.VListItemTitle(h.Text(MustGetTranslation(ctx.R, "Localize"))),
  184. ).Attr("@click", web.Plaid().
  185. EventFunc(Localize).
  186. Queries(editExtraParams).
  187. Query(presets.ParamID, id).
  188. URL(url).
  189. Go())
  190. }
  191. }