translations.ts 3.1 KB

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