translations.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { defineStore } from 'pinia'
  3. import { effectScope, ref } from 'vue'
  4. import { useTranslationsLazyQuery } from '#shared/graphql/queries/translations.api.ts'
  5. import type {
  6. TranslationsQuery,
  7. TranslationsQueryVariables,
  8. } from '#shared/graphql/types.ts'
  9. import { i18n } from '#shared/i18n.ts'
  10. import { QueryHandler } from '#shared/server/apollo/handler/index.ts'
  11. import { useApplicationStore } from '#shared/stores/application.ts'
  12. import log from '#shared/utils/log.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. const scope = effectScope()
  42. scope.run(() => {
  43. translationsQuery = new QueryHandler(
  44. useTranslationsLazyQuery({} as TranslationsQueryVariables),
  45. {
  46. // Don't show an error while app is loading as this would cause startup failure.
  47. errorShowNotification: useApplicationStore().loaded,
  48. },
  49. )
  50. })
  51. return translationsQuery
  52. }
  53. export const useTranslationsStore = defineStore(
  54. 'translations',
  55. () => {
  56. const cacheKey = ref<string>('CACHE_EMPTY')
  57. const translationData = ref<Record<string, string>>({})
  58. const load = async (locale: string): Promise<void> => {
  59. log.debug('translations.load()', locale)
  60. const cachedData = loadCache(locale)
  61. const translationsQuery = getTranslationsQuery()
  62. const { data: result } = await translationsQuery.query({
  63. variables: {
  64. cacheKey: cachedData.cacheKey,
  65. locale,
  66. },
  67. })
  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. )