Source

adminjs/src/utils/translate-functions.factory.ts

  1. import { i18n as I18n, TFunction, TOptions } from 'i18next'
  2. import startCase from 'lodash/startCase'
  3. /**
  4. * @memberof TranslateFunctions
  5. * @alias TranslateFunction
  6. */
  7. export type TranslateFunction = (
  8. /**
  9. * kwy which should be translated in a given namespace
  10. */
  11. key: string,
  12. /**
  13. * Optional resourceId or [Translate options]{@link https://www.i18next.com/overview/configuration-options}
  14. */
  15. resourceId?: string | TOptions,
  16. /**
  17. * [Translate options]{@link https://www.i18next.com/overview/configuration-options}
  18. */
  19. options?: TOptions
  20. ) => string
  21. /**
  22. * Translate Functions are the helper functions which you can use to translate
  23. * your application.
  24. *
  25. * On the fronted they can be used with {@link useTranslation} hook. On the backend
  26. * they are injected to any {@link AdminJS} instance and {@link ActionContext}.
  27. */
  28. export interface TranslateFunctions {
  29. /**
  30. * shortcut for I18n.translate function.
  31. * @see https://www.i18next.com/overview/api#t
  32. */
  33. t: TFunction;
  34. /**
  35. * I18n.translate function.
  36. * @see https://www.i18next.com/overview/api#t
  37. */
  38. translate: TFunction;
  39. /**
  40. * Shortcut for {@link TranslateFunctions#translateAction}
  41. */
  42. ta: TranslateFunction;
  43. /**
  44. * Translates all [actions]{@link Action}, to be more specific - their labels.
  45. * By default, it looks for a [translation key]{@link LocaleTranslations} in
  46. * `resource.{resourceId}.actions.{actionName}`, when it doesn't find
  47. * that, the lookup is moved to `actions.{actionName}`.
  48. * Finally, when that also fails, it returns startCase of the action name.
  49. */
  50. translateAction: TranslateFunction;
  51. /**
  52. * Shortcut for {@link TranslateFunctions#translateButton}
  53. */
  54. tb: TranslateFunction;
  55. /**
  56. * Translates all buttons.
  57. * By default, it looks for a [translation key]{@link LocaleTranslations} in
  58. * `resource.{resourceId}.buttons.{actionName}`, when it doesn't find
  59. * that, the lookup is moved to `buttons.{actionName}`.
  60. * Finally, when that also fails, it returns startCase of the given button name.
  61. */
  62. translateButton: TranslateFunction;
  63. /**
  64. * Shortcut for {@link TranslateFunctions#translateLabel}
  65. */
  66. tl: TranslateFunction;
  67. /**
  68. * Translates all labels. Most of all all resource names are treated as labels.
  69. * Also, labels are texts in the user interface which cannot be recognized
  70. * as any other type.
  71. * By default, it looks for a [translation key]{@link LocaleTranslations} in
  72. * `resource.{resourceId}.labels.{actionName}`, when it doesn't find
  73. * that, the lookup is moved to `labels.{actionName}`.
  74. * Finally, when that also fails, it returns startCase of the given label.
  75. */
  76. translateLabel: TranslateFunction;
  77. /**
  78. * Shortcut for {@link TranslateFunctions#translateProperty}
  79. */
  80. tp: TranslateFunction;
  81. /**
  82. * Translates all the property names.
  83. * By default, it looks for a [translation key]{@link LocaleTranslations} in
  84. * `resource.{resourceId}.properties.{propertyPath}`, when it doesn't find
  85. * that, the lookup is moved to `properties.{propertyPath}`. When that fails,
  86. * it returns startCase of the given property name.
  87. *
  88. * What is important here is that you can put nested property as well, In that
  89. * case you have to pass dotted path:
  90. *
  91. * ```javascript
  92. * {
  93. * properties: {
  94. * parent: 'parent property',
  95. * 'parent.nested': 'nested property'
  96. * }
  97. * }
  98. * ```
  99. */
  100. translateProperty: TranslateFunction;
  101. /**
  102. * Shortcut for {@link TranslateFunctions#translateMessage}
  103. */
  104. tm: TranslateFunction;
  105. /**
  106. * Translates all the messages in the application.
  107. * By default, it looks for a [translation key]{@link LocaleTranslations} in
  108. * `resource.{resourceId}.messages.{messageName}`, when it doesn't find
  109. * that, the lookup is moved to `messages.{messageName}`.
  110. * Finally, when that also fails, it returns startCase of the given message name.
  111. */
  112. translateMessage: TranslateFunction;
  113. }
  114. export const formatName = (name: string): string => name.split('.').join('.')
  115. const translate = (
  116. i18n: I18n,
  117. key: string,
  118. name: string,
  119. resourceId?: string | TOptions,
  120. options?: TOptions,
  121. ): string => {
  122. const realOptions: TOptions = (typeof resourceId === 'string' ? options : resourceId) || {}
  123. const formattedName = formatName(name)
  124. let keys = [`${key}.${formattedName}`]
  125. if (resourceId) {
  126. keys = [`resources.${resourceId}.${key}.${formattedName}`, ...keys]
  127. }
  128. if (i18n.exists(keys)) {
  129. return i18n.t(keys, realOptions)
  130. }
  131. return realOptions.defaultValue ?? startCase(name)
  132. }
  133. export const createFunctions = (i18n: I18n): TranslateFunctions => {
  134. const translateAction: TranslateFunction = (actionName, resourceId, options) => (
  135. translate(i18n, 'actions', actionName as string, resourceId, options)
  136. )
  137. const translateButton: TranslateFunction = (
  138. buttonLabel, resourceId, options,
  139. ) => (
  140. translate(i18n, 'buttons', buttonLabel, resourceId, options)
  141. )
  142. const translateLabel: TranslateFunction = (label, resourceId, options) => (
  143. translate(i18n, 'labels', label as string, resourceId, options)
  144. )
  145. const translateProperty: TranslateFunction = (propertyName, resourceId, options) => (
  146. translate(i18n, 'properties', propertyName, resourceId, options)
  147. )
  148. const translateMessage: TranslateFunction = (messageName, resourceId, options) => (
  149. translate(i18n, 'messages', messageName, resourceId, options)
  150. )
  151. return {
  152. translateAction,
  153. ta: translateAction,
  154. translateButton,
  155. tb: translateButton,
  156. translateLabel,
  157. tl: translateLabel,
  158. translateProperty,
  159. tp: translateProperty,
  160. translateMessage,
  161. tm: translateMessage,
  162. t: i18n.t,
  163. translate: i18n.t,
  164. }
  165. }