translations.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. import { reactive, ref } from 'vue'
  3. import { defineStore } from 'pinia'
  4. import { i18n } from '@shared/i18n'
  5. import log from '@shared/utils/log'
  6. import { useTranslationsQuery } from '@shared/graphql/queries/translations.api'
  7. import { QueryHandler } from '@shared/server/apollo/handler'
  8. import type {
  9. TranslationsQuery,
  10. TranslationsQueryVariables,
  11. } from '@shared/graphql/types'
  12. import type { ReactiveFunction } from '@shared/types/utils'
  13. import { useApplicationStore } from '@shared/stores/application'
  14. interface TranslationsCacheValue {
  15. cacheKey: string
  16. translations: Record<string, string>
  17. }
  18. const localStorageKey = (locale: string): string => {
  19. return `translationsStoreCache::${locale}`
  20. }
  21. const loadCache = (locale: string): TranslationsCacheValue => {
  22. const cached = JSON.parse(
  23. window.localStorage.getItem(localStorageKey(locale)) || '{}',
  24. )
  25. log.debug('translations.loadCache()', locale, cached)
  26. return {
  27. cacheKey: cached.cacheKey || '',
  28. translations: cached.translations || {},
  29. }
  30. }
  31. const setCache = (locale: string, value: TranslationsCacheValue): void => {
  32. const serialized = JSON.stringify(value)
  33. window.localStorage.setItem(localStorageKey(locale), serialized)
  34. log.debug('translations.setCache()', locale, value)
  35. }
  36. const translationsQueryVariables = reactive({})
  37. let translationsQuery: QueryHandler<
  38. TranslationsQuery,
  39. TranslationsQueryVariables
  40. >
  41. const getTranslationsQuery = () => {
  42. if (translationsQuery) return translationsQuery
  43. translationsQuery = new QueryHandler(
  44. useTranslationsQuery(
  45. translationsQueryVariables as ReactiveFunction<TranslationsQueryVariables>,
  46. ),
  47. {
  48. // Don't show an error while app is loading as this would cause startup failure.
  49. errorShowNotification: useApplicationStore().loaded,
  50. },
  51. )
  52. return translationsQuery
  53. }
  54. export const useTranslationsStore = defineStore(
  55. 'translations',
  56. () => {
  57. const cacheKey = ref<string>('CACHE_EMPTY')
  58. const translationData = ref<Record<string, string>>({})
  59. const load = async (locale: string): Promise<void> => {
  60. log.debug('translations.load()', locale)
  61. const cachedData = loadCache(locale)
  62. Object.assign(translationsQueryVariables, {
  63. cacheKey: cachedData.cacheKey,
  64. locale,
  65. })
  66. const query = getTranslationsQuery()
  67. const result = await query.loadedResult()
  68. if (!result?.translations) {
  69. return
  70. }
  71. if (result.translations.isCacheStillValid) {
  72. cacheKey.value = cachedData.cacheKey
  73. translationData.value = cachedData.translations
  74. } else {
  75. cacheKey.value = result.translations.cacheKey || 'CACHE_EMPTY'
  76. translationData.value = result.translations.translations
  77. setCache(locale, {
  78. cacheKey: cacheKey.value,
  79. translations: translationData.value,
  80. })
  81. }
  82. log.debug(
  83. 'translations.load() setting new translation map',
  84. locale,
  85. translationData.value,
  86. )
  87. i18n.setTranslationMap(new Map(Object.entries(translationData.value)))
  88. }
  89. return {
  90. cacheKey,
  91. translationData,
  92. load,
  93. }
  94. },
  95. {
  96. requiresAuth: false,
  97. },
  98. )