@red-hat-developer-hub/backstage-plugin-translations 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/alpha.d.ts +30 -0
  3. package/dist/alpha.esm.js +3 -0
  4. package/dist/alpha.esm.js.map +1 -0
  5. package/dist/apis/I18nextTranslationApi.esm.js.map +1 -1
  6. package/dist/apis/TranslationRef.esm.js.map +1 -1
  7. package/dist/apis/TranslationResource.esm.js.map +1 -1
  8. package/dist/components/ExportTranslationKeys.esm.js +73 -0
  9. package/dist/components/ExportTranslationKeys.esm.js.map +1 -0
  10. package/dist/components/LoadedTranslationsTable.esm.js +6 -4
  11. package/dist/components/LoadedTranslationsTable.esm.js.map +1 -1
  12. package/dist/components/TranslationsPage.esm.js +8 -13
  13. package/dist/components/TranslationsPage.esm.js.map +1 -1
  14. package/dist/hooks/useTranslation.esm.js +8 -0
  15. package/dist/hooks/useTranslation.esm.js.map +1 -0
  16. package/dist/index.d.ts +11 -1
  17. package/dist/index.esm.js +1 -1
  18. package/dist/plugin.esm.js +12 -2
  19. package/dist/plugin.esm.js.map +1 -1
  20. package/dist/translations/de.esm.js +27 -0
  21. package/dist/translations/de.esm.js.map +1 -0
  22. package/dist/translations/es.esm.js +27 -0
  23. package/dist/translations/es.esm.js.map +1 -0
  24. package/dist/translations/fr.esm.js +27 -0
  25. package/dist/translations/fr.esm.js.map +1 -0
  26. package/dist/translations/index.esm.js +15 -0
  27. package/dist/translations/index.esm.js.map +1 -0
  28. package/dist/translations/it.esm.js +27 -0
  29. package/dist/translations/it.esm.js.map +1 -0
  30. package/dist/translations/ref.esm.js +40 -0
  31. package/dist/translations/ref.esm.js.map +1 -0
  32. package/package.json +39 -22
  33. package/dist/components/AppLanguageCard.esm.js +0 -21
  34. package/dist/components/AppLanguageCard.esm.js.map +0 -1
  35. package/dist/components/I18NextCard.esm.js +0 -25
  36. package/dist/components/I18NextCard.esm.js.map +0 -1
  37. package/dist/components/LanguageToggleCard.esm.js +0 -10
  38. package/dist/components/LanguageToggleCard.esm.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-translations
2
2
 
3
+ ## 0.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a8787b0: Create an initial version of translations backend plugin
8
+ Add Download keys translations support in frontend plugin
9
+ Upgraded backstage to 1.42.5
10
+
3
11
  ## 0.0.1
4
12
 
5
13
  ### Patch Changes
@@ -0,0 +1,30 @@
1
+ import * as _backstage_core_plugin_api_alpha from '@backstage/core-plugin-api/alpha';
2
+
3
+ /**
4
+ * @alpha
5
+ */
6
+ declare const translationsPluginTranslationRef: _backstage_core_plugin_api_alpha.TranslationRef<"plugin.translations", {
7
+ readonly "table.title": string;
8
+ readonly "table.headers.refId": string;
9
+ readonly "table.headers.key": string;
10
+ readonly "table.options.pageSize": string;
11
+ readonly "table.options.pageSizeOptions": string;
12
+ readonly "language.displayFormat": string;
13
+ readonly "page.title": string;
14
+ readonly "page.subtitle": string;
15
+ readonly "export.title": string;
16
+ readonly "export.downloadButton": string;
17
+ readonly "export.filename": string;
18
+ readonly "common.loading": string;
19
+ readonly "common.error": string;
20
+ readonly "common.noData": string;
21
+ readonly "common.refresh": string;
22
+ }>;
23
+
24
+ /**
25
+ * @alpha
26
+ *
27
+ */
28
+ declare const translationsPluginTranslations: _backstage_core_plugin_api_alpha.TranslationResource<"plugin.translations">;
29
+
30
+ export { translationsPluginTranslationRef, translationsPluginTranslations };
@@ -0,0 +1,3 @@
1
+ export { translationsPluginTranslations } from './translations/index.esm.js';
2
+ export { translationsPluginTranslationRef } from './translations/ref.esm.js';
3
+ //# sourceMappingURL=alpha.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alpha.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1 +1 @@
1
- {"version":3,"file":"I18nextTranslationApi.esm.js","sources":["../../src/apis/I18nextTranslationApi.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AppLanguageApi,\n TranslationApi,\n TranslationFunction,\n TranslationMessages,\n TranslationRef,\n TranslationResource,\n TranslationSnapshot,\n} from '@backstage/core-plugin-api/alpha';\nimport {\n createInstance as createI18n,\n FormatFunction,\n Interpolator,\n TFunction,\n type i18n as I18n,\n} from 'i18next';\nimport ObservableImpl from 'zen-observable';\n\nimport { Observable } from '@backstage/types';\nimport { createElement, Fragment, ReactNode, isValidElement } from 'react';\nimport {\n InternalTranslationRef,\n toInternalTranslationRef,\n} from './TranslationRef';\nimport {\n InternalTranslationResourceLoader,\n toInternalTranslationResource,\n} from './TranslationResource';\n\nconst DEFAULT_LANGUAGE = 'en';\n\n/** @public */\nexport interface I18nextTranslationApiOptions {\n languageApi: AppLanguageApi;\n resources?: Array<TranslationMessages | TranslationResource>;\n}\n\nfunction removeNulls(\n messages: Record<string, string | null>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(messages).filter(\n (e): e is [string, string] => e[1] !== null,\n ),\n );\n}\n\n/**\n * The built-in i18next backend loading logic doesn't handle on the fly switches\n * of language very well. It gets a bit confused about whether resources are actually\n * loaded or not, so instead we implement our own resource loader.\n */\nclass ResourceLoader {\n /** Loaded resources by loader key */\n #loaded = new Set<string>();\n /** Resource loading promises by loader key */\n #loading = new Map<string, Promise<void>>();\n /** Loaders for each resource language */\n #loaders = new Map<string, InternalTranslationResourceLoader>();\n\n constructor(\n private readonly onLoad: (loaded: {\n language: string;\n namespace: string;\n messages: Record<string, string | null>;\n }) => void,\n ) {}\n\n addTranslationResource(resource: TranslationResource) {\n const internalResource = toInternalTranslationResource(resource);\n for (const entry of internalResource.resources) {\n const key = this.#getLoaderKey(entry.language, internalResource.id);\n\n // First loader to register wins, this means that resources registered in the app\n // have priority over default resource from translation refs\n if (!this.#loaders.has(key)) {\n this.#loaders.set(key, entry.loader);\n }\n }\n }\n\n #getLoaderKey(language: string, namespace: string) {\n return `${language}/${namespace}`;\n }\n\n needsLoading(language: string, namespace: string) {\n const key = this.#getLoaderKey(language, namespace);\n const loader = this.#loaders.get(key);\n if (!loader) {\n return false;\n }\n\n return !this.#loaded.has(key);\n }\n\n async load(language: string, namespace: string): Promise<void> {\n const key = this.#getLoaderKey(language, namespace);\n\n const loader = this.#loaders.get(key);\n if (!loader) {\n return;\n }\n\n if (this.#loaded.has(key)) {\n return;\n }\n\n const loading = this.#loading.get(key);\n if (loading) {\n await loading;\n return;\n }\n\n const load = loader().then(\n result => {\n this.onLoad({ language, namespace, messages: result.messages });\n this.#loaded.add(key);\n },\n error => {\n this.#loaded.add(key); // Do not try to load failed resources again\n throw error;\n },\n );\n this.#loading.set(key, load);\n await load;\n }\n}\n\n/**\n * A helper for implementing JSX interpolation\n */\nexport class JsxInterpolator {\n readonly #setFormatHook: (hook: FormatFunction) => void;\n readonly #marker: string;\n readonly #pattern: RegExp;\n\n static fromI18n(i18n: I18n) {\n const interpolator = i18n.services.interpolator as Interpolator & {\n format: FormatFunction;\n };\n const originalFormat = interpolator.format;\n\n let formatHook: FormatFunction | undefined;\n\n // This is the only way to override the format function of the interpolator\n // without overriding the default formatters. See the behavior here:\n // https://github.com/i18next/i18next/blob/c633121e57e2b6024080142d78027842bf2a6e5e/src/i18next.js#L120-L125\n interpolator.format = (value, format, lng, formatOpts) => {\n if (format) {\n return originalFormat(value, format, lng, formatOpts);\n }\n return formatHook?.(value, format, lng, formatOpts) ?? value;\n };\n\n return new JsxInterpolator(\n // Using a random marker to ensure it can't be misused\n Math.random().toString(36).substring(2, 8),\n hook => {\n formatHook = hook;\n },\n );\n }\n\n private constructor(\n marker: string,\n setFormatHook: (hook: FormatFunction) => void,\n ) {\n this.#setFormatHook = setFormatHook;\n this.#marker = marker;\n this.#pattern = new RegExp(`\\\\$${marker}\\\\(([^)]+)\\\\)`);\n }\n\n wrapT<TMessages extends { [key in string]: string }>(\n originalT: TFunction,\n ): TranslationFunction<TMessages> {\n return ((key, options) => {\n let elementsMap: Map<string, ReactNode> | undefined = undefined;\n\n // There's no way to override the format hook via the translation function\n // options, event though types indicate that it might be possible.\n // Instead, override the format function hook before every invocation and\n // rely on synchronous execution.\n this.#setFormatHook(value => {\n if (isValidElement(value)) {\n if (!elementsMap) {\n elementsMap = new Map();\n }\n const elementKey = elementsMap.size.toString();\n elementsMap.set(elementKey, value);\n\n return `$${this.#marker}(${elementKey})`;\n }\n return value;\n });\n\n // Overriding the return options is not allowed via TranslationFunction,\n // so this will always be a string\n const result = originalT(key, options as any) as unknown as string;\n if (!elementsMap) {\n return result;\n }\n\n const split = result.split(this.#pattern);\n\n return createElement(\n Fragment,\n null,\n ...split\n .map((part, index) => {\n if (index % 2 === 0) {\n return part;\n }\n return elementsMap?.get(part);\n })\n .filter(Boolean),\n );\n }) as TranslationFunction<TMessages>;\n }\n}\n\n/** @public */\nexport class I18nextTranslationApi implements TranslationApi {\n static create(options: I18nextTranslationApiOptions) {\n const { languages } = options.languageApi.getAvailableLanguages();\n\n const i18n = createI18n({\n fallbackLng: DEFAULT_LANGUAGE,\n supportedLngs: languages,\n interpolation: {\n escapeValue: false,\n // Used for the JsxInterpolator format hook\n alwaysFormat: true,\n },\n ns: [],\n defaultNS: false,\n fallbackNS: false,\n\n // Disable resource loading on init, meaning i18n will be ready to use immediately\n initImmediate: false,\n });\n\n i18n.init();\n if (!i18n.isInitialized) {\n throw new Error('i18next was unexpectedly not initialized');\n }\n\n const interpolator = JsxInterpolator.fromI18n(i18n);\n\n const { language: initialLanguage } = options.languageApi.getLanguage();\n if (initialLanguage !== DEFAULT_LANGUAGE) {\n i18n.changeLanguage(initialLanguage);\n }\n\n const loader = new ResourceLoader(loaded => {\n i18n.addResourceBundle(\n loaded.language,\n loaded.namespace,\n removeNulls(loaded.messages),\n false, // do not merge with existing translations\n true, // overwrite translations\n );\n });\n\n const resources = options?.resources || [];\n // Iterate in reverse, giving higher priority to resources registered later\n for (let i = resources.length - 1; i >= 0; i--) {\n const resource = resources[i];\n if (resource.$$type === '@backstage/TranslationResource') {\n loader.addTranslationResource(resource);\n } else if (resource.$$type === '@backstage/TranslationMessages') {\n // Overrides for default messages, created with createTranslationMessages and installed via app\n i18n.addResourceBundle(\n DEFAULT_LANGUAGE,\n resource.id,\n removeNulls(resource.messages),\n true, // merge with existing translations\n false, // do not overwrite translations\n );\n }\n }\n\n const instance = new I18nextTranslationApi(\n i18n,\n loader,\n options.languageApi.getLanguage().language,\n interpolator,\n );\n\n options.languageApi.language$().subscribe(({ language }) => {\n instance.#changeLanguage(language);\n });\n\n return instance;\n }\n\n #i18n: I18n;\n #loader: ResourceLoader;\n #language: string;\n #jsxInterpolator: JsxInterpolator;\n\n /** Keep track of which refs we have registered default resources for */\n #registeredRefs = new Set<string>();\n /** Notify observers when language changes */\n #languageChangeListeners = new Set<() => void>();\n\n private constructor(\n i18n: I18n,\n loader: ResourceLoader,\n language: string,\n jsxInterpolator: JsxInterpolator,\n ) {\n this.#i18n = i18n;\n this.#loader = loader;\n this.#language = language;\n this.#jsxInterpolator = jsxInterpolator;\n }\n\n getI18nInstance(): I18n {\n return this.#i18n;\n }\n\n getTranslation<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): TranslationSnapshot<TMessages> {\n const internalRef = toInternalTranslationRef(translationRef);\n\n this.#registerDefaults(internalRef);\n\n return this.#createSnapshot(internalRef);\n }\n\n translation$<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): Observable<TranslationSnapshot<TMessages>> {\n const internalRef = toInternalTranslationRef(translationRef);\n\n this.#registerDefaults(internalRef);\n\n return new ObservableImpl<TranslationSnapshot<TMessages>>(subscriber => {\n let loadTicket = {}; // To check for stale loads\n\n const loadResource = () => {\n loadTicket = {};\n const ticket = loadTicket;\n this.#loader.load(this.#language, internalRef.id).then(\n () => {\n if (ticket === loadTicket) {\n const snapshot = this.#createSnapshot(internalRef);\n if (snapshot.ready) {\n subscriber.next(snapshot);\n }\n }\n },\n error => {\n if (ticket === loadTicket) {\n subscriber.error(Array.isArray(error) ? error[0] : error);\n }\n },\n );\n };\n\n const onChange = () => {\n const snapshot = this.#createSnapshot(internalRef);\n if (snapshot.ready) {\n subscriber.next(snapshot);\n } else {\n loadResource();\n }\n };\n\n if (this.#loader.needsLoading(this.#language, internalRef.id)) {\n loadResource();\n }\n\n this.#languageChangeListeners.add(onChange);\n return () => {\n this.#languageChangeListeners.delete(onChange);\n };\n });\n }\n\n #changeLanguage(language: string): void {\n if (this.#language !== language) {\n this.#language = language;\n this.#i18n.changeLanguage(language);\n this.#languageChangeListeners.forEach(listener => listener());\n }\n }\n\n #createSnapshot<TMessages extends { [key in string]: string }>(\n internalRef: InternalTranslationRef<string, TMessages>,\n ): TranslationSnapshot<TMessages> {\n if (this.#loader.needsLoading(this.#language, internalRef.id)) {\n return { ready: false };\n }\n\n const unwrappedT = this.#i18n.getFixedT(null, internalRef.id);\n const t = this.#jsxInterpolator.wrapT<TMessages>(unwrappedT);\n\n return {\n ready: true,\n t,\n };\n }\n\n #registerDefaults(internalRef: InternalTranslationRef): void {\n if (this.#registeredRefs.has(internalRef.id)) {\n return;\n }\n this.#registeredRefs.add(internalRef.id);\n\n const defaultMessages = internalRef.getDefaultMessages();\n this.#i18n.addResourceBundle(\n DEFAULT_LANGUAGE,\n internalRef.id,\n defaultMessages,\n true, // merge with existing translations\n false, // do not overwrite translations\n );\n\n const defaultResource = internalRef.getDefaultResource();\n if (defaultResource) {\n this.#loader.addTranslationResource(defaultResource);\n }\n }\n}\n"],"names":["createI18n"],"mappings":";;;;;;AA6CA,MAAM,gBAAA,GAAmB,IAAA;AAQzB,SAAS,YACP,QAAA,EACwB;AACxB,EAAA,OAAO,MAAA,CAAO,WAAA;AAAA,IACZ,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA,CAAE,MAAA;AAAA,MACvB,CAAC,CAAA,KAA6B,CAAA,CAAE,CAAC,CAAA,KAAM;AAAA;AACzC,GACF;AACF;AAOA,MAAM,cAAA,CAAe;AAAA,EAQnB,YACmB,MAAA,EAKjB;AALiB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAKhB;AAAA;AAAA,EAZH,OAAA,uBAAc,GAAA,EAAY;AAAA;AAAA,EAE1B,QAAA,uBAAe,GAAA,EAA2B;AAAA;AAAA,EAE1C,QAAA,uBAAe,GAAA,EAA+C;AAAA,EAU9D,uBAAuB,QAAA,EAA+B;AACpD,IAAA,MAAM,gBAAA,GAAmB,8BAA8B,QAAQ,CAAA;AAC/D,IAAA,KAAA,MAAW,KAAA,IAAS,iBAAiB,SAAA,EAAW;AAC9C,MAAA,MAAM,MAAM,IAAA,CAAK,aAAA,CAAc,KAAA,CAAM,QAAA,EAAU,iBAAiB,EAAE,CAAA;AAIlE,MAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA,EAAG;AAC3B,QAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,GAAA,EAAK,KAAA,CAAM,MAAM,CAAA;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAA,CAAc,UAAkB,SAAA,EAAmB;AACjD,IAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAAA,EACjC;AAAA,EAEA,YAAA,CAAa,UAAkB,SAAA,EAAmB;AAChD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,SAAS,CAAA;AAClD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AACpC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,OAAO,CAAC,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,IAAA,CAAK,QAAA,EAAkB,SAAA,EAAkC;AAC7D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,SAAS,CAAA;AAElD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AACpC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG;AACzB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AACrC,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,MAAM,OAAA;AACN,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,QAAO,CAAE,IAAA;AAAA,MACpB,CAAA,MAAA,KAAU;AACR,QAAA,IAAA,CAAK,OAAO,EAAE,QAAA,EAAU,WAAW,QAAA,EAAU,MAAA,CAAO,UAAU,CAAA;AAC9D,QAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,GAAG,CAAA;AAAA,MACtB,CAAA;AAAA,MACA,CAAA,KAAA,KAAS;AACP,QAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,GAAG,CAAA;AACpB,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,KACF;AACA,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAC3B,IAAA,MAAM,IAAA;AAAA,EACR;AACF;AAKO,MAAM,eAAA,CAAgB;AAAA,EAClB,cAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EAET,OAAO,SAAS,IAAA,EAAY;AAC1B,IAAA,MAAM,YAAA,GAAe,KAAK,QAAA,CAAS,YAAA;AAGnC,IAAA,MAAM,iBAAiB,YAAA,CAAa,MAAA;AAEpC,IAAA,IAAI,UAAA;AAKJ,IAAA,YAAA,CAAa,MAAA,GAAS,CAAC,KAAA,EAAO,MAAA,EAAQ,KAAK,UAAA,KAAe;AACxD,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,OAAO,cAAA,CAAe,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,UAAU,CAAA;AAAA,MACtD;AACA,MAAA,OAAO,UAAA,GAAa,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,UAAU,CAAA,IAAK,KAAA;AAAA,IACzD,CAAA;AAEA,IAAA,OAAO,IAAI,eAAA;AAAA;AAAA,MAET,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAA,CAAU,GAAG,CAAC,CAAA;AAAA,MACzC,CAAA,IAAA,KAAQ;AACN,QAAA,UAAA,GAAa,IAAA;AAAA,MACf;AAAA,KACF;AAAA,EACF;AAAA,EAEQ,WAAA,CACN,QACA,aAAA,EACA;AACA,IAAA,IAAA,CAAK,cAAA,GAAiB,aAAA;AACtB,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,QAAA,GAAW,IAAI,MAAA,CAAO,CAAA,GAAA,EAAM,MAAM,CAAA,aAAA,CAAe,CAAA;AAAA,EACxD;AAAA,EAEA,MACE,SAAA,EACgC;AAChC,IAAA,QAAQ,CAAC,KAAK,OAAA,KAAY;AACxB,MAAA,IAAI,WAAA,GAAkD,MAAA;AAMtD,MAAA,IAAA,CAAK,eAAe,CAAA,KAAA,KAAS;AAC3B,QAAA,IAAI,cAAA,CAAe,KAAK,CAAA,EAAG;AACzB,UAAA,IAAI,CAAC,WAAA,EAAa;AAChB,YAAA,WAAA,uBAAkB,GAAA,EAAI;AAAA,UACxB;AACA,UAAA,MAAM,UAAA,GAAa,WAAA,CAAY,IAAA,CAAK,QAAA,EAAS;AAC7C,UAAA,WAAA,CAAY,GAAA,CAAI,YAAY,KAAK,CAAA;AAEjC,UAAA,OAAO,CAAA,CAAA,EAAI,IAAA,CAAK,OAAO,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,CAAA;AAAA,QACvC;AACA,QAAA,OAAO,KAAA;AAAA,MACT,CAAC,CAAA;AAID,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,GAAA,EAAK,OAAc,CAAA;AAC5C,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AAExC,MAAA,OAAO,aAAA;AAAA,QACL,QAAA;AAAA,QACA,IAAA;AAAA,QACA,GAAG,KAAA,CACA,GAAA,CAAI,CAAC,MAAM,KAAA,KAAU;AACpB,UAAA,IAAI,KAAA,GAAQ,MAAM,CAAA,EAAG;AACnB,YAAA,OAAO,IAAA;AAAA,UACT;AACA,UAAA,OAAO,WAAA,EAAa,IAAI,IAAI,CAAA;AAAA,QAC9B,CAAC,CAAA,CACA,MAAA,CAAO,OAAO;AAAA,OACnB;AAAA,IACF,CAAA;AAAA,EACF;AACF;AAGO,MAAM,qBAAA,CAAgD;AAAA,EAC3D,OAAO,OAAO,OAAA,EAAuC;AACnD,IAAA,MAAM,EAAE,SAAA,EAAU,GAAI,OAAA,CAAQ,YAAY,qBAAA,EAAsB;AAEhE,IAAA,MAAM,OAAOA,cAAA,CAAW;AAAA,MACtB,WAAA,EAAa,gBAAA;AAAA,MACb,aAAA,EAAe,SAAA;AAAA,MACf,aAAA,EAAe;AAAA,QACb,WAAA,EAAa,KAAA;AAAA;AAAA,QAEb,YAAA,EAAc;AAAA,OAChB;AAAA,MACA,IAAI,EAAC;AAAA,MACL,SAAA,EAAW,KAAA;AAAA,MACX,UAAA,EAAY,KAAA;AAAA;AAAA,MAGZ,aAAA,EAAe;AAAA,KAChB,CAAA;AAED,IAAA,IAAA,CAAK,IAAA,EAAK;AACV,IAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACvB,MAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,IAC5D;AAEA,IAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,QAAA,CAAS,IAAI,CAAA;AAElD,IAAA,MAAM,EAAE,QAAA,EAAU,eAAA,EAAgB,GAAI,OAAA,CAAQ,YAAY,WAAA,EAAY;AACtE,IAAA,IAAI,oBAAoB,gBAAA,EAAkB;AACxC,MAAA,IAAA,CAAK,eAAe,eAAe,CAAA;AAAA,IACrC;AAEA,IAAA,MAAM,MAAA,GAAS,IAAI,cAAA,CAAe,CAAA,MAAA,KAAU;AAC1C,MAAA,IAAA,CAAK,iBAAA;AAAA,QACH,MAAA,CAAO,QAAA;AAAA,QACP,MAAA,CAAO,SAAA;AAAA,QACP,WAAA,CAAY,OAAO,QAAQ,CAAA;AAAA,QAC3B,KAAA;AAAA;AAAA,QACA;AAAA;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,OAAA,EAAS,SAAA,IAAa,EAAC;AAEzC,IAAA,KAAA,IAAS,IAAI,SAAA,CAAU,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AAC9C,MAAA,MAAM,QAAA,GAAW,UAAU,CAAC,CAAA;AAC5B,MAAA,IAAI,QAAA,CAAS,WAAW,gCAAA,EAAkC;AACxD,QAAA,MAAA,CAAO,uBAAuB,QAAQ,CAAA;AAAA,MACxC,CAAA,MAAA,IAAW,QAAA,CAAS,MAAA,KAAW,gCAAA,EAAkC;AAE/D,QAAA,IAAA,CAAK,iBAAA;AAAA,UACH,gBAAA;AAAA,UACA,QAAA,CAAS,EAAA;AAAA,UACT,WAAA,CAAY,SAAS,QAAQ,CAAA;AAAA,UAC7B,IAAA;AAAA;AAAA,UACA;AAAA;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,WAAW,IAAI,qBAAA;AAAA,MACnB,IAAA;AAAA,MACA,MAAA;AAAA,MACA,OAAA,CAAQ,WAAA,CAAY,WAAA,EAAY,CAAE,QAAA;AAAA,MAClC;AAAA,KACF;AAEA,IAAA,OAAA,CAAQ,YAAY,SAAA,EAAU,CAAE,UAAU,CAAC,EAAE,UAAS,KAAM;AAC1D,MAAA,QAAA,CAAS,gBAAgB,QAAQ,CAAA;AAAA,IACnC,CAAC,CAAA;AAED,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,gBAAA;AAAA;AAAA,EAGA,eAAA,uBAAsB,GAAA,EAAY;AAAA;AAAA,EAElC,wBAAA,uBAA+B,GAAA,EAAgB;AAAA,EAEvC,WAAA,CACN,IAAA,EACA,MAAA,EACA,QAAA,EACA,eAAA,EACA;AACA,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AACjB,IAAA,IAAA,CAAK,gBAAA,GAAmB,eAAA;AAAA,EAC1B;AAAA,EAEA,eAAA,GAAwB;AACtB,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AAAA,EAEA,eACE,cAAA,EACgC;AAChC,IAAA,MAAM,WAAA,GAAc,yBAAyB,cAAc,CAAA;AAE3D,IAAA,IAAA,CAAK,kBAAkB,WAAW,CAAA;AAElC,IAAA,OAAO,IAAA,CAAK,gBAAgB,WAAW,CAAA;AAAA,EACzC;AAAA,EAEA,aACE,cAAA,EAC4C;AAC5C,IAAA,MAAM,WAAA,GAAc,yBAAyB,cAAc,CAAA;AAE3D,IAAA,IAAA,CAAK,kBAAkB,WAAW,CAAA;AAElC,IAAA,OAAO,IAAI,eAA+C,CAAA,UAAA,KAAc;AACtE,MAAA,IAAI,aAAa,EAAC;AAElB,MAAA,MAAM,eAAe,MAAM;AACzB,QAAA,UAAA,GAAa,EAAC;AACd,QAAA,MAAM,MAAA,GAAS,UAAA;AACf,QAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA,CAAK,SAAA,EAAW,WAAA,CAAY,EAAE,CAAA,CAAE,IAAA;AAAA,UAChD,MAAM;AACJ,YAAA,IAAI,WAAW,UAAA,EAAY;AACzB,cAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,WAAW,CAAA;AACjD,cAAA,IAAI,SAAS,KAAA,EAAO;AAClB,gBAAA,UAAA,CAAW,KAAK,QAAQ,CAAA;AAAA,cAC1B;AAAA,YACF;AAAA,UACF,CAAA;AAAA,UACA,CAAA,KAAA,KAAS;AACP,YAAA,IAAI,WAAW,UAAA,EAAY;AACzB,cAAA,UAAA,CAAW,KAAA,CAAM,MAAM,OAAA,CAAQ,KAAK,IAAI,KAAA,CAAM,CAAC,IAAI,KAAK,CAAA;AAAA,YAC1D;AAAA,UACF;AAAA,SACF;AAAA,MACF,CAAA;AAEA,MAAA,MAAM,WAAW,MAAM;AACrB,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,WAAW,CAAA;AACjD,QAAA,IAAI,SAAS,KAAA,EAAO;AAClB,UAAA,UAAA,CAAW,KAAK,QAAQ,CAAA;AAAA,QAC1B,CAAA,MAAO;AACL,UAAA,YAAA,EAAa;AAAA,QACf;AAAA,MACF,CAAA;AAEA,MAAA,IAAI,KAAK,OAAA,CAAQ,YAAA,CAAa,KAAK,SAAA,EAAW,WAAA,CAAY,EAAE,CAAA,EAAG;AAC7D,QAAA,YAAA,EAAa;AAAA,MACf;AAEA,MAAA,IAAA,CAAK,wBAAA,CAAyB,IAAI,QAAQ,CAAA;AAC1C,MAAA,OAAO,MAAM;AACX,QAAA,IAAA,CAAK,wBAAA,CAAyB,OAAO,QAAQ,CAAA;AAAA,MAC/C,CAAA;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,gBAAgB,QAAA,EAAwB;AACtC,IAAA,IAAI,IAAA,CAAK,cAAc,QAAA,EAAU;AAC/B,MAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AACjB,MAAA,IAAA,CAAK,KAAA,CAAM,eAAe,QAAQ,CAAA;AAClC,MAAA,IAAA,CAAK,wBAAA,CAAyB,OAAA,CAAQ,CAAA,QAAA,KAAY,QAAA,EAAU,CAAA;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,gBACE,WAAA,EACgC;AAChC,IAAA,IAAI,KAAK,OAAA,CAAQ,YAAA,CAAa,KAAK,SAAA,EAAW,WAAA,CAAY,EAAE,CAAA,EAAG;AAC7D,MAAA,OAAO,EAAE,OAAO,KAAA,EAAM;AAAA,IACxB;AAEA,IAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,IAAA,EAAM,YAAY,EAAE,CAAA;AAC5D,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,gBAAA,CAAiB,KAAA,CAAiB,UAAU,CAAA;AAE3D,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,IAAA;AAAA,MACP;AAAA,KACF;AAAA,EACF;AAAA,EAEA,kBAAkB,WAAA,EAA2C;AAC3D,IAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,WAAA,CAAY,EAAE,CAAA,EAAG;AAC5C,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,WAAA,CAAY,EAAE,CAAA;AAEvC,IAAA,MAAM,eAAA,GAAkB,YAAY,kBAAA,EAAmB;AACvD,IAAA,IAAA,CAAK,KAAA,CAAM,iBAAA;AAAA,MACT,gBAAA;AAAA,MACA,WAAA,CAAY,EAAA;AAAA,MACZ,eAAA;AAAA,MACA,IAAA;AAAA;AAAA,MACA;AAAA;AAAA,KACF;AAEA,IAAA,MAAM,eAAA,GAAkB,YAAY,kBAAA,EAAmB;AACvD,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,IAAA,CAAK,OAAA,CAAQ,uBAAuB,eAAe,CAAA;AAAA,IACrD;AAAA,EACF;AACF;;;;"}
1
+ {"version":3,"file":"I18nextTranslationApi.esm.js","sources":["../../src/apis/I18nextTranslationApi.ts"],"sourcesContent":["/*\n * Copyright The Backstage Authors and Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AppLanguageApi,\n TranslationApi,\n TranslationFunction,\n TranslationMessages,\n TranslationRef,\n TranslationResource,\n TranslationSnapshot,\n} from '@backstage/core-plugin-api/alpha';\nimport {\n createInstance as createI18n,\n FormatFunction,\n Interpolator,\n TFunction,\n type i18n as I18n,\n} from 'i18next';\nimport ObservableImpl from 'zen-observable';\n\nimport { Observable } from '@backstage/types';\nimport { createElement, Fragment, ReactNode, isValidElement } from 'react';\nimport {\n InternalTranslationRef,\n toInternalTranslationRef,\n} from './TranslationRef';\nimport {\n InternalTranslationResourceLoader,\n toInternalTranslationResource,\n} from './TranslationResource';\n\nconst DEFAULT_LANGUAGE = 'en';\n\n/** @public */\nexport interface I18nextTranslationApiOptions {\n languageApi: AppLanguageApi;\n resources?: Array<TranslationMessages | TranslationResource>;\n}\n\nfunction removeNulls(\n messages: Record<string, string | null>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(messages).filter(\n (e): e is [string, string] => e[1] !== null,\n ),\n );\n}\n\n/**\n * The built-in i18next backend loading logic doesn't handle on the fly switches\n * of language very well. It gets a bit confused about whether resources are actually\n * loaded or not, so instead we implement our own resource loader.\n */\nclass ResourceLoader {\n /** Loaded resources by loader key */\n #loaded = new Set<string>();\n /** Resource loading promises by loader key */\n #loading = new Map<string, Promise<void>>();\n /** Loaders for each resource language */\n #loaders = new Map<string, InternalTranslationResourceLoader>();\n\n constructor(\n private readonly onLoad: (loaded: {\n language: string;\n namespace: string;\n messages: Record<string, string | null>;\n }) => void,\n ) {}\n\n addTranslationResource(resource: TranslationResource) {\n const internalResource = toInternalTranslationResource(resource);\n for (const entry of internalResource.resources) {\n const key = this.#getLoaderKey(entry.language, internalResource.id);\n\n // First loader to register wins, this means that resources registered in the app\n // have priority over default resource from translation refs\n if (!this.#loaders.has(key)) {\n this.#loaders.set(key, entry.loader);\n }\n }\n }\n\n #getLoaderKey(language: string, namespace: string) {\n return `${language}/${namespace}`;\n }\n\n needsLoading(language: string, namespace: string) {\n const key = this.#getLoaderKey(language, namespace);\n const loader = this.#loaders.get(key);\n if (!loader) {\n return false;\n }\n\n return !this.#loaded.has(key);\n }\n\n async load(language: string, namespace: string): Promise<void> {\n const key = this.#getLoaderKey(language, namespace);\n\n const loader = this.#loaders.get(key);\n if (!loader) {\n return;\n }\n\n if (this.#loaded.has(key)) {\n return;\n }\n\n const loading = this.#loading.get(key);\n if (loading) {\n await loading;\n return;\n }\n\n const load = loader().then(\n result => {\n this.onLoad({ language, namespace, messages: result.messages });\n this.#loaded.add(key);\n },\n error => {\n this.#loaded.add(key); // Do not try to load failed resources again\n throw error;\n },\n );\n this.#loading.set(key, load);\n await load;\n }\n}\n\n/**\n * A helper for implementing JSX interpolation\n */\nexport class JsxInterpolator {\n readonly #setFormatHook: (hook: FormatFunction) => void;\n readonly #marker: string;\n readonly #pattern: RegExp;\n\n static fromI18n(i18n: I18n) {\n const interpolator = i18n.services.interpolator as Interpolator & {\n format: FormatFunction;\n };\n const originalFormat = interpolator.format;\n\n let formatHook: FormatFunction | undefined;\n\n // This is the only way to override the format function of the interpolator\n // without overriding the default formatters. See the behavior here:\n // https://github.com/i18next/i18next/blob/c633121e57e2b6024080142d78027842bf2a6e5e/src/i18next.js#L120-L125\n interpolator.format = (value, format, lng, formatOpts) => {\n if (format) {\n return originalFormat(value, format, lng, formatOpts);\n }\n return formatHook?.(value, format, lng, formatOpts) ?? value;\n };\n\n return new JsxInterpolator(\n // Using a random marker to ensure it can't be misused\n Math.random().toString(36).substring(2, 8),\n hook => {\n formatHook = hook;\n },\n );\n }\n\n private constructor(\n marker: string,\n setFormatHook: (hook: FormatFunction) => void,\n ) {\n this.#setFormatHook = setFormatHook;\n this.#marker = marker;\n this.#pattern = new RegExp(`\\\\$${marker}\\\\(([^)]+)\\\\)`);\n }\n\n wrapT<TMessages extends { [key in string]: string }>(\n originalT: TFunction,\n ): TranslationFunction<TMessages> {\n return ((key, options) => {\n let elementsMap: Map<string, ReactNode> | undefined = undefined;\n\n // There's no way to override the format hook via the translation function\n // options, event though types indicate that it might be possible.\n // Instead, override the format function hook before every invocation and\n // rely on synchronous execution.\n this.#setFormatHook(value => {\n if (isValidElement(value)) {\n if (!elementsMap) {\n elementsMap = new Map();\n }\n const elementKey = elementsMap.size.toString();\n elementsMap.set(elementKey, value);\n\n return `$${this.#marker}(${elementKey})`;\n }\n return value;\n });\n\n // Overriding the return options is not allowed via TranslationFunction,\n // so this will always be a string\n const result = originalT(key, options as any) as unknown as string;\n if (!elementsMap) {\n return result;\n }\n\n const split = result.split(this.#pattern);\n\n return createElement(\n Fragment,\n null,\n ...split\n .map((part, index) => {\n if (index % 2 === 0) {\n return part;\n }\n return elementsMap?.get(part);\n })\n .filter(Boolean),\n );\n }) as TranslationFunction<TMessages>;\n }\n}\n\n/** @public */\nexport class I18nextTranslationApi implements TranslationApi {\n static create(options: I18nextTranslationApiOptions) {\n const { languages } = options.languageApi.getAvailableLanguages();\n\n const i18n = createI18n({\n fallbackLng: DEFAULT_LANGUAGE,\n supportedLngs: languages,\n interpolation: {\n escapeValue: false,\n // Used for the JsxInterpolator format hook\n alwaysFormat: true,\n },\n ns: [],\n defaultNS: false,\n fallbackNS: false,\n\n // Disable resource loading on init, meaning i18n will be ready to use immediately\n initImmediate: false,\n });\n\n i18n.init();\n if (!i18n.isInitialized) {\n throw new Error('i18next was unexpectedly not initialized');\n }\n\n const interpolator = JsxInterpolator.fromI18n(i18n);\n\n const { language: initialLanguage } = options.languageApi.getLanguage();\n if (initialLanguage !== DEFAULT_LANGUAGE) {\n i18n.changeLanguage(initialLanguage);\n }\n\n const loader = new ResourceLoader(loaded => {\n i18n.addResourceBundle(\n loaded.language,\n loaded.namespace,\n removeNulls(loaded.messages),\n false, // do not merge with existing translations\n true, // overwrite translations\n );\n });\n\n const resources = options?.resources || [];\n // Iterate in reverse, giving higher priority to resources registered later\n for (let i = resources.length - 1; i >= 0; i--) {\n const resource = resources[i];\n if (resource.$$type === '@backstage/TranslationResource') {\n loader.addTranslationResource(resource);\n } else if (resource.$$type === '@backstage/TranslationMessages') {\n // Overrides for default messages, created with createTranslationMessages and installed via app\n i18n.addResourceBundle(\n DEFAULT_LANGUAGE,\n resource.id,\n removeNulls(resource.messages),\n true, // merge with existing translations\n false, // do not overwrite translations\n );\n }\n }\n\n const instance = new I18nextTranslationApi(\n i18n,\n loader,\n options.languageApi.getLanguage().language,\n interpolator,\n );\n\n options.languageApi.language$().subscribe(({ language }) => {\n instance.#changeLanguage(language);\n });\n\n return instance;\n }\n\n #i18n: I18n;\n #loader: ResourceLoader;\n #language: string;\n #jsxInterpolator: JsxInterpolator;\n\n /** Keep track of which refs we have registered default resources for */\n #registeredRefs = new Set<string>();\n /** Notify observers when language changes */\n #languageChangeListeners = new Set<() => void>();\n\n private constructor(\n i18n: I18n,\n loader: ResourceLoader,\n language: string,\n jsxInterpolator: JsxInterpolator,\n ) {\n this.#i18n = i18n;\n this.#loader = loader;\n this.#language = language;\n this.#jsxInterpolator = jsxInterpolator;\n }\n\n getI18nInstance(): I18n {\n return this.#i18n;\n }\n\n getTranslation<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): TranslationSnapshot<TMessages> {\n const internalRef = toInternalTranslationRef(translationRef);\n\n this.#registerDefaults(internalRef);\n\n return this.#createSnapshot(internalRef);\n }\n\n translation$<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): Observable<TranslationSnapshot<TMessages>> {\n const internalRef = toInternalTranslationRef(translationRef);\n\n this.#registerDefaults(internalRef);\n\n return new ObservableImpl<TranslationSnapshot<TMessages>>(subscriber => {\n let loadTicket = {}; // To check for stale loads\n\n const loadResource = () => {\n loadTicket = {};\n const ticket = loadTicket;\n this.#loader.load(this.#language, internalRef.id).then(\n () => {\n if (ticket === loadTicket) {\n const snapshot = this.#createSnapshot(internalRef);\n if (snapshot.ready) {\n subscriber.next(snapshot);\n }\n }\n },\n error => {\n if (ticket === loadTicket) {\n subscriber.error(Array.isArray(error) ? error[0] : error);\n }\n },\n );\n };\n\n const onChange = () => {\n const snapshot = this.#createSnapshot(internalRef);\n if (snapshot.ready) {\n subscriber.next(snapshot);\n } else {\n loadResource();\n }\n };\n\n if (this.#loader.needsLoading(this.#language, internalRef.id)) {\n loadResource();\n }\n\n this.#languageChangeListeners.add(onChange);\n return () => {\n this.#languageChangeListeners.delete(onChange);\n };\n });\n }\n\n #changeLanguage(language: string): void {\n if (this.#language !== language) {\n this.#language = language;\n this.#i18n.changeLanguage(language);\n this.#languageChangeListeners.forEach(listener => listener());\n }\n }\n\n #createSnapshot<TMessages extends { [key in string]: string }>(\n internalRef: InternalTranslationRef<string, TMessages>,\n ): TranslationSnapshot<TMessages> {\n if (this.#loader.needsLoading(this.#language, internalRef.id)) {\n return { ready: false };\n }\n\n const unwrappedT = this.#i18n.getFixedT(null, internalRef.id);\n const t = this.#jsxInterpolator.wrapT<TMessages>(unwrappedT);\n\n return {\n ready: true,\n t,\n };\n }\n\n #registerDefaults(internalRef: InternalTranslationRef): void {\n if (this.#registeredRefs.has(internalRef.id)) {\n return;\n }\n this.#registeredRefs.add(internalRef.id);\n\n const defaultMessages = internalRef.getDefaultMessages();\n this.#i18n.addResourceBundle(\n DEFAULT_LANGUAGE,\n internalRef.id,\n defaultMessages,\n true, // merge with existing translations\n false, // do not overwrite translations\n );\n\n const defaultResource = internalRef.getDefaultResource();\n if (defaultResource) {\n this.#loader.addTranslationResource(defaultResource);\n }\n }\n}\n"],"names":["createI18n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TranslationRef.esm.js","sources":["../../src/apis/TranslationRef.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n TranslationRef,\n TranslationResource,\n} from '@backstage/core-plugin-api/alpha';\n\n/** @internal */\ntype AnyMessages = { [key in string]: string };\n\n/** @internal */\nexport interface InternalTranslationRef<\n TId extends string = string,\n TMessages extends { [key in string]: string } = { [key in string]: string },\n> extends TranslationRef<TId, TMessages> {\n version: 'v1';\n\n getDefaultMessages(): AnyMessages;\n\n getDefaultResource(): TranslationResource | undefined;\n}\n\n/** @internal */\nexport function toInternalTranslationRef<\n TId extends string,\n TMessages extends AnyMessages,\n>(ref: TranslationRef<TId, TMessages>): InternalTranslationRef<TId, TMessages> {\n const r = ref as InternalTranslationRef<TId, TMessages>;\n if (r.$$type !== '@backstage/TranslationRef') {\n throw new Error(`Invalid translation ref, bad type '${r.$$type}'`);\n }\n if (r.version !== 'v1') {\n throw new Error(`Invalid translation ref, bad version '${r.version}'`);\n }\n return r;\n}\n"],"names":[],"mappings":"AAoCO,SAAS,yBAGd,GAAA,EAA6E;AAC7E,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,IAAI,CAAA,CAAE,WAAW,2BAAA,EAA6B;AAC5C,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,CAAA,CAAE,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EACnE;AACA,EAAA,IAAI,CAAA,CAAE,YAAY,IAAA,EAAM;AACtB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sCAAA,EAAyC,CAAA,CAAE,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,CAAA;AACT;;;;"}
1
+ {"version":3,"file":"TranslationRef.esm.js","sources":["../../src/apis/TranslationRef.ts"],"sourcesContent":["/*\n * Copyright The Backstage Authors and Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n TranslationRef,\n TranslationResource,\n} from '@backstage/core-plugin-api/alpha';\n\n/** @internal */\ntype AnyMessages = { [key in string]: string };\n\n/** @internal */\nexport interface InternalTranslationRef<\n TId extends string = string,\n TMessages extends { [key in string]: string } = { [key in string]: string },\n> extends TranslationRef<TId, TMessages> {\n version: 'v1';\n\n getDefaultMessages(): AnyMessages;\n\n getDefaultResource(): TranslationResource | undefined;\n}\n\n/** @internal */\nexport function toInternalTranslationRef<\n TId extends string,\n TMessages extends AnyMessages,\n>(ref: TranslationRef<TId, TMessages>): InternalTranslationRef<TId, TMessages> {\n const r = ref as InternalTranslationRef<TId, TMessages>;\n if (r.$$type !== '@backstage/TranslationRef') {\n throw new Error(`Invalid translation ref, bad type '${r.$$type}'`);\n }\n if (r.version !== 'v1') {\n throw new Error(`Invalid translation ref, bad version '${r.version}'`);\n }\n return r;\n}\n"],"names":[],"mappings":"AAoCO,SAAS,yBAGd,GAAA,EAA6E;AAC7E,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,IAAI,CAAA,CAAE,WAAW,2BAAA,EAA6B;AAC5C,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,CAAA,CAAE,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EACnE;AACA,EAAA,IAAI,CAAA,CAAE,YAAY,IAAA,EAAM;AACtB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sCAAA,EAAyC,CAAA,CAAE,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,CAAA;AACT;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"TranslationResource.esm.js","sources":["../../src/apis/TranslationResource.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { TranslationResource } from '@backstage/core-plugin-api/alpha';\n\n/** @internal */\nexport type InternalTranslationResourceLoader = () => Promise<{\n messages: { [key in string]: string | null };\n}>;\n\n/** @internal */\nexport interface InternalTranslationResource<TId extends string = string>\n extends TranslationResource<TId> {\n version: 'v1';\n resources: Array<{\n language: string;\n loader: InternalTranslationResourceLoader;\n }>;\n}\n\n/** @internal */\nexport function toInternalTranslationResource<TId extends string>(\n resource: TranslationResource<TId>,\n): InternalTranslationResource<TId> {\n const r = resource as InternalTranslationResource<TId>;\n if (r.$$type !== '@backstage/TranslationResource') {\n throw new Error(`Invalid translation resource, bad type '${r.$$type}'`);\n }\n if (r.version !== 'v1') {\n throw new Error(`Invalid translation resource, bad version '${r.version}'`);\n }\n\n return r;\n}\n"],"names":[],"mappings":"AAiCO,SAAS,8BACd,QAAA,EACkC;AAClC,EAAA,MAAM,CAAA,GAAI,QAAA;AACV,EAAA,IAAI,CAAA,CAAE,WAAW,gCAAA,EAAkC;AACjD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wCAAA,EAA2C,CAAA,CAAE,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EACxE;AACA,EAAA,IAAI,CAAA,CAAE,YAAY,IAAA,EAAM;AACtB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,CAAA,CAAE,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EAC5E;AAEA,EAAA,OAAO,CAAA;AACT;;;;"}
1
+ {"version":3,"file":"TranslationResource.esm.js","sources":["../../src/apis/TranslationResource.ts"],"sourcesContent":["/*\n * Copyright The Backstage Authors and Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { TranslationResource } from '@backstage/core-plugin-api/alpha';\n\n/** @internal */\nexport type InternalTranslationResourceLoader = () => Promise<{\n messages: { [key in string]: string | null };\n}>;\n\n/** @internal */\nexport interface InternalTranslationResource<TId extends string = string>\n extends TranslationResource<TId> {\n version: 'v1';\n resources: Array<{\n language: string;\n loader: InternalTranslationResourceLoader;\n }>;\n}\n\n/** @internal */\nexport function toInternalTranslationResource<TId extends string>(\n resource: TranslationResource<TId>,\n): InternalTranslationResource<TId> {\n const r = resource as InternalTranslationResource<TId>;\n if (r.$$type !== '@backstage/TranslationResource') {\n throw new Error(`Invalid translation resource, bad type '${r.$$type}'`);\n }\n if (r.version !== 'v1') {\n throw new Error(`Invalid translation resource, bad version '${r.version}'`);\n }\n\n return r;\n}\n"],"names":[],"mappings":"AAiCO,SAAS,8BACd,QAAA,EACkC;AAClC,EAAA,MAAM,CAAA,GAAI,QAAA;AACV,EAAA,IAAI,CAAA,CAAE,WAAW,gCAAA,EAAkC;AACjD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wCAAA,EAA2C,CAAA,CAAE,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EACxE;AACA,EAAA,IAAI,CAAA,CAAE,YAAY,IAAA,EAAM;AACtB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,CAAA,CAAE,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EAC5E;AAEA,EAAA,OAAO,CAAA;AACT;;;;"}
@@ -0,0 +1,73 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { InfoCard } from '@backstage/core-components';
3
+ import Button from '@mui/material/Button';
4
+ import { useState } from 'react';
5
+ import FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';
6
+ import { useTranslation } from '../hooks/useTranslation.esm.js';
7
+
8
+ const ExportTranslationKeys = ({
9
+ resources
10
+ }) => {
11
+ const { t } = useTranslation();
12
+ const [isLoading, setIsLoading] = useState(false);
13
+ function downloadTranslations(translations) {
14
+ return new Promise((resolve) => {
15
+ const now = /* @__PURE__ */ new Date();
16
+ const day = String(now.getDate()).padStart(2, "0");
17
+ const month = String(now.getMonth() + 1).padStart(2, "0");
18
+ const year = String(now.getFullYear()).slice(-2);
19
+ const hours = String(now.getHours()).padStart(2, "0");
20
+ const minutes = String(now.getMinutes()).padStart(2, "0");
21
+ const seconds = String(now.getSeconds()).padStart(2, "0");
22
+ const milliseconds = String(now.getMilliseconds()).padStart(3, "0");
23
+ const timestamp = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}-${milliseconds}`;
24
+ const blob = new Blob(
25
+ [JSON.stringify(translations, null, 2)],
26
+ // pretty print with 2 spaces
27
+ { type: "application/json" }
28
+ );
29
+ const url = URL.createObjectURL(blob);
30
+ const link = document.createElement("a");
31
+ link.href = url;
32
+ link.download = t("export.filename", { timestamp });
33
+ link.click();
34
+ setTimeout(() => {
35
+ URL.revokeObjectURL(url);
36
+ resolve();
37
+ }, 100);
38
+ });
39
+ }
40
+ return /* @__PURE__ */ jsx(InfoCard, { title: t("export.title"), children: /* @__PURE__ */ jsx(
41
+ Button,
42
+ {
43
+ variant: "text",
44
+ startIcon: /* @__PURE__ */ jsx(FileDownloadOutlinedIcon, {}),
45
+ disabled: isLoading,
46
+ onClick: async () => {
47
+ if (isLoading) return;
48
+ setIsLoading(true);
49
+ try {
50
+ const finalJson = {};
51
+ resources.forEach((resource) => {
52
+ finalJson[resource.id] = {
53
+ en: resource?.getDefaultMessages()
54
+ };
55
+ });
56
+ await downloadTranslations(finalJson);
57
+ } finally {
58
+ setIsLoading(false);
59
+ }
60
+ },
61
+ sx: {
62
+ fontSize: "1rem !important",
63
+ "&:hover": {
64
+ backgroundColor: "transparent !important"
65
+ }
66
+ },
67
+ children: t("export.downloadButton")
68
+ }
69
+ ) });
70
+ };
71
+
72
+ export { ExportTranslationKeys };
73
+ //# sourceMappingURL=ExportTranslationKeys.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExportTranslationKeys.esm.js","sources":["../../src/components/ExportTranslationKeys.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InfoCard } from '@backstage/core-components';\n\nimport Button from '@mui/material/Button';\nimport { useState } from 'react';\n\nimport FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';\nimport { TranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { useTranslation } from '../hooks/useTranslation';\n\n/**\n * @public\n * @param resources - The resources to export\n * @returns The exported translations\n * @example\n * <ExportTranslationKeys resources={resources} />\n */\nexport const ExportTranslationKeys = ({\n resources,\n}: {\n resources: TranslationRef[];\n}) => {\n const { t } = useTranslation();\n const [isLoading, setIsLoading] = useState(false);\n\n function downloadTranslations(\n translations: Record<string, any>,\n ): Promise<void> {\n return new Promise(resolve => {\n const now = new Date();\n const day = String(now.getDate()).padStart(2, '0');\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const year = String(now.getFullYear()).slice(-2);\n const hours = String(now.getHours()).padStart(2, '0');\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const seconds = String(now.getSeconds()).padStart(2, '0');\n const milliseconds = String(now.getMilliseconds()).padStart(3, '0');\n const timestamp = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}-${milliseconds}`;\n\n const blob = new Blob(\n [JSON.stringify(translations, null, 2)], // pretty print with 2 spaces\n { type: 'application/json' },\n );\n\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = t('export.filename', { timestamp } as any);\n link.click();\n\n // Clean up after a short delay to ensure download starts\n setTimeout(() => {\n URL.revokeObjectURL(url);\n resolve();\n }, 100);\n });\n }\n\n return (\n <InfoCard title={t('export.title')}>\n <Button\n variant=\"text\"\n startIcon={<FileDownloadOutlinedIcon />}\n disabled={isLoading}\n onClick={async () => {\n if (isLoading) return;\n\n setIsLoading(true);\n try {\n const finalJson: any = {};\n resources.forEach(resource => {\n finalJson[resource.id] = {\n en: (resource as any)?.getDefaultMessages(),\n };\n });\n await downloadTranslations(finalJson);\n } finally {\n setIsLoading(false);\n }\n }}\n sx={{\n fontSize: '1rem !important',\n '&:hover': {\n backgroundColor: 'transparent !important',\n },\n }}\n >\n {t('export.downloadButton')}\n </Button>\n </InfoCard>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { Table } from '@backstage/core-components';
3
3
  import { useApi } from '@backstage/core-plugin-api';
4
4
  import { appLanguageApiRef, translationApiRef } from '@backstage/core-plugin-api/alpha';
5
5
  import { useMemo } from 'react';
6
+ import { useTranslation } from '../hooks/useTranslation.esm.js';
6
7
 
7
8
  const getLanguageDisplayName = (language) => {
8
9
  try {
@@ -25,6 +26,7 @@ const getTranslation = (resources, lang, ref, key) => {
25
26
  return translation;
26
27
  };
27
28
  const LoadedTranslationsTable = () => {
29
+ const { t } = useTranslation();
28
30
  const appLanguageApi = useApi(appLanguageApiRef);
29
31
  const translationApi = useApi(translationApiRef);
30
32
  const i18n = translationApi.getI18nInstance();
@@ -38,14 +40,14 @@ const LoadedTranslationsTable = () => {
38
40
  );
39
41
  const columns = useMemo(
40
42
  () => [
41
- { title: "Ref ID", field: "ref" },
42
- { title: "Key", field: "key" },
43
+ { title: t("table.headers.refId"), field: "ref" },
44
+ { title: t("table.headers.key"), field: "key" },
43
45
  ...showLanguages.map((lang) => ({
44
46
  title: getLanguageDisplayName(lang),
45
47
  field: lang
46
48
  }))
47
49
  ],
48
- [showLanguages]
50
+ [showLanguages, t]
49
51
  );
50
52
  const data = useMemo(() => {
51
53
  const rows = [];
@@ -105,7 +107,7 @@ const LoadedTranslationsTable = () => {
105
107
  return /* @__PURE__ */ jsx(
106
108
  Table,
107
109
  {
108
- title: `Loaded translations (${data.length})`,
110
+ title: t("table.title", { count: data.length.toString() }),
109
111
  columns,
110
112
  data,
111
113
  options: {
@@ -1 +1 @@
1
- {"version":3,"file":"LoadedTranslationsTable.esm.js","sources":["../../src/components/LoadedTranslationsTable.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Table } from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n appLanguageApiRef,\n translationApiRef,\n} from '@backstage/core-plugin-api/alpha';\n\nimport type { i18n as I18n, Resource } from 'i18next';\nimport { useMemo } from 'react';\n\ninterface Row {\n ref: string;\n key: string;\n [lang: string]: string | undefined;\n}\n\n// From https://github.com/backstage/backstage/blob/89f191b72c154e3f0bde70548a7bccbb23af8de0/plugins/user-settings/src/components/General/UserSettingsLanguageToggle.tsx#L68\nconst getLanguageDisplayName = (language: string) => {\n try {\n const names = new Intl.DisplayNames([language], {\n type: 'language',\n });\n const languageDisplayName = names.of(language);\n if (languageDisplayName) {\n return `${languageDisplayName} (${language})`;\n }\n return language;\n } catch (err) {\n return language;\n }\n};\n\nconst getTranslation = (\n resources: Resource,\n lang: string,\n ref: string,\n key: string,\n) => {\n const resourceLang = resources[lang];\n const resourceKey = resourceLang?.[ref];\n const translation =\n typeof resourceKey === 'object' ? resourceKey?.[key] : undefined;\n return translation;\n};\n\nexport const LoadedTranslationsTable = () => {\n const appLanguageApi = useApi(appLanguageApiRef);\n const translationApi = useApi(translationApiRef);\n const i18n: I18n = (translationApi as any).getI18nInstance();\n\n const resources = i18n.store.data;\n\n // FIXME: the available languages are not yet loaded...\n const showLanguages = useMemo(\n () => [\n 'en',\n ...appLanguageApi\n .getAvailableLanguages()\n .languages.filter(lang => lang !== 'en'),\n ],\n [appLanguageApi],\n );\n\n const columns = useMemo(\n () => [\n { title: 'Ref ID', field: 'ref' },\n { title: 'Key', field: 'key' },\n ...showLanguages.map(lang => ({\n title: getLanguageDisplayName(lang),\n field: lang,\n })),\n ],\n [showLanguages],\n );\n\n const data = useMemo(() => {\n const rows: Row[] = [];\n\n // Iterate first over primary language english\n if (resources.en) {\n for (const ref of Object.keys(resources.en)) {\n for (const key of Object.keys(resources.en[ref])) {\n rows.push(\n showLanguages.reduce(\n (row, lang) => {\n row[lang] = getTranslation(resources, lang, ref, key);\n return row;\n },\n {\n ref,\n key,\n } as Row,\n ),\n );\n }\n }\n }\n\n // Check if other languages have additional keys\n for (const otherLang of Object.keys(resources)) {\n if (otherLang === 'en') {\n continue;\n }\n for (const ref of Object.keys(resources[otherLang])) {\n for (const key of Object.keys(resources[otherLang][ref])) {\n // if the key exists in english, then it was already added\n const resourceLang = resources.en;\n const resourceKey = resourceLang?.[ref];\n if (typeof resourceKey === 'object' && resourceKey?.[key]) {\n continue;\n }\n // Check if we already have a row for this ref/key combination\n // from another language. If yes, then we can skip this as well.\n const existingRow = rows.find(r => r.ref === ref && r.key === key);\n if (existingRow) {\n showLanguages.forEach(lang => {\n existingRow[lang] = getTranslation(resources, lang, ref, key);\n });\n continue;\n }\n // Otherwise add a new row and include all languages\n rows.push(\n showLanguages.reduce(\n (row, lang) => {\n row[lang] = getTranslation(resources, lang, ref, key);\n return row;\n },\n {\n ref,\n key,\n } as Row,\n ),\n );\n }\n }\n }\n\n return rows;\n }, [resources, showLanguages]);\n\n return (\n <Table\n title={`Loaded translations (${data.length})`}\n columns={columns}\n data={data}\n options={{\n pageSize: 10,\n pageSizeOptions: [10, 25, 100],\n }}\n />\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LoadedTranslationsTable.esm.js","sources":["../../src/components/LoadedTranslationsTable.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Table } from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n appLanguageApiRef,\n translationApiRef,\n} from '@backstage/core-plugin-api/alpha';\n\nimport type { i18n as I18n, Resource } from 'i18next';\nimport { useMemo } from 'react';\nimport { useTranslation } from '../hooks/useTranslation';\n\ninterface Row {\n ref: string;\n key: string;\n [lang: string]: string | undefined;\n}\n\n// From https://github.com/backstage/backstage/blob/89f191b72c154e3f0bde70548a7bccbb23af8de0/plugins/user-settings/src/components/General/UserSettingsLanguageToggle.tsx#L68\nconst getLanguageDisplayName = (language: string) => {\n try {\n const names = new Intl.DisplayNames([language], {\n type: 'language',\n });\n const languageDisplayName = names.of(language);\n if (languageDisplayName) {\n return `${languageDisplayName} (${language})`;\n }\n return language;\n } catch (err) {\n return language;\n }\n};\n\nconst getTranslation = (\n resources: Resource,\n lang: string,\n ref: string,\n key: string,\n) => {\n const resourceLang = resources[lang];\n const resourceKey = resourceLang?.[ref];\n const translation =\n typeof resourceKey === 'object' ? resourceKey?.[key] : undefined;\n return translation;\n};\n\nexport const LoadedTranslationsTable = () => {\n const { t } = useTranslation();\n const appLanguageApi = useApi(appLanguageApiRef);\n const translationApi = useApi(translationApiRef);\n const i18n: I18n = (translationApi as any).getI18nInstance();\n\n const resources = i18n.store.data;\n\n // FIXME: the available languages are not yet loaded...\n const showLanguages = useMemo(\n () => [\n 'en',\n ...appLanguageApi\n .getAvailableLanguages()\n .languages.filter(lang => lang !== 'en'),\n ],\n [appLanguageApi],\n );\n\n const columns = useMemo(\n () => [\n { title: t('table.headers.refId'), field: 'ref' },\n { title: t('table.headers.key'), field: 'key' },\n ...showLanguages.map(lang => ({\n title: getLanguageDisplayName(lang),\n field: lang,\n })),\n ],\n [showLanguages, t],\n );\n\n const data = useMemo(() => {\n const rows: Row[] = [];\n\n // Iterate first over primary language english\n if (resources.en) {\n for (const ref of Object.keys(resources.en)) {\n for (const key of Object.keys(resources.en[ref])) {\n rows.push(\n showLanguages.reduce(\n (row, lang) => {\n row[lang] = getTranslation(resources, lang, ref, key);\n return row;\n },\n {\n ref,\n key,\n } as Row,\n ),\n );\n }\n }\n }\n\n // Check if other languages have additional keys\n for (const otherLang of Object.keys(resources)) {\n if (otherLang === 'en') {\n continue;\n }\n for (const ref of Object.keys(resources[otherLang])) {\n for (const key of Object.keys(resources[otherLang][ref])) {\n // if the key exists in english, then it was already added\n const resourceLang = resources.en;\n const resourceKey = resourceLang?.[ref];\n if (typeof resourceKey === 'object' && resourceKey?.[key]) {\n continue;\n }\n // Check if we already have a row for this ref/key combination\n // from another language. If yes, then we can skip this as well.\n const existingRow = rows.find(r => r.ref === ref && r.key === key);\n if (existingRow) {\n showLanguages.forEach(lang => {\n existingRow[lang] = getTranslation(resources, lang, ref, key);\n });\n continue;\n }\n // Otherwise add a new row and include all languages\n rows.push(\n showLanguages.reduce(\n (row, lang) => {\n row[lang] = getTranslation(resources, lang, ref, key);\n return row;\n },\n {\n ref,\n key,\n } as Row,\n ),\n );\n }\n }\n }\n\n return rows;\n }, [resources, showLanguages]);\n\n return (\n <Table\n title={t('table.title' as any, { count: data.length.toString() })}\n columns={columns}\n data={data}\n options={{\n pageSize: 10,\n pageSizeOptions: [10, 25, 100],\n }}\n />\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,24 +1,19 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { Page, Header, Content } from '@backstage/core-components';
3
- import { LanguageToggleCard } from './LanguageToggleCard.esm.js';
4
3
  import { LoadedTranslationsTable } from './LoadedTranslationsTable.esm.js';
5
- import { AppLanguageCard } from './AppLanguageCard.esm.js';
6
- import { I18NextCard } from './I18NextCard.esm.js';
4
+ import { useTranslation } from '../hooks/useTranslation.esm.js';
5
+ import { ExportTranslationKeys } from './ExportTranslationKeys.esm.js';
6
+ import '../translations/index.esm.js';
7
+ import { translationsPluginTranslationRef } from '../translations/ref.esm.js';
7
8
 
8
9
  const TranslationsPage = () => {
10
+ const { t } = useTranslation();
9
11
  return /* @__PURE__ */ jsxs(Page, { themeId: "tool", children: [
10
- /* @__PURE__ */ jsx(Header, { title: "Translations" }),
12
+ /* @__PURE__ */ jsx(Header, { title: t("page.title") }),
11
13
  /* @__PURE__ */ jsxs(Content, { children: [
12
- /* @__PURE__ */ jsx(LanguageToggleCard, {}),
14
+ /* @__PURE__ */ jsx(ExportTranslationKeys, { resources: [translationsPluginTranslationRef] }),
13
15
  /* @__PURE__ */ jsx("br", {}),
14
- /* @__PURE__ */ jsx("br", {}),
15
- /* @__PURE__ */ jsx(LoadedTranslationsTable, {}),
16
- /* @__PURE__ */ jsx("br", {}),
17
- /* @__PURE__ */ jsx("br", {}),
18
- /* @__PURE__ */ jsx(AppLanguageCard, {}),
19
- /* @__PURE__ */ jsx("br", {}),
20
- /* @__PURE__ */ jsx("br", {}),
21
- /* @__PURE__ */ jsx(I18NextCard, {})
16
+ /* @__PURE__ */ jsx(LoadedTranslationsTable, {})
22
17
  ] })
23
18
  ] });
24
19
  };
@@ -1 +1 @@
1
- {"version":3,"file":"TranslationsPage.esm.js","sources":["../../src/components/TranslationsPage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Page, Header, Content } from '@backstage/core-components';\n\nimport { LanguageToggleCard } from './LanguageToggleCard';\nimport { LoadedTranslationsTable } from './LoadedTranslationsTable';\nimport { AppLanguageCard } from './AppLanguageCard';\nimport { I18NextCard } from './I18NextCard';\n\nexport const TranslationsPage = () => {\n return (\n <Page themeId=\"tool\">\n <Header title=\"Translations\" />\n <Content>\n <LanguageToggleCard />\n <br />\n <br />\n <LoadedTranslationsTable />\n <br />\n <br />\n <AppLanguageCard />\n <br />\n <br />\n <I18NextCard />\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAsBO,MAAM,mBAAmB,MAAM;AACpC,EAAA,uBACE,IAAA,CAAC,IAAA,EAAA,EAAK,OAAA,EAAQ,MAAA,EACZ,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,OAAM,cAAA,EAAe,CAAA;AAAA,yBAC5B,OAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,kBAAA,EAAA,EAAmB,CAAA;AAAA,0BACnB,IAAA,EAAA,EAAG,CAAA;AAAA,0BACH,IAAA,EAAA,EAAG,CAAA;AAAA,0BACH,uBAAA,EAAA,EAAwB,CAAA;AAAA,0BACxB,IAAA,EAAA,EAAG,CAAA;AAAA,0BACH,IAAA,EAAA,EAAG,CAAA;AAAA,0BACH,eAAA,EAAA,EAAgB,CAAA;AAAA,0BAChB,IAAA,EAAA,EAAG,CAAA;AAAA,0BACH,IAAA,EAAA,EAAG,CAAA;AAAA,0BACH,WAAA,EAAA,EAAY;AAAA,KAAA,EACf;AAAA,GAAA,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"TranslationsPage.esm.js","sources":["../../src/components/TranslationsPage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Page, Header, Content } from '@backstage/core-components';\n\nimport { LoadedTranslationsTable } from './LoadedTranslationsTable';\nimport { useTranslation } from '../hooks/useTranslation';\nimport { ExportTranslationKeys } from './ExportTranslationKeys';\nimport { translationsPluginTranslationRef } from '../translations';\n\nexport const TranslationsPage = () => {\n const { t } = useTranslation();\n\n return (\n <Page themeId=\"tool\">\n <Header title={t('page.title')} />\n <Content>\n <ExportTranslationKeys resources={[translationsPluginTranslationRef]} />\n <br />\n <LoadedTranslationsTable />\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAsBO,MAAM,mBAAmB,MAAM;AACpC,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,cAAA,EAAe;AAE7B,EAAA,uBACE,IAAA,CAAC,IAAA,EAAA,EAAK,OAAA,EAAQ,MAAA,EACZ,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,KAAA,EAAO,CAAA,CAAE,YAAY,CAAA,EAAG,CAAA;AAAA,yBAC/B,OAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,qBAAA,EAAA,EAAsB,SAAA,EAAW,CAAC,gCAAgC,CAAA,EAAG,CAAA;AAAA,0BACrE,IAAA,EAAA,EAAG,CAAA;AAAA,0BACH,uBAAA,EAAA,EAAwB;AAAA,KAAA,EAC3B;AAAA,GAAA,EACF,CAAA;AAEJ;;;;"}
@@ -0,0 +1,8 @@
1
+ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
2
+ import '../translations/index.esm.js';
3
+ import { translationsPluginTranslationRef } from '../translations/ref.esm.js';
4
+
5
+ const useTranslation = () => useTranslationRef(translationsPluginTranslationRef);
6
+
7
+ export { useTranslation };
8
+ //# sourceMappingURL=useTranslation.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTranslation.esm.js","sources":["../../src/hooks/useTranslation.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n useTranslationRef,\n TranslationFunction,\n} from '@backstage/core-plugin-api/alpha';\nimport { translationsPluginTranslationRef } from '../translations';\n\nexport const useTranslation = (): {\n t: TranslationFunction<typeof translationsPluginTranslationRef.T>;\n} => useTranslationRef(translationsPluginTranslationRef);\n"],"names":[],"mappings":";;;;AAqBO,MAAM,cAAA,GAAiB,MAEzB,iBAAA,CAAkB,gCAAgC;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _backstage_core_plugin_api_alpha from '@backstage/core-plugin-api/alpha';
1
2
  import { TranslationApi, AppLanguageApi, TranslationMessages, TranslationResource, TranslationRef, TranslationSnapshot } from '@backstage/core-plugin-api/alpha';
2
3
  import { i18n } from 'i18next';
3
4
  import { Observable } from '@backstage/types';
@@ -33,6 +34,15 @@ declare const translationsPlugin: _backstage_core_plugin_api.BackstagePlugin<{
33
34
  * @public
34
35
  */
35
36
  declare const TranslationsPage: () => react_jsx_runtime.JSX.Element;
37
+ /**
38
+ * Export Translation Keys
39
+ * @public
40
+ */
41
+ declare const ExportTranslationKeys: ({ resources, }: {
42
+ resources: _backstage_core_plugin_api_alpha.TranslationRef<string, {
43
+ [x: string]: string;
44
+ }>[];
45
+ }) => react_jsx_runtime.JSX.Element;
36
46
 
37
- export { I18nextTranslationApi, TranslationsPage, translationsPlugin };
47
+ export { ExportTranslationKeys, I18nextTranslationApi, TranslationsPage, translationsPlugin };
38
48
  export type { I18nextTranslationApiOptions };
package/dist/index.esm.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { I18nextTranslationApi } from './apis/I18nextTranslationApi.esm.js';
2
- export { TranslationsPage, translationsPlugin } from './plugin.esm.js';
2
+ export { ExportTranslationKeys, TranslationsPage, translationsPlugin } from './plugin.esm.js';
3
3
  //# sourceMappingURL=index.esm.js.map
@@ -1,4 +1,4 @@
1
- import { createPlugin, createRoutableExtension } from '@backstage/core-plugin-api';
1
+ import { createPlugin, createRoutableExtension, createComponentExtension } from '@backstage/core-plugin-api';
2
2
  import { rootRouteRef } from './routes.esm.js';
3
3
 
4
4
  const translationsPlugin = createPlugin({
@@ -14,6 +14,16 @@ const TranslationsPage = translationsPlugin.provide(
14
14
  mountPoint: rootRouteRef
15
15
  })
16
16
  );
17
+ const ExportTranslationKeys = translationsPlugin.provide(
18
+ createComponentExtension({
19
+ name: "ExportTranslationKeys",
20
+ component: {
21
+ lazy: () => import('./components/ExportTranslationKeys.esm.js').then(
22
+ (m) => m.ExportTranslationKeys
23
+ )
24
+ }
25
+ })
26
+ );
17
27
 
18
- export { TranslationsPage, translationsPlugin };
28
+ export { ExportTranslationKeys, TranslationsPage, translationsPlugin };
19
29
  //# sourceMappingURL=plugin.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n createPlugin,\n createRoutableExtension,\n} from '@backstage/core-plugin-api';\n\nimport { rootRouteRef } from './routes';\n\n/**\n * @public\n */\nexport const translationsPlugin = createPlugin({\n id: 'translations',\n routes: {\n root: rootRouteRef,\n },\n});\n\n/**\n * @public\n */\nexport const TranslationsPage = translationsPlugin.provide(\n createRoutableExtension({\n name: 'TranslationsPage',\n component: () =>\n import('./components/TranslationsPage').then(m => m.TranslationsPage),\n mountPoint: rootRouteRef,\n }),\n);\n"],"names":[],"mappings":";;;AAyBO,MAAM,qBAAqB,YAAA,CAAa;AAAA,EAC7C,EAAA,EAAI,cAAA;AAAA,EACJ,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA;AAEV,CAAC;AAKM,MAAM,mBAAmB,kBAAA,CAAmB,OAAA;AAAA,EACjD,uBAAA,CAAwB;AAAA,IACtB,IAAA,EAAM,kBAAA;AAAA,IACN,SAAA,EAAW,MACT,OAAO,sCAA+B,EAAE,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,gBAAgB,CAAA;AAAA,IACtE,UAAA,EAAY;AAAA,GACb;AACH;;;;"}
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n createPlugin,\n createRoutableExtension,\n createComponentExtension,\n} from '@backstage/core-plugin-api';\n\nimport { rootRouteRef } from './routes';\n\n/**\n * @public\n */\nexport const translationsPlugin = createPlugin({\n id: 'translations',\n routes: {\n root: rootRouteRef,\n },\n});\n\n/**\n * @public\n */\nexport const TranslationsPage = translationsPlugin.provide(\n createRoutableExtension({\n name: 'TranslationsPage',\n component: () =>\n import('./components/TranslationsPage').then(m => m.TranslationsPage),\n mountPoint: rootRouteRef,\n }),\n);\n\n/**\n * Export Translation Keys\n * @public\n */\nexport const ExportTranslationKeys = translationsPlugin.provide(\n createComponentExtension({\n name: 'ExportTranslationKeys',\n component: {\n lazy: () =>\n import('./components/ExportTranslationKeys').then(\n m => m.ExportTranslationKeys,\n ),\n },\n }),\n);\n"],"names":[],"mappings":";;;AA0BO,MAAM,qBAAqB,YAAA,CAAa;AAAA,EAC7C,EAAA,EAAI,cAAA;AAAA,EACJ,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA;AAEV,CAAC;AAKM,MAAM,mBAAmB,kBAAA,CAAmB,OAAA;AAAA,EACjD,uBAAA,CAAwB;AAAA,IACtB,IAAA,EAAM,kBAAA;AAAA,IACN,SAAA,EAAW,MACT,OAAO,sCAA+B,EAAE,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,gBAAgB,CAAA;AAAA,IACtE,UAAA,EAAY;AAAA,GACb;AACH;AAMO,MAAM,wBAAwB,kBAAA,CAAmB,OAAA;AAAA,EACtD,wBAAA,CAAyB;AAAA,IACvB,IAAA,EAAM,uBAAA;AAAA,IACN,SAAA,EAAW;AAAA,MACT,IAAA,EAAM,MACJ,OAAO,2CAAoC,CAAA,CAAE,IAAA;AAAA,QAC3C,OAAK,CAAA,CAAE;AAAA;AACT;AACJ,GACD;AACH;;;;"}
@@ -0,0 +1,27 @@
1
+ import { createTranslationMessages } from '@backstage/core-plugin-api/alpha';
2
+ import { translationsPluginTranslationRef } from './ref.esm.js';
3
+
4
+ const translationsTranslationDe = createTranslationMessages({
5
+ ref: translationsPluginTranslationRef,
6
+ messages: {
7
+ // CRITICAL: Use flat dot notation, not nested objects
8
+ "page.title": "\xDCbersetzungen",
9
+ "page.subtitle": "Geladene \xDCbersetzungen verwalten und anzeigen",
10
+ "table.title": "Geladene \xDCbersetzungen ({{count}})",
11
+ "table.headers.refId": "Ref-ID",
12
+ "table.headers.key": "Schl\xFCssel",
13
+ "table.options.pageSize": "Elemente pro Seite",
14
+ "table.options.pageSizeOptions": "{{count}} Elemente anzeigen",
15
+ "export.title": "\xDCbersetzungen",
16
+ "export.downloadButton": "Standard-\xDCbersetzungen herunterladen (Englisch)",
17
+ "export.filename": "\xFCbersetzungen-{{timestamp}}.json",
18
+ "common.loading": "Wird geladen...",
19
+ "common.error": "Ein Fehler ist aufgetreten",
20
+ "common.noData": "Keine Daten verf\xFCgbar",
21
+ "common.refresh": "Aktualisieren",
22
+ "language.displayFormat": "{{displayName}} ({{code}})"
23
+ }
24
+ });
25
+
26
+ export { translationsTranslationDe as default };
27
+ //# sourceMappingURL=de.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"de.esm.js","sources":["../../src/translations/de.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createTranslationMessages } from '@backstage/core-plugin-api/alpha';\nimport { translationsPluginTranslationRef } from './ref';\n\nconst translationsTranslationDe = createTranslationMessages({\n ref: translationsPluginTranslationRef,\n messages: {\n // CRITICAL: Use flat dot notation, not nested objects\n 'page.title': 'Übersetzungen',\n 'page.subtitle': 'Geladene Übersetzungen verwalten und anzeigen',\n 'table.title': 'Geladene Übersetzungen ({{count}})',\n 'table.headers.refId': 'Ref-ID',\n 'table.headers.key': 'Schlüssel',\n 'table.options.pageSize': 'Elemente pro Seite',\n 'table.options.pageSizeOptions': '{{count}} Elemente anzeigen',\n 'export.title': 'Übersetzungen',\n 'export.downloadButton': 'Standard-Übersetzungen herunterladen (Englisch)',\n 'export.filename': 'übersetzungen-{{timestamp}}.json',\n 'common.loading': 'Wird geladen...',\n 'common.error': 'Ein Fehler ist aufgetreten',\n 'common.noData': 'Keine Daten verfügbar',\n 'common.refresh': 'Aktualisieren',\n 'language.displayFormat': '{{displayName}} ({{code}})',\n },\n});\n\nexport default translationsTranslationDe;\n"],"names":[],"mappings":";;;AAkBA,MAAM,4BAA4B,yBAAA,CAA0B;AAAA,EAC1D,GAAA,EAAK,gCAAA;AAAA,EACL,QAAA,EAAU;AAAA;AAAA,IAER,YAAA,EAAc,kBAAA;AAAA,IACd,eAAA,EAAiB,kDAAA;AAAA,IACjB,aAAA,EAAe,uCAAA;AAAA,IACf,qBAAA,EAAuB,QAAA;AAAA,IACvB,mBAAA,EAAqB,cAAA;AAAA,IACrB,wBAAA,EAA0B,oBAAA;AAAA,IAC1B,+BAAA,EAAiC,6BAAA;AAAA,IACjC,cAAA,EAAgB,kBAAA;AAAA,IAChB,uBAAA,EAAyB,oDAAA;AAAA,IACzB,iBAAA,EAAmB,qCAAA;AAAA,IACnB,gBAAA,EAAkB,iBAAA;AAAA,IAClB,cAAA,EAAgB,4BAAA;AAAA,IAChB,eAAA,EAAiB,0BAAA;AAAA,IACjB,gBAAA,EAAkB,eAAA;AAAA,IAClB,wBAAA,EAA0B;AAAA;AAE9B,CAAC;;;;"}
@@ -0,0 +1,27 @@
1
+ import { createTranslationMessages } from '@backstage/core-plugin-api/alpha';
2
+ import { translationsPluginTranslationRef } from './ref.esm.js';
3
+
4
+ const translationsTranslationEs = createTranslationMessages({
5
+ ref: translationsPluginTranslationRef,
6
+ messages: {
7
+ // CRITICAL: Use flat dot notation, not nested objects
8
+ "page.title": "Traducciones",
9
+ "page.subtitle": "Gestionar y ver traducciones cargadas",
10
+ "table.title": "Traducciones cargadas ({{count}})",
11
+ "table.headers.refId": "ID de referencia",
12
+ "table.headers.key": "Clave",
13
+ "table.options.pageSize": "Elementos por p\xE1gina",
14
+ "table.options.pageSizeOptions": "Mostrar {{count}} elementos",
15
+ "export.title": "Traducciones",
16
+ "export.downloadButton": "Descargar traducciones por defecto (Ingl\xE9s)",
17
+ "export.filename": "traducciones-{{timestamp}}.json",
18
+ "common.loading": "Cargando...",
19
+ "common.error": "Ocurri\xF3 un error",
20
+ "common.noData": "No hay datos disponibles",
21
+ "common.refresh": "Actualizar",
22
+ "language.displayFormat": "{{displayName}} ({{code}})"
23
+ }
24
+ });
25
+
26
+ export { translationsTranslationEs as default };
27
+ //# sourceMappingURL=es.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"es.esm.js","sources":["../../src/translations/es.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createTranslationMessages } from '@backstage/core-plugin-api/alpha';\nimport { translationsPluginTranslationRef } from './ref';\n\nconst translationsTranslationEs = createTranslationMessages({\n ref: translationsPluginTranslationRef,\n messages: {\n // CRITICAL: Use flat dot notation, not nested objects\n 'page.title': 'Traducciones',\n 'page.subtitle': 'Gestionar y ver traducciones cargadas',\n 'table.title': 'Traducciones cargadas ({{count}})',\n 'table.headers.refId': 'ID de referencia',\n 'table.headers.key': 'Clave',\n 'table.options.pageSize': 'Elementos por página',\n 'table.options.pageSizeOptions': 'Mostrar {{count}} elementos',\n 'export.title': 'Traducciones',\n 'export.downloadButton': 'Descargar traducciones por defecto (Inglés)',\n 'export.filename': 'traducciones-{{timestamp}}.json',\n 'common.loading': 'Cargando...',\n 'common.error': 'Ocurrió un error',\n 'common.noData': 'No hay datos disponibles',\n 'common.refresh': 'Actualizar',\n 'language.displayFormat': '{{displayName}} ({{code}})',\n },\n});\n\nexport default translationsTranslationEs;\n"],"names":[],"mappings":";;;AAkBA,MAAM,4BAA4B,yBAAA,CAA0B;AAAA,EAC1D,GAAA,EAAK,gCAAA;AAAA,EACL,QAAA,EAAU;AAAA;AAAA,IAER,YAAA,EAAc,cAAA;AAAA,IACd,eAAA,EAAiB,uCAAA;AAAA,IACjB,aAAA,EAAe,mCAAA;AAAA,IACf,qBAAA,EAAuB,kBAAA;AAAA,IACvB,mBAAA,EAAqB,OAAA;AAAA,IACrB,wBAAA,EAA0B,yBAAA;AAAA,IAC1B,+BAAA,EAAiC,6BAAA;AAAA,IACjC,cAAA,EAAgB,cAAA;AAAA,IAChB,uBAAA,EAAyB,gDAAA;AAAA,IACzB,iBAAA,EAAmB,iCAAA;AAAA,IACnB,gBAAA,EAAkB,aAAA;AAAA,IAClB,cAAA,EAAgB,qBAAA;AAAA,IAChB,eAAA,EAAiB,0BAAA;AAAA,IACjB,gBAAA,EAAkB,YAAA;AAAA,IAClB,wBAAA,EAA0B;AAAA;AAE9B,CAAC;;;;"}
@@ -0,0 +1,27 @@
1
+ import { createTranslationMessages } from '@backstage/core-plugin-api/alpha';
2
+ import { translationsPluginTranslationRef } from './ref.esm.js';
3
+
4
+ const translationsTranslationFr = createTranslationMessages({
5
+ ref: translationsPluginTranslationRef,
6
+ messages: {
7
+ // CRITICAL: Use flat dot notation, not nested objects
8
+ "page.title": "Traductions",
9
+ "page.subtitle": "G\xE9rer et afficher les traductions charg\xE9es",
10
+ "table.title": "Traductions charg\xE9es ({{count}})",
11
+ "table.headers.refId": "ID de r\xE9f\xE9rence",
12
+ "table.headers.key": "Cl\xE9",
13
+ "table.options.pageSize": "\xC9l\xE9ments par page",
14
+ "table.options.pageSizeOptions": "Afficher {{count}} \xE9l\xE9ments",
15
+ "export.title": "Traductions",
16
+ "export.downloadButton": "T\xE9l\xE9charger les traductions par d\xE9faut (Anglais)",
17
+ "export.filename": "traductions-{{timestamp}}.json",
18
+ "common.loading": "Chargement...",
19
+ "common.error": "Une erreur s'est produite",
20
+ "common.noData": "Aucune donn\xE9e disponible",
21
+ "common.refresh": "Actualiser",
22
+ "language.displayFormat": "{{displayName}} ({{code}})"
23
+ }
24
+ });
25
+
26
+ export { translationsTranslationFr as default };
27
+ //# sourceMappingURL=fr.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fr.esm.js","sources":["../../src/translations/fr.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createTranslationMessages } from '@backstage/core-plugin-api/alpha';\nimport { translationsPluginTranslationRef } from './ref';\n\nconst translationsTranslationFr = createTranslationMessages({\n ref: translationsPluginTranslationRef,\n messages: {\n // CRITICAL: Use flat dot notation, not nested objects\n 'page.title': 'Traductions',\n 'page.subtitle': 'Gérer et afficher les traductions chargées',\n 'table.title': 'Traductions chargées ({{count}})',\n 'table.headers.refId': 'ID de référence',\n 'table.headers.key': 'Clé',\n 'table.options.pageSize': 'Éléments par page',\n 'table.options.pageSizeOptions': 'Afficher {{count}} éléments',\n 'export.title': 'Traductions',\n 'export.downloadButton': 'Télécharger les traductions par défaut (Anglais)',\n 'export.filename': 'traductions-{{timestamp}}.json',\n 'common.loading': 'Chargement...',\n 'common.error': \"Une erreur s'est produite\",\n 'common.noData': 'Aucune donnée disponible',\n 'common.refresh': 'Actualiser',\n 'language.displayFormat': '{{displayName}} ({{code}})',\n },\n});\n\nexport default translationsTranslationFr;\n"],"names":[],"mappings":";;;AAkBA,MAAM,4BAA4B,yBAAA,CAA0B;AAAA,EAC1D,GAAA,EAAK,gCAAA;AAAA,EACL,QAAA,EAAU;AAAA;AAAA,IAER,YAAA,EAAc,aAAA;AAAA,IACd,eAAA,EAAiB,kDAAA;AAAA,IACjB,aAAA,EAAe,qCAAA;AAAA,IACf,qBAAA,EAAuB,uBAAA;AAAA,IACvB,mBAAA,EAAqB,QAAA;AAAA,IACrB,wBAAA,EAA0B,yBAAA;AAAA,IAC1B,+BAAA,EAAiC,mCAAA;AAAA,IACjC,cAAA,EAAgB,aAAA;AAAA,IAChB,uBAAA,EAAyB,2DAAA;AAAA,IACzB,iBAAA,EAAmB,gCAAA;AAAA,IACnB,gBAAA,EAAkB,eAAA;AAAA,IAClB,cAAA,EAAgB,2BAAA;AAAA,IAChB,eAAA,EAAiB,6BAAA;AAAA,IACjB,gBAAA,EAAkB,YAAA;AAAA,IAClB,wBAAA,EAA0B;AAAA;AAE9B,CAAC;;;;"}
@@ -0,0 +1,15 @@
1
+ import { createTranslationResource } from '@backstage/core-plugin-api/alpha';
2
+ import { translationsPluginTranslationRef } from './ref.esm.js';
3
+
4
+ const translationsPluginTranslations = createTranslationResource({
5
+ ref: translationsPluginTranslationRef,
6
+ translations: {
7
+ de: () => import('./de.esm.js'),
8
+ fr: () => import('./fr.esm.js'),
9
+ it: () => import('./it.esm.js'),
10
+ es: () => import('./es.esm.js')
11
+ }
12
+ });
13
+
14
+ export { translationsPluginTranslationRef, translationsPluginTranslations };
15
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../../src/translations/index.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createTranslationResource } from '@backstage/core-plugin-api/alpha';\nimport { translationsPluginTranslationRef } from './ref';\n\n/**\n * @alpha\n *\n */\nexport const translationsPluginTranslations = createTranslationResource({\n ref: translationsPluginTranslationRef,\n translations: {\n de: () => import('./de'),\n fr: () => import('./fr'),\n it: () => import('./it'),\n es: () => import('./es'),\n },\n});\n/**\n * @alpha\n */\nexport { translationsPluginTranslationRef };\n"],"names":[],"mappings":";;;AAsBO,MAAM,iCAAiC,yBAAA,CAA0B;AAAA,EACtE,GAAA,EAAK,gCAAA;AAAA,EACL,YAAA,EAAc;AAAA,IACZ,EAAA,EAAI,MAAM,OAAO,aAAM,CAAA;AAAA,IACvB,EAAA,EAAI,MAAM,OAAO,aAAM,CAAA;AAAA,IACvB,EAAA,EAAI,MAAM,OAAO,aAAM,CAAA;AAAA,IACvB,EAAA,EAAI,MAAM,OAAO,aAAM;AAAA;AAE3B,CAAC;;;;"}
@@ -0,0 +1,27 @@
1
+ import { createTranslationMessages } from '@backstage/core-plugin-api/alpha';
2
+ import { translationsPluginTranslationRef } from './ref.esm.js';
3
+
4
+ const translationsTranslationIt = createTranslationMessages({
5
+ ref: translationsPluginTranslationRef,
6
+ messages: {
7
+ // CRITICAL: Use flat dot notation, not nested objects
8
+ "page.title": "Traduzioni",
9
+ "page.subtitle": "Gestisci e visualizza le traduzioni caricate",
10
+ "table.title": "Traduzioni caricate ({{count}})",
11
+ "table.headers.refId": "ID di riferimento",
12
+ "table.headers.key": "Chiave",
13
+ "table.options.pageSize": "Elementi per pagina",
14
+ "table.options.pageSizeOptions": "Mostra {{count}} elementi",
15
+ "export.title": "Traduzioni",
16
+ "export.downloadButton": "Scarica traduzioni predefinite (Inglese)",
17
+ "export.filename": "traduzioni-{{timestamp}}.json",
18
+ "common.loading": "Caricamento...",
19
+ "common.error": "Si \xE8 verificato un errore",
20
+ "common.noData": "Nessun dato disponibile",
21
+ "common.refresh": "Aggiorna",
22
+ "language.displayFormat": "{{displayName}} ({{code}})"
23
+ }
24
+ });
25
+
26
+ export { translationsTranslationIt as default };
27
+ //# sourceMappingURL=it.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"it.esm.js","sources":["../../src/translations/it.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createTranslationMessages } from '@backstage/core-plugin-api/alpha';\nimport { translationsPluginTranslationRef } from './ref';\n\nconst translationsTranslationIt = createTranslationMessages({\n ref: translationsPluginTranslationRef,\n messages: {\n // CRITICAL: Use flat dot notation, not nested objects\n 'page.title': 'Traduzioni',\n 'page.subtitle': 'Gestisci e visualizza le traduzioni caricate',\n 'table.title': 'Traduzioni caricate ({{count}})',\n 'table.headers.refId': 'ID di riferimento',\n 'table.headers.key': 'Chiave',\n 'table.options.pageSize': 'Elementi per pagina',\n 'table.options.pageSizeOptions': 'Mostra {{count}} elementi',\n 'export.title': 'Traduzioni',\n 'export.downloadButton': 'Scarica traduzioni predefinite (Inglese)',\n 'export.filename': 'traduzioni-{{timestamp}}.json',\n 'common.loading': 'Caricamento...',\n 'common.error': 'Si è verificato un errore',\n 'common.noData': 'Nessun dato disponibile',\n 'common.refresh': 'Aggiorna',\n 'language.displayFormat': '{{displayName}} ({{code}})',\n },\n});\n\nexport default translationsTranslationIt;\n"],"names":[],"mappings":";;;AAkBA,MAAM,4BAA4B,yBAAA,CAA0B;AAAA,EAC1D,GAAA,EAAK,gCAAA;AAAA,EACL,QAAA,EAAU;AAAA;AAAA,IAER,YAAA,EAAc,YAAA;AAAA,IACd,eAAA,EAAiB,8CAAA;AAAA,IACjB,aAAA,EAAe,iCAAA;AAAA,IACf,qBAAA,EAAuB,mBAAA;AAAA,IACvB,mBAAA,EAAqB,QAAA;AAAA,IACrB,wBAAA,EAA0B,qBAAA;AAAA,IAC1B,+BAAA,EAAiC,2BAAA;AAAA,IACjC,cAAA,EAAgB,YAAA;AAAA,IAChB,uBAAA,EAAyB,0CAAA;AAAA,IACzB,iBAAA,EAAmB,+BAAA;AAAA,IACnB,gBAAA,EAAkB,gBAAA;AAAA,IAClB,cAAA,EAAgB,8BAAA;AAAA,IAChB,eAAA,EAAiB,yBAAA;AAAA,IACjB,gBAAA,EAAkB,UAAA;AAAA,IAClB,wBAAA,EAA0B;AAAA;AAE9B,CAAC;;;;"}
@@ -0,0 +1,40 @@
1
+ import { createTranslationRef } from '@backstage/core-plugin-api/alpha';
2
+
3
+ const translationsMessages = {
4
+ page: {
5
+ title: "Translations",
6
+ subtitle: "Manage and view loaded translations"
7
+ },
8
+ table: {
9
+ title: "Loaded translations ({{count}})",
10
+ headers: {
11
+ refId: "Ref ID",
12
+ key: "Key"
13
+ },
14
+ options: {
15
+ pageSize: "Items per page",
16
+ pageSizeOptions: "Show {{count}} items"
17
+ }
18
+ },
19
+ export: {
20
+ title: "Translations",
21
+ downloadButton: "Download default translations (English)",
22
+ filename: "translations-{{timestamp}}.json"
23
+ },
24
+ common: {
25
+ loading: "Loading...",
26
+ error: "An error occurred",
27
+ noData: "No data available",
28
+ refresh: "Refresh"
29
+ },
30
+ language: {
31
+ displayFormat: "{{displayName}} ({{code}})"
32
+ }
33
+ };
34
+ const translationsPluginTranslationRef = createTranslationRef({
35
+ id: "plugin.translations",
36
+ messages: translationsMessages
37
+ });
38
+
39
+ export { translationsMessages, translationsPluginTranslationRef };
40
+ //# sourceMappingURL=ref.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref.esm.js","sources":["../../src/translations/ref.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createTranslationRef } from '@backstage/core-plugin-api/alpha';\n\n/**\n * @alpha\n */\nexport const translationsMessages = {\n page: {\n title: 'Translations',\n subtitle: 'Manage and view loaded translations',\n },\n table: {\n title: 'Loaded translations ({{count}})',\n headers: {\n refId: 'Ref ID',\n key: 'Key',\n },\n options: {\n pageSize: 'Items per page',\n pageSizeOptions: 'Show {{count}} items',\n },\n },\n export: {\n title: 'Translations',\n downloadButton: 'Download default translations (English)',\n filename: 'translations-{{timestamp}}.json',\n },\n common: {\n loading: 'Loading...',\n error: 'An error occurred',\n noData: 'No data available',\n refresh: 'Refresh',\n },\n language: {\n displayFormat: '{{displayName}} ({{code}})',\n },\n};\n/**\n * @alpha\n */\nexport const translationsPluginTranslationRef = createTranslationRef({\n id: 'plugin.translations',\n messages: translationsMessages,\n});\n"],"names":[],"mappings":";;AAoBO,MAAM,oBAAA,GAAuB;AAAA,EAClC,IAAA,EAAM;AAAA,IACJ,KAAA,EAAO,cAAA;AAAA,IACP,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,KAAA,EAAO;AAAA,IACL,KAAA,EAAO,iCAAA;AAAA,IACP,OAAA,EAAS;AAAA,MACP,KAAA,EAAO,QAAA;AAAA,MACP,GAAA,EAAK;AAAA,KACP;AAAA,IACA,OAAA,EAAS;AAAA,MACP,QAAA,EAAU,gBAAA;AAAA,MACV,eAAA,EAAiB;AAAA;AACnB,GACF;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO,cAAA;AAAA,IACP,cAAA,EAAgB,yCAAA;AAAA,IAChB,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,OAAA,EAAS,YAAA;AAAA,IACT,KAAA,EAAO,mBAAA;AAAA,IACP,MAAA,EAAQ,mBAAA;AAAA,IACR,OAAA,EAAS;AAAA,GACX;AAAA,EACA,QAAA,EAAU;AAAA,IACR,aAAA,EAAe;AAAA;AAEnB;AAIO,MAAM,mCAAmC,oBAAA,CAAqB;AAAA,EACnE,EAAA,EAAI,qBAAA;AAAA,EACJ,QAAA,EAAU;AACZ,CAAC;;;;"}
package/package.json CHANGED
@@ -1,14 +1,35 @@
1
1
  {
2
2
  "name": "@red-hat-developer-hub/backstage-plugin-translations",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "license": "Apache-2.0",
5
- "main": "dist/index.esm.js",
6
- "types": "dist/index.d.ts",
7
5
  "publishConfig": {
8
- "access": "public",
9
- "main": "dist/index.esm.js",
10
- "types": "dist/index.d.ts"
6
+ "access": "public"
11
7
  },
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.esm.js",
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.esm.js"
13
+ },
14
+ "./alpha": {
15
+ "import": "./dist/alpha.esm.js",
16
+ "types": "./dist/alpha.d.ts",
17
+ "default": "./dist/alpha.esm.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "typesVersions": {
22
+ "*": {
23
+ "alpha": [
24
+ "dist/alpha.d.ts"
25
+ ],
26
+ "package.json": [
27
+ "package.json"
28
+ ]
29
+ }
30
+ },
31
+ "main": "./dist/index.esm.js",
32
+ "types": "./dist/index.d.ts",
12
33
  "repository": {
13
34
  "type": "git",
14
35
  "url": "https://github.com/redhat-developer/rhdh-plugins",
@@ -18,7 +39,8 @@
18
39
  "role": "frontend-plugin",
19
40
  "pluginId": "translations",
20
41
  "pluginPackages": [
21
- "@red-hat-developer-hub/backstage-plugin-translations"
42
+ "@red-hat-developer-hub/backstage-plugin-translations",
43
+ "@red-hat-developer-hub/backstage-plugin-translations-backend"
22
44
  ]
23
45
  },
24
46
  "sideEffects": false,
@@ -32,11 +54,13 @@
32
54
  "postpack": "backstage-cli package postpack"
33
55
  },
34
56
  "dependencies": {
35
- "@backstage/core-components": "^0.17.2",
36
- "@backstage/core-plugin-api": "^1.10.7",
37
- "@backstage/plugin-user-settings": "^0.8.22",
38
- "@backstage/theme": "^0.6.6",
57
+ "@backstage/core-components": "^0.17.5",
58
+ "@backstage/core-plugin-api": "^1.10.9",
59
+ "@backstage/plugin-user-settings": "^0.8.25",
60
+ "@backstage/theme": "^0.6.8",
39
61
  "@backstage/types": "^1.2.1",
62
+ "@mui/icons-material": "5.18.0",
63
+ "@mui/material": "5.18.0",
40
64
  "i18next": "^22.4.15",
41
65
  "zen-observable": "^0.10.0"
42
66
  },
@@ -44,10 +68,10 @@
44
68
  "react": "^16.13.1 || ^17.0.0 || ^18.0.0"
45
69
  },
46
70
  "devDependencies": {
47
- "@backstage/cli": "^0.32.1",
48
- "@backstage/core-app-api": "^1.17.0",
49
- "@backstage/dev-utils": "^1.1.10",
50
- "@backstage/test-utils": "^1.7.8",
71
+ "@backstage/cli": "^0.34.1",
72
+ "@backstage/core-app-api": "^1.18.0",
73
+ "@backstage/dev-utils": "^1.1.13",
74
+ "@backstage/test-utils": "^1.7.11",
51
75
  "@testing-library/jest-dom": "^6.0.0",
52
76
  "@testing-library/react": "^14.0.0",
53
77
  "@testing-library/user-event": "^14.0.0",
@@ -58,12 +82,5 @@
58
82
  "files": [
59
83
  "dist"
60
84
  ],
61
- "typesVersions": {
62
- "*": {
63
- "package.json": [
64
- "package.json"
65
- ]
66
- }
67
- },
68
85
  "module": "./dist/index.esm.js"
69
86
  }
@@ -1,21 +0,0 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { InfoCard } from '@backstage/core-components';
3
- import { useApi } from '@backstage/core-plugin-api';
4
- import { appLanguageApiRef } from '@backstage/core-plugin-api/alpha';
5
-
6
- const AppLanguageCard = () => {
7
- const appLanguageApi = useApi(appLanguageApiRef);
8
- return /* @__PURE__ */ jsxs(InfoCard, { title: "AppLanguageApi", children: [
9
- /* @__PURE__ */ jsx("strong", { children: "Current Language:" }),
10
- /* @__PURE__ */ jsx("br", {}),
11
- appLanguageApi.getLanguage().language,
12
- /* @__PURE__ */ jsx("br", {}),
13
- /* @__PURE__ */ jsx("br", {}),
14
- /* @__PURE__ */ jsx("strong", { children: "Available languages:" }),
15
- /* @__PURE__ */ jsx("br", {}),
16
- appLanguageApi.getAvailableLanguages().languages.map((lang) => /* @__PURE__ */ jsx("div", { children: lang }, lang))
17
- ] });
18
- };
19
-
20
- export { AppLanguageCard };
21
- //# sourceMappingURL=AppLanguageCard.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AppLanguageCard.esm.js","sources":["../../src/components/AppLanguageCard.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { InfoCard } from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { appLanguageApiRef } from '@backstage/core-plugin-api/alpha';\n\nexport const AppLanguageCard = () => {\n const appLanguageApi = useApi(appLanguageApiRef);\n\n return (\n <InfoCard title=\"AppLanguageApi\">\n <strong>Current Language:</strong>\n <br />\n {appLanguageApi.getLanguage().language}\n <br />\n <br />\n\n <strong>Available languages:</strong>\n <br />\n {appLanguageApi.getAvailableLanguages().languages.map(lang => (\n <div key={lang}>{lang}</div>\n ))}\n </InfoCard>\n );\n};\n"],"names":[],"mappings":";;;;;AAmBO,MAAM,kBAAkB,MAAM;AACnC,EAAA,MAAM,cAAA,GAAiB,OAAO,iBAAiB,CAAA;AAE/C,EAAA,uBACE,IAAA,CAAC,QAAA,EAAA,EAAS,KAAA,EAAM,gBAAA,EACd,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,YAAO,QAAA,EAAA,mBAAA,EAAiB,CAAA;AAAA,wBACxB,IAAA,EAAA,EAAG,CAAA;AAAA,IACH,cAAA,CAAe,aAAY,CAAE,QAAA;AAAA,wBAC7B,IAAA,EAAA,EAAG,CAAA;AAAA,wBACH,IAAA,EAAA,EAAG,CAAA;AAAA,oBAEJ,GAAA,CAAC,YAAO,QAAA,EAAA,sBAAA,EAAoB,CAAA;AAAA,wBAC3B,IAAA,EAAA,EAAG,CAAA;AAAA,IACH,cAAA,CAAe,qBAAA,EAAsB,CAAE,SAAA,CAAU,GAAA,CAAI,0BACpD,GAAA,CAAC,KAAA,EAAA,EAAgB,QAAA,EAAA,IAAA,EAAA,EAAP,IAAY,CACvB;AAAA,GAAA,EACH,CAAA;AAEJ;;;;"}
@@ -1,25 +0,0 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { InfoCard } from '@backstage/core-components';
3
- import { useApi } from '@backstage/core-plugin-api';
4
- import { translationApiRef } from '@backstage/core-plugin-api/alpha';
5
-
6
- const I18NextCard = () => {
7
- const translationApi = useApi(translationApiRef);
8
- const i18n = translationApi.getI18nInstance();
9
- return /* @__PURE__ */ jsxs(InfoCard, { title: "TranslationApi / i18Next", children: [
10
- /* @__PURE__ */ jsx("strong", { children: "Current Language:" }),
11
- /* @__PURE__ */ jsx("br", {}),
12
- i18n.language,
13
- /* @__PURE__ */ jsx("br", {}),
14
- /* @__PURE__ */ jsx("br", {}),
15
- /* @__PURE__ */ jsx("strong", { children: "Available languages:" }),
16
- /* @__PURE__ */ jsx("br", {}),
17
- i18n.languages?.map((lang) => /* @__PURE__ */ jsx("div", { children: lang }, lang)),
18
- /* @__PURE__ */ jsx("strong", { children: "Available languages:" }),
19
- /* @__PURE__ */ jsx("br", {}),
20
- /* @__PURE__ */ jsx("pre", { children: JSON.stringify(i18n.store.data, null, 2) })
21
- ] });
22
- };
23
-
24
- export { I18NextCard };
25
- //# sourceMappingURL=I18NextCard.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"I18NextCard.esm.js","sources":["../../src/components/I18NextCard.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { InfoCard } from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { translationApiRef } from '@backstage/core-plugin-api/alpha';\n\nimport type { i18n as I18n } from 'i18next';\n\nexport const I18NextCard = () => {\n const translationApi = useApi(translationApiRef);\n const i18n: I18n = (translationApi as any).getI18nInstance();\n\n return (\n <InfoCard title=\"TranslationApi / i18Next\">\n <strong>Current Language:</strong>\n <br />\n {i18n.language}\n <br />\n <br />\n\n <strong>Available languages:</strong>\n <br />\n {i18n.languages?.map(lang => (\n <div key={lang}>{lang}</div>\n ))}\n\n <strong>Available languages:</strong>\n <br />\n <pre>{JSON.stringify(i18n.store.data, null, 2)}</pre>\n </InfoCard>\n );\n};\n"],"names":[],"mappings":";;;;;AAqBO,MAAM,cAAc,MAAM;AAC/B,EAAA,MAAM,cAAA,GAAiB,OAAO,iBAAiB,CAAA;AAC/C,EAAA,MAAM,IAAA,GAAc,eAAuB,eAAA,EAAgB;AAE3D,EAAA,uBACE,IAAA,CAAC,QAAA,EAAA,EAAS,KAAA,EAAM,0BAAA,EACd,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,YAAO,QAAA,EAAA,mBAAA,EAAiB,CAAA;AAAA,wBACxB,IAAA,EAAA,EAAG,CAAA;AAAA,IACH,IAAA,CAAK,QAAA;AAAA,wBACL,IAAA,EAAA,EAAG,CAAA;AAAA,wBACH,IAAA,EAAA,EAAG,CAAA;AAAA,oBAEJ,GAAA,CAAC,YAAO,QAAA,EAAA,sBAAA,EAAoB,CAAA;AAAA,wBAC3B,IAAA,EAAA,EAAG,CAAA;AAAA,IACH,IAAA,CAAK,WAAW,GAAA,CAAI,CAAA,IAAA,yBAClB,KAAA,EAAA,EAAgB,QAAA,EAAA,IAAA,EAAA,EAAP,IAAY,CACvB,CAAA;AAAA,oBAED,GAAA,CAAC,YAAO,QAAA,EAAA,sBAAA,EAAoB,CAAA;AAAA,wBAC3B,IAAA,EAAA,EAAG,CAAA;AAAA,oBACJ,GAAA,CAAC,SAAK,QAAA,EAAA,IAAA,CAAK,SAAA,CAAU,KAAK,KAAA,CAAM,IAAA,EAAM,IAAA,EAAM,CAAC,CAAA,EAAE;AAAA,GAAA,EACjD,CAAA;AAEJ;;;;"}
@@ -1,10 +0,0 @@
1
- import { jsx } from 'react/jsx-runtime';
2
- import { InfoCard } from '@backstage/core-components';
3
- import { UserSettingsLanguageToggle } from '@backstage/plugin-user-settings';
4
-
5
- const LanguageToggleCard = () => {
6
- return /* @__PURE__ */ jsx(InfoCard, { title: "Language Toggle", children: /* @__PURE__ */ jsx(UserSettingsLanguageToggle, {}) });
7
- };
8
-
9
- export { LanguageToggleCard };
10
- //# sourceMappingURL=LanguageToggleCard.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LanguageToggleCard.esm.js","sources":["../../src/components/LanguageToggleCard.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { InfoCard } from '@backstage/core-components';\n\nimport { UserSettingsLanguageToggle } from '@backstage/plugin-user-settings';\n\nexport const LanguageToggleCard = () => {\n return (\n <InfoCard title=\"Language Toggle\">\n <UserSettingsLanguageToggle />\n </InfoCard>\n );\n};\n"],"names":[],"mappings":";;;;AAmBO,MAAM,qBAAqB,MAAM;AACtC,EAAA,2BACG,QAAA,EAAA,EAAS,KAAA,EAAM,iBAAA,EACd,QAAA,kBAAA,GAAA,CAAC,8BAA2B,CAAA,EAC9B,CAAA;AAEJ;;;;"}