├── .eslintrc.json ├── .github ├── scripts │ └── update-readme.sh └── workflows │ ├── auto-merge.yml │ ├── prerelease-tolgee-5.yml │ ├── prerelease.yml │ ├── publish-examples-check.yml │ ├── publish-examples.yml │ ├── release.yml │ ├── report-intermittent-tests.yml │ └── test.yml ├── .gitignore ├── .mergify.yml ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── .snyk ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── README.njk.md ├── docker ├── Dockerfile ├── Dockerfile.builder ├── Dockerfile.with-build └── wait-for-file ├── e2e ├── .eslintrc.json ├── .gitignore ├── cypress.config.ts ├── cypress │ ├── common │ │ ├── apiCalls.ts │ │ ├── constants.ts │ │ ├── devUiTools.ts │ │ ├── exampleAppDevTest.ts │ │ ├── exampleAppTest.ts │ │ ├── namespacesNgxTest.ts │ │ ├── namespacesTest.ts │ │ ├── nextInternalCommon.ts │ │ ├── selectors.ts │ │ ├── simulateReqAndResponse.ts │ │ ├── testApiKeys.ts │ │ ├── testLanguages.ts │ │ ├── translationMethodsTest.ts │ │ └── types.ts │ ├── e2e │ │ ├── next-app-intl │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── next-app │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── next │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── ngx │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── react-i18next │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── react │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── svelte │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── vanilla │ │ │ ├── base.cy.ts │ │ │ ├── lang_switching.cy.ts │ │ │ └── production.cy.ts │ │ ├── vue-i18next │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── vue-ssr │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ ├── vue │ │ │ ├── dev.cy.ts │ │ │ └── prod.cy.ts │ │ └── web-internal │ │ │ ├── plural.cy.ts │ │ │ ├── screenshots.cy.ts │ │ │ ├── tags.cy.ts │ │ │ └── ui.cy.ts │ ├── fixtures │ │ └── example.json │ ├── plugins │ │ └── index.js │ └── support │ │ ├── commands.js │ │ ├── custom.d.ts │ │ ├── e2e.js │ │ └── index.d.ts ├── docker-compose.yml ├── import-data │ └── examples │ │ ├── cs.json │ │ ├── de.json │ │ ├── en.json │ │ ├── fr.json │ │ ├── namespaced │ │ ├── cs.json │ │ ├── de.json │ │ ├── en.json │ │ └── fr.json │ │ └── translation │ │ ├── cs.json │ │ ├── de.json │ │ ├── en.json │ │ └── fr.json ├── package.json ├── scripts │ ├── startCypress.sh │ └── waitForServices.js └── tsconfig.json ├── jest.config.mjs ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── core │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── README.njk.md │ ├── jest.config.mjs │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── Controller │ │ │ ├── Cache │ │ │ │ ├── Cache.test.ts │ │ │ │ ├── Cache.ts │ │ │ │ └── helpers.ts │ │ │ ├── Controller.ts │ │ │ ├── Events │ │ │ │ ├── EventEmitter.ts │ │ │ │ ├── EventEmitterCombined.ts │ │ │ │ └── Events.ts │ │ │ ├── Plugins │ │ │ │ └── Plugins.ts │ │ │ ├── State │ │ │ │ ├── State.ts │ │ │ │ ├── initState.ts │ │ │ │ └── observerOptions.ts │ │ │ └── ValueObserver.ts │ │ ├── FormatSimple │ │ │ ├── FormatError.ts │ │ │ ├── FormatSimple.ts │ │ │ ├── formatParser.ts │ │ │ ├── formatter.test.ts │ │ │ └── formatter.ts │ │ ├── TolgeeCore.ts │ │ ├── TranslateParams.test.ts │ │ ├── TranslateParams.ts │ │ ├── __test │ │ │ ├── backend.test.ts │ │ │ ├── cache.test.ts │ │ │ ├── client.test.ts │ │ │ ├── errors.detector.test.ts │ │ │ ├── errors.record.test.ts │ │ │ ├── errors.storage.test.ts │ │ │ ├── events.test.ts │ │ │ ├── format.simple.test.ts │ │ │ ├── formatError.test.ts │ │ │ ├── initialization.test.ts │ │ │ ├── jest-setup.ts │ │ │ ├── languageDetection.test.ts │ │ │ ├── languageStorage.test.ts │ │ │ ├── languages.test.ts │ │ │ ├── load.matrix.test.ts │ │ │ ├── load.required.test.ts │ │ │ ├── loading.test.ts │ │ │ ├── missingTranslation.test.ts │ │ │ ├── namespaces.controller.test.ts │ │ │ ├── namespaces.fallback.test.ts │ │ │ ├── namespaces.required.test.ts │ │ │ ├── namespaces.test.ts │ │ │ ├── options.test.ts │ │ │ ├── plugins.test.ts │ │ │ └── testTools.ts │ │ ├── helpers.ts │ │ ├── index.ts │ │ └── types │ │ │ ├── cache.ts │ │ │ ├── errors.ts │ │ │ ├── events.ts │ │ │ ├── general.ts │ │ │ ├── index.ts │ │ │ └── plugin.ts │ ├── tsconfig.json │ └── tsconfig.prod.json ├── format-icu │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── README.njk.md │ ├── jest.config.mjs │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── FormatIcu.ts │ │ ├── createFormatIcu.test.ts │ │ ├── createFormatIcu.ts │ │ └── index.ts │ ├── tsconfig.json │ └── tsconfig.prod.json ├── i18next │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── README.njk.md │ ├── index.js │ ├── jest.config.mjs │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── I18nextPlugin.ts │ │ ├── __integration │ │ │ ├── tolgeeUpdating.test.ts │ │ │ └── withTolgee.test.ts │ │ ├── index.ts │ │ ├── tolgeeApply.ts │ │ ├── tolgeeBackend.ts │ │ ├── tolgeeOptions.ts │ │ ├── tolgeeProcessor.ts │ │ └── withTolgee.ts │ ├── tsconfig.json │ └── tsconfig.prod.json ├── ngx │ ├── .editorconfig │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── angular.json │ ├── package.json │ ├── projects │ │ └── ngx-tolgee │ │ │ ├── CHANGELOG.md │ │ │ ├── README.md │ │ │ ├── README.njk.md │ │ │ ├── jest.config.js │ │ │ ├── ng-package.json │ │ │ ├── package.json │ │ │ ├── src │ │ │ ├── __integration │ │ │ │ ├── resolving │ │ │ │ │ ├── lazy.module.ts │ │ │ │ │ ├── resolving.spec.ts │ │ │ │ │ └── root.component.ts │ │ │ │ ├── t.component.spec.ts │ │ │ │ ├── translate.pipe.spec.ts │ │ │ │ └── translate.service.spec.ts │ │ │ ├── lib │ │ │ │ ├── loader.component.ts │ │ │ │ ├── namespace.resolver.ts │ │ │ │ ├── ngx-tolgee.module.ts │ │ │ │ ├── t.component.ts │ │ │ │ ├── tolgee-instance-token.ts │ │ │ │ ├── translate.pipe.ts │ │ │ │ └── translate.service.ts │ │ │ ├── public-api.ts │ │ │ └── test-setup.ts │ │ │ ├── tsconfig.lib.json │ │ │ ├── tsconfig.lib.prod.json │ │ │ └── tsconfig.spec.json │ └── tsconfig.json ├── react │ ├── .buildversions │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── README.njk.md │ ├── jest.config.mjs │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── GlobalContextPlugin.tsx │ │ ├── T.tsx │ │ ├── TBase.tsx │ │ ├── TolgeeProvider.spec.tsx │ │ ├── TolgeeProvider.tsx │ │ ├── __integration │ │ │ ├── T.spec.tsx │ │ │ ├── TolgeeProvider.spec.tsx │ │ │ ├── namespaces.spec.tsx │ │ │ ├── useTolgee.spec.tsx │ │ │ └── useTranslation.spec.tsx │ │ ├── createServerInstance.tsx │ │ ├── hooks.ts │ │ ├── index.ts │ │ ├── server.ts │ │ ├── tagsTools.tsx │ │ ├── types.ts │ │ ├── useTolgee.ts │ │ ├── useTolgeeContext.ts │ │ ├── useTolgeeSSR.ts │ │ ├── useTranslate.ts │ │ └── useTranslateInternal.ts │ ├── tsconfig.json │ ├── tsconfig.prod.json │ └── tsconfig.spec.json ├── svelte │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── CHANGELOG.md │ ├── README.md │ ├── README.njk.md │ ├── eslint.config.js │ ├── package.json │ ├── src │ │ ├── app.d.ts │ │ ├── app.html │ │ ├── lib │ │ │ ├── GlobalContextPlugin.ts │ │ │ ├── T.svelte │ │ │ ├── TolgeeProvider.svelte │ │ │ ├── TolgeeProvider.test.ts │ │ │ ├── __integration │ │ │ │ ├── T.spec.ts │ │ │ │ ├── TolgeeProvider.spec.ts │ │ │ │ ├── components │ │ │ │ │ ├── Namespaces.svelte │ │ │ │ │ ├── TestGetTolgee.svelte │ │ │ │ │ ├── TestProviderComponent.svelte │ │ │ │ │ ├── TestTComponent.svelte │ │ │ │ │ ├── TestTranslateComponent.svelte │ │ │ │ │ └── TestTranslateComponentInside.svelte │ │ │ │ ├── getTolgee.spec.ts │ │ │ │ ├── getTranslate.spec.ts │ │ │ │ ├── mockCoreFetch.ts │ │ │ │ └── namespaces.spec.ts │ │ │ ├── __testUtil │ │ │ │ ├── TolgeeProviderFallback.svelte │ │ │ │ └── TolgeeProviderSlotTest.svelte │ │ │ ├── getTolgee.ts │ │ │ ├── getTolgeeContext.ts │ │ │ ├── getTranslate.ts │ │ │ ├── getTranslateInternal.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── routes │ │ │ └── +page.svelte │ ├── static │ │ └── favicon.png │ ├── svelte.config.js │ ├── tests │ │ └── setup.ts │ ├── tsconfig.json │ └── vite.config.ts ├── testing │ ├── CHANGELOG.md │ ├── createResolvablePromise.ts │ ├── currentApiKeyMock.ts │ ├── fetchMock.ts │ ├── index.ts │ ├── mockData.ts │ ├── mockStaticData.ts │ ├── mockTranslations.ts │ ├── package.json │ └── wait.ts ├── vue │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── README.njk.md │ ├── jest.config.mjs │ ├── package.json │ ├── rollup.config.mjs │ ├── src │ │ ├── GlobalContextPlugin.ts │ │ ├── T.ts │ │ ├── TolgeeProvider.spec.ts │ │ ├── TolgeeProvider.ts │ │ ├── VueTolgee.ts │ │ ├── __integration │ │ │ ├── T.spec.ts │ │ │ ├── TolgeeComposition.spec.ts │ │ │ ├── TolgeeProvider.spec.ts │ │ │ ├── namespaces.spec.ts │ │ │ ├── useTolgee.spec.ts │ │ │ └── useTranslate.spec.ts │ │ ├── index.ts │ │ ├── mocks │ │ │ ├── ComponentUsingProvider.vue │ │ │ ├── ProviderComponent.vue │ │ │ └── ProviderComponentSlot.vue │ │ ├── shims-vue.d.ts │ │ ├── types.ts │ │ ├── useTolgee.ts │ │ ├── useTranslate.ts │ │ └── useTranslateInternal.ts │ ├── tsconfig.json │ └── tsconfig.prod.json └── web │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── README.njk.md │ ├── index.cjs │ ├── index.html │ ├── jest.config.ts │ ├── package.json │ ├── public │ ├── i18n │ │ ├── cs.json │ │ ├── de.json │ │ ├── en.json │ │ └── fr.json │ ├── img │ │ ├── appLogo.svg │ │ ├── background.svg │ │ ├── iconAdd.svg │ │ ├── iconMail.svg │ │ └── iconShare.svg │ └── vite.svg │ ├── rollup.common.ts │ ├── src │ ├── app │ │ ├── App.tsx │ │ ├── Todos.tsx │ │ ├── TranslationMethods.tsx │ │ ├── basicTolgee.ts │ │ ├── components │ │ │ ├── LangSelector.tsx │ │ │ └── Navbar.tsx │ │ ├── main.tsx │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── package │ │ ├── BackendFetch.test.ts │ │ ├── BackendFetch.ts │ │ ├── BrowserExtensionPlugin │ │ │ ├── BrowserExtensionPlugin.ts │ │ │ ├── constants.ts │ │ │ └── loadInContextLib.ts │ │ ├── ContextUi.ts │ │ ├── DevBackend.ts │ │ ├── InContextTools.ts │ │ ├── InvisibleObserver.ts │ │ ├── LanguageDetector.test.ts │ │ ├── LanguageDetector.ts │ │ ├── LanguageStorage.ts │ │ ├── ObserverPlugin.ts │ │ ├── TextObserver.ts │ │ ├── Tolgee.ts │ │ ├── __test__ │ │ │ ├── browser.extension.test.ts │ │ │ ├── fetch.apiUrl.test.ts │ │ │ ├── fetch.fallbacks.test.ts │ │ │ ├── fetchingUtillity.ts │ │ │ ├── observer.options.test.tsx │ │ │ ├── observer.test.ts │ │ │ ├── testObserver.ts │ │ │ └── testRetranslate.ts │ │ ├── constants.ts │ │ ├── entry-development.ts │ │ ├── entry-production.ts │ │ ├── entry-tools.ts │ │ ├── observers │ │ │ ├── general │ │ │ │ ├── DomHelper.ts │ │ │ │ ├── ElementHighlighter.ts │ │ │ │ ├── ElementMeta.ts │ │ │ │ ├── ElementRegistry.ts │ │ │ │ ├── ElementStore.ts │ │ │ │ ├── GeneralObserver.ts │ │ │ │ ├── MouseEventHandler.ts │ │ │ │ ├── NodeHandler.ts │ │ │ │ └── helpers.ts │ │ │ ├── invisible │ │ │ │ ├── InvisibleWrapper.test.ts │ │ │ │ ├── InvisibleWrapper.ts │ │ │ │ ├── ValueMemory.test.ts │ │ │ │ ├── ValueMemory.ts │ │ │ │ ├── secret.test.ts │ │ │ │ └── secret.ts │ │ │ └── text │ │ │ │ ├── TextWrapper.test.ts │ │ │ │ ├── TextWrapper.ts │ │ │ │ └── helpers.ts │ │ ├── tools │ │ │ ├── decodeApiKey.test.ts │ │ │ ├── decodeApiKey.ts │ │ │ ├── detectLanguageFromHeaders.ts │ │ │ ├── extension.test.ts │ │ │ ├── extension.ts │ │ │ ├── getHeaderLanguages.test.ts │ │ │ ├── getHeaderLanguages.ts │ │ │ ├── isSSR.ts │ │ │ ├── url.test.ts │ │ │ └── url.ts │ │ ├── typedIndex.ts │ │ ├── types.ts │ │ └── ui │ │ │ ├── InContextUi.tsx │ │ │ ├── KeyContextMenu │ │ │ ├── KeyContextMenu.test.ts │ │ │ └── KeyContextMenu.tsx │ │ │ ├── KeyDialog │ │ │ ├── ErrorAlert.tsx │ │ │ ├── KeyDialog.tsx │ │ │ ├── KeyForm.tsx │ │ │ ├── LanguageSelect.tsx │ │ │ ├── Link.tsx │ │ │ ├── NewWindow.tsx │ │ │ ├── NsSelect.tsx │ │ │ ├── PluralFormCheckbox.tsx │ │ │ ├── ScreenshotGallery │ │ │ │ ├── ExtensionPrompt.tsx │ │ │ │ ├── ScreenshotDetail.tsx │ │ │ │ ├── ScreenshotDropzone.tsx │ │ │ │ ├── ScreenshotGallery.tsx │ │ │ │ ├── ScreenshotThumbnail.tsx │ │ │ │ ├── ScreenshotWithLabels.tsx │ │ │ │ └── utils.ts │ │ │ ├── State │ │ │ │ ├── ControlsButton.tsx │ │ │ │ ├── StateIcon.tsx │ │ │ │ ├── StateTransitionButtons.tsx │ │ │ │ └── translationStates.ts │ │ │ ├── Tags │ │ │ │ ├── CloseButton.tsx │ │ │ │ ├── CustomPopper.tsx │ │ │ │ ├── FilterTagMissingInfo.tsx │ │ │ │ ├── MissingTag.tsx │ │ │ │ ├── MissingTagsList.tsx │ │ │ │ ├── Tag.tsx │ │ │ │ ├── TagAdd.tsx │ │ │ │ ├── TagInput.tsx │ │ │ │ ├── Tags.tsx │ │ │ │ └── Wrapper.tsx │ │ │ ├── TranslationDialog.tsx │ │ │ ├── TranslationDialogWrapper.tsx │ │ │ ├── TranslationFields.tsx │ │ │ ├── TranslationTextField.tsx │ │ │ ├── dialogContext │ │ │ │ ├── index.ts │ │ │ │ ├── tools.ts │ │ │ │ ├── useGallery.ts │ │ │ │ └── usePermissions.ts │ │ │ ├── editor │ │ │ │ ├── ControlsEditorSmall.tsx │ │ │ │ ├── Editor.tsx │ │ │ │ ├── EditorWrapper.tsx │ │ │ │ ├── PluralEditor.tsx │ │ │ │ ├── TranslationPlurals.tsx │ │ │ │ └── editorTheme.ts │ │ │ └── languageHelpers.ts │ │ │ ├── ThemeProvider.tsx │ │ │ ├── client │ │ │ ├── HttpError.ts │ │ │ ├── QueryProvider.tsx │ │ │ ├── apiSchema.generated.ts │ │ │ ├── client.ts │ │ │ ├── types.ts │ │ │ └── useQueryApi.ts │ │ │ ├── common │ │ │ ├── FieldTitle.tsx │ │ │ ├── LoadingButton.tsx │ │ │ └── Tooltip.tsx │ │ │ ├── getRootElement.ts │ │ │ ├── screenshots │ │ │ └── ScreenshotPreview.tsx │ │ │ └── tools │ │ │ ├── checkPlatformVersion.test.ts │ │ │ ├── checkPlatformVersion.ts │ │ │ ├── createProvider.tsx │ │ │ ├── isTranslationEmpty.ts │ │ │ ├── limitSurroundingKeys.test.ts │ │ │ ├── limitSurroundingKeys.ts │ │ │ ├── permissions.ts │ │ │ ├── sleep.ts │ │ │ └── validateUrl.ts │ └── vite-env.d.ts │ ├── tools │ └── package.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── tsconfig.prod.json │ ├── types │ ├── index.d.ts │ └── tools.d.ts │ ├── vite.config.production.ts │ ├── vite.config.tools.ts │ └── vite.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── readmeMacros └── macros.njk.md ├── scripts ├── cleanNodeModules.js ├── cleanTurbo.js ├── customLinks.js ├── e2eRunner │ ├── CommandRunner.ts │ ├── CypressRunner.ts │ ├── ServiceMonitor.ts │ ├── config.ts │ ├── index.ts │ ├── log.ts │ ├── serviceRunner │ │ ├── CommandLineServiceRunner.ts │ │ ├── DockerComposeRunner.ts │ │ ├── ServicesRunner.ts │ │ └── checkOutput.ts │ └── types.ts ├── generateReadmes.ts ├── packageJsonRemoveWorkspaces.js ├── packages.test.ts ├── searchRecursively.js ├── testapps.test.ts └── tolgeeUiVersion.js ├── testapps ├── next-app-intl │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── messages │ │ ├── cs.json │ │ ├── de.json │ │ ├── en.json │ │ └── fr.json │ ├── next.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── img │ │ │ ├── appLogo.svg │ │ │ ├── background.svg │ │ │ ├── iconAdd.svg │ │ │ ├── iconMail.svg │ │ │ └── iconShare.svg │ ├── src │ │ ├── app │ │ │ ├── [locale] │ │ │ │ ├── Todos.tsx │ │ │ │ ├── [...rest] │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── translation-methods │ │ │ │ │ ├── TranslationMethodsClient.tsx │ │ │ │ │ ├── TranslationMethodsServer.tsx │ │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── not-found.tsx │ │ │ ├── page.tsx │ │ │ └── style.css │ │ ├── components │ │ │ ├── LangSelector.tsx │ │ │ └── Navbar.tsx │ │ ├── i18n │ │ │ └── request.ts │ │ ├── middleware.ts │ │ ├── navigation.ts │ │ └── tolgee │ │ │ ├── client.tsx │ │ │ ├── server.tsx │ │ │ └── shared.ts │ └── tsconfig.json ├── next-app │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── messages │ │ ├── cs.json │ │ ├── de.json │ │ ├── en.json │ │ └── fr.json │ ├── next-env.d.ts │ ├── next.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── img │ │ │ ├── appLogo.svg │ │ │ ├── background.svg │ │ │ ├── iconAdd.svg │ │ │ ├── iconMail.svg │ │ │ └── iconShare.svg │ ├── src │ │ ├── app │ │ │ ├── Todos.tsx │ │ │ ├── layout.tsx │ │ │ ├── not-found.tsx │ │ │ ├── page.tsx │ │ │ ├── style.css │ │ │ └── translation-methods │ │ │ │ ├── TranslationMethodsClient.tsx │ │ │ │ ├── TranslationMethodsServer.tsx │ │ │ │ └── page.tsx │ │ ├── components │ │ │ ├── LangSelector.tsx │ │ │ └── Navbar.tsx │ │ └── tolgee │ │ │ ├── client.tsx │ │ │ ├── language.ts │ │ │ ├── server.tsx │ │ │ └── shared.ts │ └── tsconfig.json ├── next │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── messages │ │ ├── cs.json │ │ ├── de.json │ │ ├── en.json │ │ ├── fr.json │ │ └── namespaced │ │ │ ├── cs.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── fr.json │ ├── next-env.d.ts │ ├── next.config.js │ ├── package.json │ ├── public │ │ ├── img │ │ │ ├── appLogo.svg │ │ │ ├── background.svg │ │ │ ├── iconAdd.svg │ │ │ ├── iconMail.svg │ │ │ └── iconShare.svg │ │ └── style.css │ ├── src │ │ ├── components │ │ │ ├── LangSelector.tsx │ │ │ ├── Namespaces.tsx │ │ │ └── Navbar.tsx │ │ ├── pages │ │ │ ├── _app.tsx │ │ │ ├── _document.tsx │ │ │ ├── index.tsx │ │ │ └── translation-methods.tsx │ │ ├── tolgee.ts │ │ └── views │ │ │ ├── Todos.tsx │ │ │ └── TranslationMethods.tsx │ └── tsconfig.json ├── ngx │ ├── .editorconfig │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── angular.json │ ├── package.json │ ├── projects │ │ └── sampleapp │ │ │ ├── .browserslistrc │ │ │ ├── karma.conf.js │ │ │ ├── src │ │ │ ├── app │ │ │ │ ├── app-routing.module.ts │ │ │ │ ├── app.component.html │ │ │ │ ├── app.component.ts │ │ │ │ ├── app.module.ts │ │ │ │ ├── component │ │ │ │ │ ├── lang-selector │ │ │ │ │ │ ├── lang-selector.component.html │ │ │ │ │ │ └── lang-selector.component.ts │ │ │ │ │ └── navbar │ │ │ │ │ │ ├── navbar.component.html │ │ │ │ │ │ └── navbar.component.ts │ │ │ │ ├── lazy │ │ │ │ │ ├── lazy-routing.module.ts │ │ │ │ │ ├── lazy.component.html │ │ │ │ │ ├── lazy.component.ts │ │ │ │ │ └── lazy.module.ts │ │ │ │ ├── pages │ │ │ │ │ ├── index │ │ │ │ │ │ ├── index.component.html │ │ │ │ │ │ └── index.component.ts │ │ │ │ │ └── translation-methods │ │ │ │ │ │ ├── translation-methods.component.html │ │ │ │ │ │ └── translation-methods.component.ts │ │ │ │ └── wait.ts │ │ │ ├── assets │ │ │ │ ├── .gitkeep │ │ │ │ └── img │ │ │ │ │ ├── appLogo.svg │ │ │ │ │ ├── background.svg │ │ │ │ │ ├── iconAdd.svg │ │ │ │ │ ├── iconMail.svg │ │ │ │ │ └── iconShare.svg │ │ │ ├── environments │ │ │ │ ├── environment.e2e.ts │ │ │ │ ├── environment.prod.ts │ │ │ │ └── environment.ts │ │ │ ├── i18n │ │ │ │ ├── cs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ ├── fr.json │ │ │ │ └── namespaced │ │ │ │ │ ├── cs.json │ │ │ │ │ ├── de.json │ │ │ │ │ ├── en.json │ │ │ │ │ └── fr.json │ │ │ ├── index.html │ │ │ ├── main.ts │ │ │ ├── polyfills.ts │ │ │ ├── styles.scss │ │ │ └── test.ts │ │ │ ├── tsconfig.app.json │ │ │ └── tsconfig.spec.json │ └── tsconfig.json ├── react-i18next │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ ├── i18n │ │ │ ├── namespaced │ │ │ │ ├── cs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ └── fr.json │ │ │ └── translation │ │ │ │ ├── cs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ └── fr.json │ │ ├── img │ │ │ ├── appLogo.svg │ │ │ ├── background.svg │ │ │ ├── iconAdd.svg │ │ │ ├── iconMail.svg │ │ │ └── iconShare.svg │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ ├── robots.txt │ │ ├── style.css │ │ └── vite.svg │ ├── src │ │ ├── App.tsx │ │ ├── Todos.tsx │ │ ├── TranslationMethods.tsx │ │ ├── components │ │ │ ├── LangSelector.tsx │ │ │ ├── Namespaces.tsx │ │ │ └── Navbar.tsx │ │ ├── main.tsx │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── react │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ ├── i18n │ │ │ ├── cs.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ ├── fr.json │ │ │ └── namespaced │ │ │ │ ├── cs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ └── fr.json │ │ ├── img │ │ │ ├── appLogo.svg │ │ │ ├── background.svg │ │ │ ├── iconAdd.svg │ │ │ ├── iconMail.svg │ │ │ └── iconShare.svg │ │ └── vite.svg │ ├── src │ │ ├── App.tsx │ │ ├── Todos.tsx │ │ ├── TranslationMethods.tsx │ │ ├── components │ │ │ ├── LangSelector.tsx │ │ │ ├── Namespaces.tsx │ │ │ └── Navbar.tsx │ │ ├── main.tsx │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── svelte │ ├── .gitignore │ ├── .npmrc │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── app.d.ts │ │ ├── app.html │ │ ├── component │ │ │ ├── LangSelector.svelte │ │ │ ├── Namespaces.svelte │ │ │ └── Navbar.svelte │ │ ├── lib │ │ │ └── index.ts │ │ └── routes │ │ │ ├── +layout.svelte │ │ │ ├── +page.svelte │ │ │ └── translation-methods │ │ │ └── +page.svelte │ ├── static │ │ ├── favicon.png │ │ ├── i18n │ │ │ ├── cs.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ ├── fr.json │ │ │ └── namespaced │ │ │ │ ├── cs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ └── fr.json │ │ ├── img │ │ │ ├── appLogo.svg │ │ │ ├── background.svg │ │ │ ├── iconAdd.svg │ │ │ ├── iconMail.svg │ │ │ └── iconShare.svg │ │ └── style.css │ ├── svelte.config.js │ ├── tsconfig.json │ └── vite.config.ts ├── vanilla │ ├── .gitignore │ ├── CHANGELOG.md │ ├── apps │ │ ├── base │ │ │ └── index.js │ │ ├── lang_switching │ │ │ └── index.js │ │ └── production │ │ │ └── index.js │ ├── package.json │ ├── public │ │ └── i18n │ │ │ ├── cs.json │ │ │ └── en.json │ └── webpack.config.js ├── vue-i18next │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── package.json │ ├── public │ │ ├── i18n │ │ │ ├── namespaced │ │ │ │ ├── cs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ └── fr.json │ │ │ └── translation │ │ │ │ ├── cs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ └── fr.json │ │ ├── img │ │ │ ├── appLogo.svg │ │ │ ├── background.svg │ │ │ ├── iconAdd.svg │ │ │ ├── iconMail.svg │ │ │ └── iconShare.svg │ │ ├── index.html │ │ └── style.css │ └── src │ │ ├── App.vue │ │ ├── Todos.vue │ │ ├── TranslationMethods.vue │ │ ├── components │ │ ├── LangSelector.vue │ │ └── Navbar.vue │ │ ├── i18n.js │ │ └── main.js ├── vue-ssr │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── assets │ │ └── style.css │ ├── components │ │ ├── LangSelector.vue │ │ ├── Namespaces.vue │ │ ├── Navbar.vue │ │ ├── Todos.vue │ │ └── TranslationMethods.vue │ ├── package.json │ ├── pages │ │ ├── +Layout.vue │ │ ├── +data.ts │ │ ├── index │ │ │ └── +Page.vue │ │ └── translation-methods │ │ │ └── +Page.vue │ ├── public │ │ ├── i18n │ │ │ ├── cs.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ ├── fr.json │ │ │ └── namespaced │ │ │ │ ├── cs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ └── fr.json │ │ └── img │ │ │ ├── appLogo.svg │ │ │ ├── background.svg │ │ │ ├── iconAdd.svg │ │ │ ├── iconMail.svg │ │ │ └── iconShare.svg │ ├── renderer │ │ ├── +config.ts │ │ └── +onCreateApp.ts │ ├── server │ │ ├── index.js │ │ └── root.js │ ├── tolgee.ts │ ├── tsconfig.json │ └── vite.config.ts └── vue │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── env.d.ts │ ├── index.html │ ├── package.json │ ├── public │ ├── i18n │ │ ├── cs.json │ │ ├── de.json │ │ ├── en.json │ │ ├── fr.json │ │ └── namespaced │ │ │ ├── cs.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ └── fr.json │ ├── img │ │ ├── appLogo.svg │ │ ├── background.svg │ │ ├── iconAdd.svg │ │ ├── iconMail.svg │ │ └── iconShare.svg │ ├── index.html │ └── style.css │ ├── src │ ├── App.vue │ ├── Todos.vue │ ├── TranslationMethods.vue │ ├── components │ │ ├── LangSelector.vue │ │ ├── Namespaces.vue │ │ └── Navbar.vue │ ├── main.ts │ └── shims-vue.d.ts │ ├── tsconfig.config.json │ ├── tsconfig.json │ └── vite.config.ts ├── tsconfig.json └── turbo.json /.github/scripts/update-readme.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | project="$1" 5 | app_dir="testapps/$project" 6 | 7 | header="

8 | 🚨🚨🚨 This repo is just a dummy 🚨🚨🚨
9 | Submit issues in the 10 | monorepo 11 | or 12 | check the source code here. 13 |

14 | " 15 | 16 | tmp=$(mktemp) 17 | echo "$header" | cat - "$app_dir/README.md" > "$tmp" 18 | mv "$tmp" "$app_dir/README.md" -------------------------------------------------------------------------------- /.github/workflows/auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: auto-merge 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | auto-merge: 7 | runs-on: ubuntu-latest 8 | if: github.actor == 'dependabot[bot]' 9 | steps: 10 | - uses: actions/checkout@v4 11 | - uses: ahmadnassri/action-dependabot-auto-merge@v2 12 | with: 13 | config: 'dummy-config' 14 | botName: tolgee 15 | approve: true 16 | target: minor 17 | github-token: '${{ secrets.TOLGEE_MACHINE_PAT }}' 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.iml 3 | **/package.json.lerna_backup 4 | **/.DS_Store 5 | **/.vscode 6 | .gradle 7 | .idea 8 | **/.turbo 9 | **/'.turbo' 10 | .pnpm-store 11 | .VERSION 12 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | #pull_request_rules: 2 | # - name: automatic merge for Dependabot pull requests 3 | # conditions: 4 | # - author~=^dependabot\[bot\]$ 5 | # - check-success=Test 6 | # - title~=Bump [^\s]+ from ([\d]+)\..+ to \1\. 7 | # actions: 8 | # merge: 9 | # method: rebase 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | strict-peer-dependencies=false 2 | store-dir=.pnpm-store 3 | auto-install-peers=true 4 | 5 | # jest completely not working without this 6 | shamefully-hoist=true 7 | prefer-workspace-packages=true 8 | save-workspace-protocol=false -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/build 2 | **/dist 3 | ./*/*/lib 4 | 5 | **/*.json 6 | 7 | **/*.generated.* 8 | **/*.md 9 | testapps/next/.next 10 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | exclude: 2 | global: 3 | # exclude unit tests 4 | - '**/*.spec.*' 5 | - '**/*.test.*' 6 | # exclude e2e tests 7 | - '**/e2e/**' 8 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG nodever=20 2 | FROM node:${nodever}-alpine 3 | 4 | # gatsby needs to have access to user directory 5 | RUN chmod -R 777 /root 6 | 7 | WORKDIR /data 8 | 9 | COPY wait-for-file / 10 | -------------------------------------------------------------------------------- /docker/Dockerfile.builder: -------------------------------------------------------------------------------- 1 | ARG nodever=20 2 | FROM node:${nodever} 3 | 4 | RUN npm install -g pnpm 5 | 6 | WORKDIR /data -------------------------------------------------------------------------------- /docker/Dockerfile.with-build: -------------------------------------------------------------------------------- 1 | ARG nodever=20 2 | FROM node:${nodever} 3 | 4 | RUN npm install -g pnpm 5 | 6 | # Files required by pnpm install 7 | COPY .npmrc package.json pnpm-lock.yaml /data/ 8 | 9 | WORKDIR /data 10 | 11 | RUN pnpm fetch 12 | 13 | COPY . /data 14 | 15 | RUN pnpm install 16 | 17 | RUN pnpm build -------------------------------------------------------------------------------- /docker/wait-for-file: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | file="$1" 4 | shift 5 | cmd="$@" 6 | 7 | until [ -f "$file" ]; do 8 | >&2 echo "File $file does not exist" 9 | sleep 1 10 | done -------------------------------------------------------------------------------- /e2e/.gitignore: -------------------------------------------------------------------------------- 1 | cypress/screenshots 2 | cypress/videos 3 | cypress/downloads 4 | node_modules 5 | testapps/dist 6 | extension -------------------------------------------------------------------------------- /e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | import { defineConfig } from 'cypress'; 3 | 4 | export default defineConfig({ 5 | e2e: { 6 | // We've imported your old cypress plugins here. 7 | // You may want to clean this up later by importing these. 8 | setupNodeEvents(on, config) { 9 | // @ts-ignore 10 | return require('./cypress/plugins/index.js')(on, config); 11 | }, 12 | }, 13 | }); 14 | -------------------------------------------------------------------------------- /e2e/cypress/common/constants.ts: -------------------------------------------------------------------------------- 1 | export const PASSWORD = Cypress.env('DEFAULT_PASSWORD') || 'admin'; 2 | export const USERNAME = Cypress.env('DEFAULT_USERNAME') || 'admin'; 3 | export const API_URL = Cypress.env('API_URL') || 'http://localhost:8202'; 4 | -------------------------------------------------------------------------------- /e2e/cypress/common/devUiTools.ts: -------------------------------------------------------------------------------- 1 | export const getDevUiRoot = () => { 2 | return cy.get('#__tolgee_dev_tools'); 3 | }; 4 | 5 | export const getDevUi = () => { 6 | return getDevUiRoot().shadow().find('div').first(); 7 | }; 8 | -------------------------------------------------------------------------------- /e2e/cypress/common/selectors.ts: -------------------------------------------------------------------------------- 1 | import { getDevUi } from './devUiTools'; 2 | 3 | export const getByAriaLabel = (label: string) => { 4 | return getDevUi().find(`*[aria-label="${label}"]`); 5 | }; 6 | 7 | export const gcyWithCustom = ( 8 | { value, ...other }: { value: string; [key: string]: string }, 9 | options?: Parameters[1] 10 | ) => 11 | cy.get( 12 | `[data-cy="${value}"]${Object.entries(other) 13 | .map(([key, value]) => `[data-cy-${key}="${value}"]`) 14 | .join('')}`, 15 | options 16 | ); 17 | -------------------------------------------------------------------------------- /e2e/cypress/common/types.ts: -------------------------------------------------------------------------------- 1 | export type Scope = 2 | | 'translations.view' 3 | | 'translations.edit' 4 | | 'keys.edit' 5 | | 'screenshots.view' 6 | | 'screenshots.upload' 7 | | 'screenshots.delete'; 8 | 9 | // eslint-disable-next-line @typescript-eslint/ban-types 10 | export type ArgumentTypes = F extends ( 11 | ...args: infer A 12 | ) => any 13 | ? A 14 | : never; 15 | -------------------------------------------------------------------------------- /e2e/cypress/e2e/vanilla/base.cy.ts: -------------------------------------------------------------------------------- 1 | context('Base test', () => { 2 | beforeEach(() => { 3 | cy.visit('http://localhost:8101/base/'); 4 | }); 5 | 6 | it('is working', () => { 7 | const xpath = cy.xpath("//*[contains(text(), 'This is test text!')]"); 8 | xpath.should('have.length', 2); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /e2e/cypress/e2e/vanilla/lang_switching.cy.ts: -------------------------------------------------------------------------------- 1 | context('Base test', () => { 2 | beforeEach(() => { 3 | cy.visit('http://localhost:8101/lang_switching/'); 4 | }); 5 | 6 | it('stores current language', () => { 7 | cy.contains('This is test text!').should('be.visible'); 8 | cy.contains('cs').click(); 9 | cy.contains('Toto je text').should('be.visible'); 10 | cy.reload(); 11 | cy.contains('Toto je text').should('be.visible'); 12 | cy.contains('This is just in english.').should('be.visible'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /e2e/cypress/e2e/vanilla/production.cy.ts: -------------------------------------------------------------------------------- 1 | context('Production test', () => { 2 | beforeEach(() => { 3 | cy.visit('http://localhost:8101/production/'); 4 | }); 5 | 6 | it('has text with parameter', () => { 7 | cy.contains('Toto je text s parametrem: value.').should('be.visible'); 8 | }); 9 | 10 | it('switches language', () => { 11 | cy.wait(200); 12 | cy.get('button').contains('en').click(); 13 | cy.contains('This is test text!').should('be.visible'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /e2e/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /e2e/cypress/support/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Cypress { 2 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 3 | interface Chainable { 4 | closestDcy(dataCy: string): Chainable; 5 | 6 | gcy(dataCy: string): Chainable; 7 | 8 | findDcy(dataCy: string): Chainable; 9 | 10 | findDcyWithCustom( 11 | params: { value: string; [key: string]: string }, 12 | options?: Parameters[1] 13 | ): Chainable; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /e2e/cypress/support/e2e.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | require('cypress-xpath'); 19 | 20 | // Alternatively you can use CommonJS syntax: 21 | // require('./commands') 22 | -------------------------------------------------------------------------------- /e2e/cypress/support/index.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Cypress { 2 | interface Chainable { 3 | promisify(): Promise; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /e2e/import-data/examples/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}", 12 | "value": "hodnota" 13 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}", 12 | "value": "Wert" 13 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}", 12 | "value": "value" 13 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}", 12 | "value": "valeur" 13 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/translation/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/translation/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/translation/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /e2e/import-data/examples/translation/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /e2e/scripts/startCypress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -x 3 | 4 | ARGS="--browser chrome --headed" 5 | 6 | if [ -n "$E2E_APP" ]; then 7 | npx cypress run $ARGS --spec "cypress/e2e/$E2E_APP/**" 8 | else 9 | npx cypress run $ARGS 10 | fi -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "lib": ["es5", "dom", "es2020"], 5 | "types": ["cypress", "cypress-xpath/src", "cypress-real-events"], 6 | "checkJs": false, 7 | "allowJs": true 8 | }, 9 | "include": ["**/*.ts", "cypress/plugins/index.js"] 10 | } 11 | -------------------------------------------------------------------------------- /jest.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | preset: 'ts-jest', 3 | roots: ['scripts'], 4 | }; 5 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "6.2.5", 3 | "command": { 4 | "publish": { 5 | "conventionalCommits": true 6 | }, 7 | "version": { 8 | "message": "%s [skip ci]", 9 | "conventionalCommits": true 10 | } 11 | }, 12 | "ignoreChanges": [ 13 | "**/*.test.ts", 14 | "**/*.spec.ts", 15 | "**/*.test.tsx", 16 | "**/*.spec.tsx", 17 | "**/package-lock.json" 18 | ] 19 | } -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /lib 5 | /coverage 6 | stats.html 7 | 8 | 9 | # local env files 10 | .env.local 11 | .env.*.local 12 | 13 | # Log files 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | pnpm-debug.log* 18 | 19 | # Editor directories and files 20 | .idea 21 | .vscode 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | -------------------------------------------------------------------------------- /packages/core/jest.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | preset: 'ts-jest', 3 | roots: ['src'], 4 | testEnvironment: 'jsdom', 5 | setupFilesAfterEnv: ['./src/__test/jest-setup.ts'], 6 | }; 7 | -------------------------------------------------------------------------------- /packages/core/src/Controller/ValueObserver.ts: -------------------------------------------------------------------------------- 1 | export const ValueObserver = ( 2 | initialValue: T, 3 | valueGetter: () => T, 4 | handler: (value: T) => void 5 | ): ValueObserverInstance => { 6 | let previousValue: T = initialValue; 7 | 8 | return Object.freeze({ 9 | init(value: T) { 10 | previousValue = value; 11 | }, 12 | notify() { 13 | const value = valueGetter(); 14 | if (previousValue !== value) { 15 | handler(value); 16 | } 17 | previousValue = value; 18 | }, 19 | }); 20 | }; 21 | 22 | export type ValueObserverInstance = { 23 | readonly init: (value: T) => void; 24 | readonly notify: () => void; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/core/src/FormatSimple/FormatSimple.ts: -------------------------------------------------------------------------------- 1 | import { formatter } from './formatter'; 2 | import { FinalFormatterMiddleware, TolgeePlugin } from '../types'; 3 | 4 | function createFormatSimple(): FinalFormatterMiddleware { 5 | return { 6 | format: ({ translation, params }) => formatter(translation, params), 7 | }; 8 | } 9 | 10 | export const FormatSimple = (): TolgeePlugin => (tolgee, tools) => { 11 | tools.setFinalFormatter(createFormatSimple()); 12 | return tolgee; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/core/src/FormatSimple/formatter.ts: -------------------------------------------------------------------------------- 1 | import { DefaultParamType, TranslateParams } from '../types'; 2 | import { formatParser } from './formatParser'; 3 | 4 | export function formatter( 5 | translation: string, 6 | params?: TranslateParams 7 | ) { 8 | const [texts, pars] = formatParser(translation); 9 | const result = [texts[0]]; 10 | for (let i = 1; i < texts.length; i++) { 11 | const parameter = params?.[pars[i - 1]]; 12 | if (parameter === undefined) { 13 | throw new Error(`Missing parameter "${pars[i - 1]}" in "${translation}"`); 14 | } 15 | result.push(String(parameter)); 16 | result.push(texts[i]); 17 | } 18 | return result.join(''); 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/__test/format.simple.test.ts: -------------------------------------------------------------------------------- 1 | import { FormatSimple } from '../FormatSimple/FormatSimple'; 2 | import { TolgeeCore } from '../TolgeeCore'; 3 | 4 | describe('format simple', () => { 5 | it('works with parameters', () => { 6 | const tolgee = TolgeeCore() 7 | .use(FormatSimple()) 8 | .init({ 9 | language: 'en', 10 | staticData: { en: { apples: 'Bob has { num } apples' } }, 11 | }); 12 | expect(tolgee.t('apples', { num: 7 })).toEqual('Bob has 7 apples'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/core/src/__test/jest-setup.ts: -------------------------------------------------------------------------------- 1 | // In your own jest-setup.js (or any other name) 2 | import '@testing-library/jest-dom'; 3 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export { getFallback, getFallbackArray, createFetchFunction } from './helpers'; 2 | export { TolgeeCore } from './TolgeeCore'; 3 | export * from './types'; 4 | export { getTranslateProps } from './TranslateParams'; 5 | export { FormatSimple } from './FormatSimple/FormatSimple'; 6 | -------------------------------------------------------------------------------- /packages/core/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './general'; 2 | export * from './events'; 3 | export * from './cache'; 4 | export * from './plugin'; 5 | export * from './errors'; 6 | 7 | export type { 8 | State, 9 | TolgeeOptions, 10 | TolgeeOptionsInternal, 11 | TolgeeStaticData, 12 | TolgeeStaticDataProp, 13 | } from '../Controller/State/initState'; 14 | 15 | export type { 16 | ObserverOptions, 17 | ObserverOptionsInternal, 18 | ModifierKey, 19 | } from '../Controller/State/observerOptions'; 20 | 21 | export type { TolgeeChainer, TolgeeInstance } from '../TolgeeCore'; 22 | -------------------------------------------------------------------------------- /packages/core/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "compilerOptions": { 4 | "noEmit": false 5 | }, 6 | "include": ["src/index.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/format-icu/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /lib 5 | /coverage 6 | stats.html 7 | 8 | 9 | # local env files 10 | .env.local 11 | .env.*.local 12 | 13 | # Log files 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | pnpm-debug.log* 18 | 19 | # Editor directories and files 20 | .idea 21 | .vscode 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | -------------------------------------------------------------------------------- /packages/format-icu/jest.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | preset: 'ts-jest', 3 | roots: ['src'], 4 | testEnvironment: 'jsdom', 5 | }; 6 | -------------------------------------------------------------------------------- /packages/format-icu/src/FormatIcu.ts: -------------------------------------------------------------------------------- 1 | import { TolgeePlugin } from '@tolgee/core'; 2 | import { createFormatIcu } from './createFormatIcu'; 3 | 4 | export const FormatIcu = (): TolgeePlugin => (tolgee, tools) => { 5 | tools.setFinalFormatter(createFormatIcu()); 6 | return tolgee; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/format-icu/src/createFormatIcu.test.ts: -------------------------------------------------------------------------------- 1 | jest.autoMockOff(); 2 | import { createFormatIcu } from './createFormatIcu'; 3 | 4 | describe('format icu', () => { 5 | it('formats simple string', () => { 6 | const formatter = createFormatIcu(); 7 | const result = formatter.format({ 8 | translation: 'result is {number, number}', 9 | params: { number: 42000 }, 10 | language: 'en', 11 | }); 12 | expect(result).toEqual('result is 42,000'); 13 | }); 14 | 15 | it('fixes invalid language', () => { 16 | const formatter = createFormatIcu() as any; 17 | expect(formatter.getLanguage('en_GB')).toEqual('en-GB'); 18 | expect(formatter.getLanguage('en_GB-nonsenceeeee')).toEqual('en-GB'); 19 | expect(formatter.getLanguage('cs CZ')).toEqual('cs-CZ'); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/format-icu/src/index.ts: -------------------------------------------------------------------------------- 1 | export { FormatIcu } from './FormatIcu'; 2 | -------------------------------------------------------------------------------- /packages/format-icu/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "include": ["src/index.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/i18next/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /lib 5 | /coverage 6 | 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | pnpm-debug.log* 17 | 18 | # Editor directories and files 19 | .idea 20 | .vscode 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? -------------------------------------------------------------------------------- /packages/i18next/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (process.env.NODE_ENV === 'production') { 4 | module.exports = require('./dist/tolgee-i18next.cjs.min.js'); 5 | } else { 6 | module.exports = require('./dist/tolgee-i18next.cjs.js'); 7 | } 8 | -------------------------------------------------------------------------------- /packages/i18next/jest.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | automock: true, 3 | preset: 'ts-jest', 4 | testEnvironment: 'jsdom', 5 | roots: ['src'], 6 | unmockedModulePathPatterns: [ 7 | '/src/__testFixtures/*', 8 | '/node_modules/*', 9 | ], 10 | moduleNameMapper: { 11 | '@testFixtures/(.*)': '/src/__testFixtures/$1', 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /packages/i18next/src/I18nextPlugin.ts: -------------------------------------------------------------------------------- 1 | import { TolgeePlugin } from '@tolgee/web'; 2 | 3 | export const I18nextPlugin = (): TolgeePlugin => (tolgee) => { 4 | tolgee.updateOptions({ autoLoadRequiredData: false }); 5 | return tolgee; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/i18next/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './withTolgee'; 2 | export * from './tolgeeApply'; 3 | export * from './tolgeeOptions'; 4 | export * from './tolgeeBackend'; 5 | export * from './tolgeeProcessor'; 6 | export * from './I18nextPlugin'; 7 | 8 | export * from '@tolgee/web'; 9 | -------------------------------------------------------------------------------- /packages/i18next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "moduleResolution": "node", 5 | "module": "esnext", 6 | "sourceMap": true, 7 | "declaration": true, 8 | "rootDir": "src", 9 | "emitDeclarationOnly": true, 10 | "outDir": "lib", 11 | "lib": ["es2015", "es2018", "es2020", "dom"], 12 | "experimentalDecorators": true, 13 | "emitDecoratorMetadata": true, 14 | "preserveSymlinks": true, 15 | "skipLibCheck": true, 16 | "jsx": "react", 17 | "downlevelIteration": true, 18 | "esModuleInterop": true, 19 | "paths": { 20 | "tolgee/ui": ["./ui"], 21 | "tolgee/core": ["./core"], 22 | "@testFixtures/*": ["./__testFixtures/*"] 23 | } 24 | }, 25 | "include": ["src"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /packages/i18next/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "include": ["src/index.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/ngx/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'jest-preset-angular', 3 | setupFilesAfterEnv: ['/src/test-setup.ts'], 4 | globalSetup: 'jest-preset-angular/global-setup', 5 | }; 6 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/ngx-tolgee", 4 | "lib": { 5 | "entryFile": "src/public-api.ts" 6 | }, 7 | "allowedNonPeerDependencies": [ 8 | "@tolgee/web" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tolgee/ngx", 3 | "description": "Angular integration of Tolgee localization tool", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/tolgee/tolgee-js" 7 | }, 8 | "scripts": { 9 | "build": "ng build --configuration production" 10 | }, 11 | "dependencies": { 12 | "@tolgee/web": "6.2.5" 13 | }, 14 | "version": "6.2.5", 15 | "publishConfig": { 16 | "directory": "../../dist/ngx-tolgee", 17 | "access": "public" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/src/__integration/resolving/root.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'root', 5 | template: ` 6 | Root 7 | Lazy 8 | 9 | `, 10 | }) 11 | export class RootComponent {} 12 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/src/lib/loader.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | template: ` 5 |
6 | `, 7 | standalone: false, 8 | }) 9 | export class LoaderComponent { 10 | @Input() html: string | undefined; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/src/lib/ngx-tolgee.module.ts: -------------------------------------------------------------------------------- 1 | import { APP_INITIALIZER, NgModule } from '@angular/core'; 2 | import { TranslatePipe } from './translate.pipe'; 3 | import { TComponent } from './t.component'; 4 | import { TranslateService } from './translate.service'; 5 | import { LoaderComponent } from "./loader.component"; 6 | 7 | @NgModule({ 8 | declarations: [TranslatePipe, TComponent, LoaderComponent], 9 | exports: [TranslatePipe, TComponent], 10 | providers: [ 11 | { 12 | provide: APP_INITIALIZER, 13 | useFactory: (service: TranslateService) => { 14 | return async () => await service.start(); 15 | }, 16 | deps: [TranslateService], 17 | multi: true, 18 | }, 19 | ], 20 | }) 21 | export class NgxTolgeeModule {} 22 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/src/lib/tolgee-instance-token.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { TolgeeInstance } from '@tolgee/web'; 3 | 4 | export const TOLGEE_INSTANCE = new InjectionToken( 5 | 'tolgee.instance' 6 | ); 7 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ngx-tolgee 3 | */ 4 | export * from './lib/translate.service'; 5 | export * from './lib/translate.pipe'; 6 | export * from './lib/t.component'; 7 | 8 | export * from './lib/ngx-tolgee.module'; 9 | export * from './lib/tolgee-instance-token'; 10 | 11 | export * from '@tolgee/web'; 12 | export * from './lib/namespace.resolver'; 13 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | import '@testing-library/jest-dom'; 3 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "declarationMap": true, 6 | "target": "es2020", 7 | "declaration": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "fullTemplateTypeCheck": true, 16 | "strictInjectionParameters": true, 17 | "enableResourceInlining": true 18 | }, 19 | "exclude": ["src/test.ts", "**/*.spec.ts", "src/__mocks/**"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": {} 7 | } 8 | -------------------------------------------------------------------------------- /packages/ngx/projects/ngx-tolgee/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc/spec", 5 | "module": "CommonJs", 6 | "types": [ 7 | "node", 8 | "jest", 9 | "@testing-library/jest-dom" 10 | ] 11 | }, 12 | "include": [ 13 | "src/**/*.spec.ts", 14 | "src/**/*.d.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/react/.buildversions: -------------------------------------------------------------------------------- 1 | CORE_VERSION=1.0.0-alpha.12 -------------------------------------------------------------------------------- /packages/react/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /lib 5 | /coverage 6 | stats.html 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | pnpm-debug.log* 17 | 18 | # Editor directories and files 19 | .idea 20 | .vscode 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? -------------------------------------------------------------------------------- /packages/react/jest.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jsdom', 4 | unmockedModulePathPatterns: ['/node_modules/*'], 5 | modulePathIgnorePatterns: ['cypress'], 6 | transformIgnorePatterns: ['node_modules/(?!@tolgee/web)'], 7 | roots: ['src'], 8 | globals: { 9 | 'ts-jest': { 10 | tsconfig: 'tsconfig.spec.json', 11 | }, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /packages/react/src/GlobalContextPlugin.tsx: -------------------------------------------------------------------------------- 1 | import type { TolgeePlugin } from '@tolgee/web'; 2 | import { DEFAULT_REACT_OPTIONS } from './TolgeeProvider'; 3 | import type { ReactOptions, TolgeeReactContext } from './types'; 4 | 5 | let globalContext: TolgeeReactContext | undefined; 6 | 7 | export const GlobalContextPlugin = 8 | (options?: Partial): TolgeePlugin => 9 | (tolgee) => { 10 | globalContext = { 11 | tolgee, 12 | options: { ...DEFAULT_REACT_OPTIONS, ...options }, 13 | }; 14 | return tolgee; 15 | }; 16 | 17 | export function getGlobalContext() { 18 | return globalContext; 19 | } 20 | -------------------------------------------------------------------------------- /packages/react/src/T.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ParamsTags, TProps } from './types'; 3 | 4 | import { useTranslateInternal } from './useTranslateInternal'; 5 | import { TFnType } from '@tolgee/web'; 6 | import { TBase } from './TBase'; 7 | 8 | interface TInterface { 9 | (props: TProps): JSX.Element; 10 | } 11 | 12 | export const T: TInterface = (props) => { 13 | const { t } = useTranslateInternal(); 14 | 15 | return } {...props} />; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/react/src/hooks.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useState } from 'react'; 2 | 3 | export const useRerender = () => { 4 | const [instance, setCounter] = useState(0); 5 | 6 | const rerender = useCallback(() => { 7 | setCounter((num) => num + 1); 8 | }, [setCounter]); 9 | return { instance, rerender }; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react/src/index.ts: -------------------------------------------------------------------------------- 1 | export { useTranslate, UseTranslateResult } from './useTranslate'; 2 | export { 3 | TolgeeProvider, 4 | TolgeeProviderProps, 5 | getProviderInstance, 6 | } from './TolgeeProvider'; 7 | export { T } from './T'; 8 | export { useTolgee } from './useTolgee'; 9 | export { GlobalContextPlugin } from './GlobalContextPlugin'; 10 | export { useTolgeeSSR } from './useTolgeeSSR'; 11 | export { TBase } from './TBase'; 12 | export * from './types'; 13 | 14 | export * from '@tolgee/web'; 15 | -------------------------------------------------------------------------------- /packages/react/src/server.ts: -------------------------------------------------------------------------------- 1 | export { TBase } from './TBase'; 2 | export * from './types'; 3 | export * from './createServerInstance'; 4 | 5 | export * from '@tolgee/web'; 6 | -------------------------------------------------------------------------------- /packages/react/src/useTolgee.ts: -------------------------------------------------------------------------------- 1 | import { TolgeeEvent, TolgeeInstance } from '@tolgee/web'; 2 | import { useEffect } from 'react'; 3 | import { useRerender } from './hooks'; 4 | import { useTolgeeContext } from './useTolgeeContext'; 5 | 6 | export const useTolgee = (events?: TolgeeEvent[]): TolgeeInstance => { 7 | const { tolgee } = useTolgeeContext(); 8 | 9 | const { rerender } = useRerender(); 10 | 11 | useEffect(() => { 12 | const listeners = events?.map((e) => tolgee.on(e, rerender)); 13 | return () => { 14 | listeners?.forEach((listener) => listener.unsubscribe()); 15 | }; 16 | }, [events?.join(':')]); 17 | 18 | return tolgee; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/react/src/useTolgeeContext.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { getGlobalContext } from './GlobalContextPlugin'; 3 | import { getProviderInstance } from './TolgeeProvider'; 4 | 5 | export const useTolgeeContext = () => { 6 | const TolgeeProviderContext = getProviderInstance(); 7 | const context = useContext(TolgeeProviderContext) || getGlobalContext(); 8 | if (!context) { 9 | throw new Error( 10 | "Couldn't find tolgee instance, did you forgot to use `TolgeeProvider`?" 11 | ); 12 | } 13 | return context; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "declaration": true, 6 | "outDir": "./lib", 7 | "moduleResolution": "node", 8 | "skipLibCheck": true, 9 | "lib": [ 10 | "es2018", 11 | "es2020", 12 | "dom" 13 | ], 14 | "experimentalDecorators": true, 15 | "emitDecoratorMetadata": true, 16 | "emitDeclarationOnly": true, 17 | "esModuleInterop": true, 18 | "strict": true, 19 | "jsx": "react", 20 | "downlevelIteration": true, 21 | "paths": {} 22 | }, 23 | "include": [ 24 | "./src/**/*.ts" 25 | ], 26 | "exclude": [ 27 | "node_modules" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /packages/react/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "include": ["src/index.ts", "src/server.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/react/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "include": ["src/**/*.ts?"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/svelte/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | /.svelte-kit 7 | /build 8 | /dist 9 | 10 | # OS 11 | .DS_Store 12 | Thumbs.db 13 | 14 | # Env 15 | .env 16 | .env.* 17 | !.env.example 18 | !.env.test 19 | 20 | # Vite 21 | vite.config.js.timestamp-* 22 | vite.config.ts.timestamp-* 23 | -------------------------------------------------------------------------------- /packages/svelte/.prettierignore: -------------------------------------------------------------------------------- 1 | # Package Managers 2 | package-lock.json 3 | pnpm-lock.yaml 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /packages/svelte/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 8 | } 9 | -------------------------------------------------------------------------------- /packages/svelte/src/app.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // See https://kit.svelte.dev/docs/types#app 4 | // for information about these interfaces 5 | // and what to do when importing types 6 | declare namespace App { 7 | // interface Locals {} 8 | // interface Platform {} 9 | // interface PrivateEnv {} 10 | // interface PublicEnv {} 11 | } 12 | -------------------------------------------------------------------------------- /packages/svelte/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/GlobalContextPlugin.ts: -------------------------------------------------------------------------------- 1 | import type { TolgeePlugin } from '@tolgee/web'; 2 | import type { TolgeeSvelteContext } from './types'; 3 | 4 | let globalContext: TolgeeSvelteContext | undefined; 5 | 6 | export const GlobalContextPlugin = (): TolgeePlugin => (tolgee) => { 7 | globalContext = { 8 | tolgee 9 | }; 10 | return tolgee; 11 | }; 12 | 13 | export function getGlobalContext() { 14 | return globalContext; 15 | } 16 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/T.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | {$t({ 20 | key: keyName, 21 | params: params, 22 | noWrap: noWrap, 23 | defaultValue: defaultValue, 24 | ns, 25 | language 26 | })} 27 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/TolgeeProvider.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 | {#if !isLoading} 24 | 25 | {:else if fallback} 26 | {fallback} 27 | {:else} 28 | 29 | {/if} 30 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/__integration/components/Namespaces.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | {#if $isLoading} 8 |
Loading...
9 | {/if} 10 |
{$t('test')}
11 |
12 | {$t('test_english_fallback')} 13 |
14 |
15 | {$t('non_existant', 'Non existant')} 16 |
17 |
18 | {$t('fallback', { ns: 'invalid' })} 19 |
20 |
21 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/__integration/components/TestGetTolgee.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 |
{String($tolgee.getLanguage())}
11 |
{String($tolgee.getPendingLanguage())}
12 |
{String($tolgee.isFetching())}
13 |
{String($tolgee.isLoading())}
14 |
{String($tolgee.isInitialLoading())}
15 |
{String($tolgee.isRunning())}
16 |
17 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/__integration/components/TestProviderComponent.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 |
9 |
10 | 11 |
12 |
13 | 14 |
15 |
16 | 17 |
18 |
19 | Loading... 20 |
21 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/__integration/components/TestTranslateComponent.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | Loading... 12 | 13 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/__integration/components/TestTranslateComponentInside.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 |
8 | {$t('peter_dogs', { dogsCount: 5 })} 9 |
10 |
11 | {$t('hello_world')} 12 |
13 |
14 | {$t({ key: 'hello_world', noWrap: true })} 15 |
16 |
17 | {$t('non_existant', 'Non existant')} 18 |
19 |
20 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/__integration/mockCoreFetch.ts: -------------------------------------------------------------------------------- 1 | import 'node-fetch'; 2 | import { getMocker } from '@tolgee/testing/mockData.js'; 3 | import createFetchMock from 'vitest-fetch-mock'; 4 | import { vi } from 'vitest'; 5 | 6 | const fetchMocker = createFetchMock(vi); 7 | 8 | export const mockCoreFetch = () => { 9 | const mocker = getMocker(); 10 | 11 | const fetch = fetchMocker.mockResponse((req) => { 12 | return mocker.getDataForUrl(req.url); 13 | }); 14 | 15 | return { ...mocker.mockData, fetch, resolveAll: mocker.resolveAll }; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/__testUtil/TolgeeProviderFallback.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 |
It's rendered!
10 |
11 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/__testUtil/TolgeeProviderSlotTest.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 |
loading
10 |
It's rendered!
11 |
12 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/getTolgee.ts: -------------------------------------------------------------------------------- 1 | import { readable } from 'svelte/store'; 2 | import type { TolgeeEvent } from '@tolgee/web'; 3 | import { getTolgeeContext } from './getTolgeeContext'; 4 | 5 | export const getTolgee = (events?: TolgeeEvent[]) => { 6 | const tolgeeContext = getTolgeeContext(); 7 | 8 | const tolgee = tolgeeContext.tolgee; 9 | 10 | const { subscribe } = readable(tolgee, (set) => { 11 | const listeners = events?.map((e) => 12 | tolgee.on(e, () => { 13 | set({ ...tolgee }); 14 | }) 15 | ); 16 | 17 | return () => listeners?.forEach((listener) => listener.unsubscribe()); 18 | }); 19 | 20 | return { subscribe, value: tolgee }; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/getTolgeeContext.ts: -------------------------------------------------------------------------------- 1 | import { getContext } from 'svelte'; 2 | import { getGlobalContext } from './GlobalContextPlugin'; 3 | import type { TolgeeSvelteContext } from './types'; 4 | 5 | /** 6 | * Returns Tolgee context. 7 | * @throws Error when context is not defined. 8 | */ 9 | export const getTolgeeContext = (): TolgeeSvelteContext => { 10 | const context = (getContext('tolgeeContext') || getGlobalContext()) as TolgeeSvelteContext; 11 | if (context === undefined) { 12 | throw Error( 13 | 'Tolgee context is undefined. Trying to use getTranslate method or T component outside TolgeeProvider?' 14 | ); 15 | } 16 | return context; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { default as T } from './T.svelte'; 2 | export { default as getTranslate } from './getTranslate'; 3 | export { default as TolgeeProvider } from './TolgeeProvider.svelte'; 4 | export { getTolgeeContext } from './getTolgeeContext'; 5 | export { GlobalContextPlugin } from './GlobalContextPlugin'; 6 | export { getTolgee } from './getTolgee'; 7 | 8 | export * from '@tolgee/web'; 9 | -------------------------------------------------------------------------------- /packages/svelte/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import type { TolgeeInstance } from '@tolgee/web'; 2 | 3 | export type TolgeeSvelteContext = { 4 | tolgee: TolgeeInstance; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/svelte/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 |

Welcome to your library project

2 |

Create your package using @sveltejs/package and preview/showcase your work with SvelteKit

3 |

Visit kit.svelte.dev to read the documentation

4 | -------------------------------------------------------------------------------- /packages/svelte/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolgee/tolgee-js/ea8ffc97dcfec4a1ea7b06abde18d35e208cfe91/packages/svelte/static/favicon.png -------------------------------------------------------------------------------- /packages/svelte/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported, or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /packages/svelte/tests/setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/vitest'; 2 | -------------------------------------------------------------------------------- /packages/svelte/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node" 14 | }, 15 | "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte", "jest-setup.ts"] 16 | } 17 | -------------------------------------------------------------------------------- /packages/svelte/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | import { svelteTesting } from '@testing-library/svelte/vite'; 4 | 5 | export default defineConfig({ 6 | plugins: [sveltekit(), svelteTesting()], 7 | test: { 8 | include: ['src/**/*.{test,spec}.{js,ts}'], 9 | setupFiles: ['./tests/setup.ts'], 10 | globals: true, 11 | environment: 'jsdom' 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /packages/testing/createResolvablePromise.ts: -------------------------------------------------------------------------------- 1 | export const createResolvablePromise = ( 2 | data: T 3 | ): { promise: Promise; resolve: () => void } => { 4 | let resolve: (data: T) => void; 5 | return { 6 | promise: new Promise((resolveArg) => { 7 | resolve = resolveArg; 8 | }), 9 | resolve: () => resolve(data), 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/testing/currentApiKeyMock.ts: -------------------------------------------------------------------------------- 1 | export const currentApiKeyMock = { 2 | id: 42, 3 | key: 'asdfasdsfasdfasdfasdf', 4 | username: 'john@toe@tolgee.com', 5 | userFullName: 'John Doe', 6 | projectId: 15, 7 | projectName: 'Tolgee test', 8 | scopes: [ 9 | 'screenshots.view', 10 | 'screenshots.upload', 11 | 'screenshots.delete', 12 | 'keys.edit', 13 | 'translations.edit', 14 | 'translations.view', 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /packages/testing/fetchMock.ts: -------------------------------------------------------------------------------- 1 | import fetchMock from 'jest-fetch-mock'; 2 | import { getMocker } from './mockData'; 3 | 4 | export const mockCoreFetch = () => { 5 | const asyncFetchResult = mockCoreFetchAsync(); 6 | asyncFetchResult.resolveAll(); 7 | return asyncFetchResult.fetch; 8 | }; 9 | 10 | export const mockCoreFetchAsync = () => { 11 | const mocker = getMocker(); 12 | 13 | const fetch = fetchMock.mockResponse((req) => { 14 | return mocker.getDataForUrl(req.url); 15 | }); 16 | 17 | return { ...mocker.mockData, fetch, resolveAll: mocker.resolveAll }; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/testing/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolgee/tolgee-js/ea8ffc97dcfec4a1ea7b06abde18d35e208cfe91/packages/testing/index.ts -------------------------------------------------------------------------------- /packages/testing/mockTranslations.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | en: { 3 | hello_world: 'Hello world!', 4 | peter_dogs: 'Peter has {dogsCount} dogs.', 5 | english_fallback: 'English fallback', 6 | with_tags: 'This text is formatted', 7 | with_tag: 'bold', 8 | }, 9 | 'en:test': { 10 | test: 'English test', 11 | test_english_fallback: 'Test english fallback', 12 | }, 13 | cs: { 14 | hello_world: 'Ahoj světe!', 15 | peter_dogs: 'Petr má {dogsCount} psů.', 16 | with_tags: 'Tento text je formátovaný', 17 | with_tag: 'bold', 18 | }, 19 | 'cs:test': { 20 | test: 'Český test', 21 | }, 22 | 'en:fallback': { 23 | fallback: 'Fallback fallback', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/testing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tolgee/testing", 3 | "version": "6.2.5", 4 | "description": "Shared testing tools", 5 | "main": "index.ts", 6 | "private": true, 7 | "keywords": [], 8 | "author": "Tolgee", 9 | "license": "ISC" 10 | } 11 | -------------------------------------------------------------------------------- /packages/testing/wait.ts: -------------------------------------------------------------------------------- 1 | export const wait = (durationInMs: number) => 2 | new Promise((resolve) => { 3 | setTimeout(() => { 4 | resolve(); 5 | }, durationInMs); 6 | }); 7 | -------------------------------------------------------------------------------- /packages/vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /lib 5 | /coverage 6 | 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | pnpm-debug.log* 17 | 18 | # Editor directories and files 19 | .idea 20 | .vscode 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? -------------------------------------------------------------------------------- /packages/vue/jest.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jsdom', 4 | unmockedModulePathPatterns: ['/node_modules/*'], 5 | modulePathIgnorePatterns: ['cypress'], 6 | transformIgnorePatterns: ['node_modules/(?!@tolgee/core)'], 7 | moduleFileExtensions: ['js', 'ts', 'tsx', 'json', 'vue'], 8 | transform: { 9 | '^.+\\.vue$': '@vue/vue3-jest', 10 | }, 11 | testEnvironmentOptions: { 12 | customExportConditions: ['node', 'node-addons'], 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /packages/vue/src/GlobalContextPlugin.ts: -------------------------------------------------------------------------------- 1 | import type { TolgeePlugin } from '@tolgee/web'; 2 | import type { TolgeeVueContext } from './types'; 3 | 4 | let globalContext: TolgeeVueContext | undefined; 5 | 6 | export const GlobalContextPlugin = (): TolgeePlugin => (tolgee) => { 7 | globalContext = { 8 | tolgee, 9 | isInitialRender: false, 10 | }; 11 | return tolgee; 12 | }; 13 | 14 | export function getGlobalContext() { 15 | return globalContext; 16 | } 17 | -------------------------------------------------------------------------------- /packages/vue/src/index.ts: -------------------------------------------------------------------------------- 1 | export { TolgeeProvider } from './TolgeeProvider'; 2 | export { T } from './T'; 3 | export { useTolgee } from './useTolgee'; 4 | export { useTranslate } from './useTranslate'; 5 | export { GlobalContextPlugin } from './GlobalContextPlugin'; 6 | export { VueTolgee } from './VueTolgee'; 7 | export * from './types'; 8 | 9 | export * from '@tolgee/web'; 10 | -------------------------------------------------------------------------------- /packages/vue/src/mocks/ComponentUsingProvider.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /packages/vue/src/mocks/ProviderComponent.vue: -------------------------------------------------------------------------------- 1 | 7 | 23 | -------------------------------------------------------------------------------- /packages/vue/src/mocks/ProviderComponentSlot.vue: -------------------------------------------------------------------------------- 1 | 7 | 23 | -------------------------------------------------------------------------------- /packages/vue/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module '*.vue' { 3 | import type { DefineComponent } from 'vue' 4 | const component: DefineComponent<{}, {}, any> 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /packages/vue/src/types.ts: -------------------------------------------------------------------------------- 1 | import { TolgeeInstance } from '@tolgee/web'; 2 | 3 | export type TolgeeVueContext = { 4 | tolgee: TolgeeInstance; 5 | isInitialRender: boolean; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "esnext", 5 | "rootDir": "src", 6 | "sourceMap": true, 7 | "declaration": true, 8 | "outDir": "./lib", 9 | "moduleResolution": "node", 10 | "skipLibCheck": true, 11 | "lib": ["es2018", "es2020", "dom"], 12 | "experimentalDecorators": true, 13 | "emitDecoratorMetadata": true, 14 | "jsx": "preserve", 15 | "downlevelIteration": true, 16 | "emitDeclarationOnly": true, 17 | "types": ["node", "jest", "@types/jest"], 18 | "paths": { 19 | "@/*": ["./*"] 20 | }, 21 | "esModuleInterop": true 22 | }, 23 | "include": ["src"], 24 | "exclude": ["node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/vue/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "include": ["src/index.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/web/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | lib 11 | coverage 12 | 13 | node_modules 14 | dist 15 | dist-ssr 16 | *.local 17 | 18 | # Editor directories and files 19 | .vscode/* 20 | !.vscode/extensions.json 21 | .idea 22 | .DS_Store 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | -------------------------------------------------------------------------------- /packages/web/index.cjs: -------------------------------------------------------------------------------- 1 | module.exports = 2 | process.env.NODE_ENV === 'production' 3 | ? require('./dist/tolgee-web.production.umd.cjs') 4 | : require('./dist/tolgee-web.development.umd.cjs'); 5 | -------------------------------------------------------------------------------- /packages/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/web/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jsdom', 4 | transformIgnorePatterns: ['/node_modules/(?!@tolgee)', '^.+\\.js$'], 5 | moduleNameMapper: { 6 | '@testFixtures/(.*)': '/src/__testFixtures/$1', 7 | }, 8 | roots: ['src'], 9 | }; 10 | -------------------------------------------------------------------------------- /packages/web/public/i18n/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /packages/web/public/i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /packages/web/public/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /packages/web/public/i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /packages/web/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /packages/web/src/app/App.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { useTolgee } from './basicTolgee'; 3 | 4 | import { Todos } from './Todos'; 5 | import { TranslationMethods } from './TranslationMethods'; 6 | 7 | export const App = () => { 8 | const currentRoute = window.location.pathname; 9 | const tolgee = useTolgee(['initialLoad']); 10 | 11 | useEffect(() => { 12 | tolgee.run(); 13 | }, []); 14 | 15 | if (!tolgee.isLoaded()) { 16 | return null; 17 | } 18 | 19 | return ( 20 | <> 21 | {currentRoute === '/translation-methods' ? ( 22 | 23 | ) : ( 24 | 25 | )} 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /packages/web/src/app/components/LangSelector.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTolgee } from '../basicTolgee'; 3 | 4 | export const LangSelector: React.FC = () => { 5 | const tolgee = useTolgee(['pendingLanguage']); 6 | 7 | return ( 8 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/web/src/app/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { LangSelector } from './LangSelector'; 2 | 3 | export const Navbar = ({ children }: React.PropsWithChildren) => { 4 | return ( 5 |
6 | {children} 7 | 8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/web/src/app/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import { App } from './App.tsx'; 4 | import './style.css'; 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /packages/web/src/app/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/web/src/package/BrowserExtensionPlugin/constants.ts: -------------------------------------------------------------------------------- 1 | export const IN_CONTEXT_FILE = 'tolgee-in-context-tools.umd.min.js'; 2 | export const IN_CONTEXT_UMD_NAME = '@tolgee/in-context-tools'; 3 | export const IN_CONTEXT_EXPORT_NAME = 'InContextTools'; 4 | -------------------------------------------------------------------------------- /packages/web/src/package/ContextUi.ts: -------------------------------------------------------------------------------- 1 | import { TolgeePlugin, UiMiddleware } from '@tolgee/core'; 2 | import { isSSR } from './tools/isSSR'; 3 | import { InContextUi } from './ui/InContextUi'; 4 | 5 | export const ContextUi = (): TolgeePlugin => (tolgee, tools) => { 6 | let ui: UiMiddleware | undefined = undefined; 7 | 8 | if (!isSSR()) { 9 | ui = (props) => InContextUi(props); 10 | } 11 | tools.setUi(ui); 12 | return tolgee; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/web/src/package/InContextTools.ts: -------------------------------------------------------------------------------- 1 | import type { TolgeePlugin } from '@tolgee/core'; 2 | import { ContextUi } from './ContextUi'; 3 | import { DevBackend } from './DevBackend'; 4 | import { InContextOptions } from './types'; 5 | import { ObserverPlugin } from './ObserverPlugin'; 6 | 7 | export const InContextTools = 8 | (props?: InContextOptions): TolgeePlugin => 9 | (tolgee, tools) => { 10 | const { credentials } = props || {}; 11 | tolgee.addPlugin(DevBackend()); 12 | if (!tools.hasUi()) { 13 | tolgee.addPlugin(ContextUi()); 14 | } 15 | if (!tools.hasObserver()) { 16 | tolgee.addPlugin(ObserverPlugin()); 17 | } 18 | if (credentials) { 19 | tolgee.overrideCredentials(credentials); 20 | } 21 | return tolgee; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/web/src/package/InvisibleObserver.ts: -------------------------------------------------------------------------------- 1 | import type { ObserverMiddleware, ObserverRunProps } from '@tolgee/core'; 2 | import { GeneralObserver } from './observers/general/GeneralObserver'; 3 | import { InvisibleWrapper } from './observers/invisible/InvisibleWrapper'; 4 | 5 | export const InvisibleObserver = (): ObserverMiddleware => () => { 6 | const observer = GeneralObserver(); 7 | 8 | const self = Object.freeze({ 9 | ...observer, 10 | run(props: ObserverRunProps) { 11 | const wrapper = InvisibleWrapper({ 12 | fullKeyEncode: props.options.fullKeyEncode, 13 | }); 14 | observer.run({ ...props, wrapper }); 15 | }, 16 | retranslate() {}, 17 | outputNotFormattable: false, 18 | }); 19 | return self; 20 | }; 21 | -------------------------------------------------------------------------------- /packages/web/src/package/ObserverPlugin.ts: -------------------------------------------------------------------------------- 1 | import { TolgeePlugin } from '@tolgee/core'; 2 | import { InvisibleObserver } from './InvisibleObserver'; 3 | import { TextObserver } from './TextObserver'; 4 | 5 | export const ObserverPlugin = (): TolgeePlugin => (tolgee, tools) => { 6 | if (tolgee.getInitialOptions().observerType === 'text') { 7 | tools.setObserver(TextObserver()); 8 | } else { 9 | tools.setObserver(InvisibleObserver()); 10 | } 11 | return tolgee; 12 | }; 13 | -------------------------------------------------------------------------------- /packages/web/src/package/Tolgee.ts: -------------------------------------------------------------------------------- 1 | import { TolgeeCore, TolgeeChainer } from '@tolgee/core'; 2 | import { BrowserExtensionPlugin } from './BrowserExtensionPlugin/BrowserExtensionPlugin'; 3 | 4 | export function Tolgee(): TolgeeChainer { 5 | return TolgeeCore().use(BrowserExtensionPlugin()); 6 | } 7 | -------------------------------------------------------------------------------- /packages/web/src/package/__test__/observer.test.ts: -------------------------------------------------------------------------------- 1 | import { testObserver } from './testObserver'; 2 | import { testRetranslate } from './testRetranslate'; 3 | 4 | describe('invisble observer', () => { 5 | testObserver('invisible'); 6 | }); 7 | 8 | describe('text observer', () => { 9 | testObserver('text'); 10 | testRetranslate('text'); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/web/src/package/entry-development.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | export * from './entry-production'; 3 | import { InContextTools } from './InContextTools'; 4 | 5 | export const DevTools = InContextTools; 6 | -------------------------------------------------------------------------------- /packages/web/src/package/entry-production.ts: -------------------------------------------------------------------------------- 1 | import { TolgeeInstance } from '@tolgee/core'; 2 | 3 | export const DevTools = () => (tolgee: TolgeeInstance) => tolgee; 4 | export * from './typedIndex'; 5 | export { 6 | PREFERRED_LANGUAGES_LOCAL_STORAGE_KEY, 7 | DEVTOOLS_ID, 8 | } from './constants'; 9 | -------------------------------------------------------------------------------- /packages/web/src/package/entry-tools.ts: -------------------------------------------------------------------------------- 1 | export { InContextTools } from './InContextTools'; 2 | export { ContextUi } from './ContextUi'; 3 | -------------------------------------------------------------------------------- /packages/web/src/package/observers/general/ElementMeta.ts: -------------------------------------------------------------------------------- 1 | import type { KeyAndParams } from '@tolgee/core'; 2 | import type { ElementMeta, NodeMeta, TolgeeElement } from '../../types'; 3 | 4 | export function initElementMeta(element: TolgeeElement): ElementMeta { 5 | return { 6 | element, 7 | nodes: new Map(), 8 | }; 9 | } 10 | 11 | export function initNodeMeta( 12 | oldTextContent: string, 13 | keys: KeyAndParams[] 14 | ): NodeMeta { 15 | return { 16 | oldTextContent, 17 | keys, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /packages/web/src/package/observers/invisible/ValueMemory.ts: -------------------------------------------------------------------------------- 1 | export function ValueMemory() { 2 | const values: string[] = []; 3 | 4 | return Object.freeze({ 5 | valueToNumber(key: string) { 6 | let index = values.indexOf(key); 7 | if (index === -1) { 8 | index = values.length; 9 | values.push(key); 10 | } 11 | return index; 12 | }, 13 | 14 | numberToValue(num: number) { 15 | return values[num]; 16 | }, 17 | }); 18 | } 19 | 20 | export type ValueMemoryInstance = ReturnType; 21 | -------------------------------------------------------------------------------- /packages/web/src/package/tools/decodeApiKey.test.ts: -------------------------------------------------------------------------------- 1 | import { getProjectIdFromApiKey } from './decodeApiKey'; 2 | 3 | const PAK_KEY = 'tgpak_gfpxm4lin4zdazleoq4gm2rumfxgi2lfom2gw4dpguzxc'; 4 | const OLD_KEY = 'ryj4psai6vetel5b27ven6fajf'; 5 | 6 | describe('get projectId from api key', () => { 7 | it('can decode from pak key', () => { 8 | expect(getProjectIdFromApiKey(PAK_KEY)).toEqual(1); 9 | }); 10 | 11 | it("won't fail on legacy code", () => { 12 | expect(getProjectIdFromApiKey(OLD_KEY)).toBeUndefined(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/web/src/package/tools/detectLanguageFromHeaders.ts: -------------------------------------------------------------------------------- 1 | import { detectLanguage } from '../LanguageDetector'; 2 | import { getHeaderLanguages } from './getHeaderLanguages'; 3 | 4 | export const detectLanguageFromHeaders = ( 5 | headers: Headers, 6 | availableLanguages: string[] 7 | ) => { 8 | const languages = getHeaderLanguages(headers); 9 | return languages[0] && detectLanguage(languages[0], availableLanguages); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/web/src/package/tools/getHeaderLanguages.ts: -------------------------------------------------------------------------------- 1 | export function getHeaderLanguages(headers: Headers) { 2 | const acceptLanguageHeader = headers.get('Accept-Language'); 3 | if (!acceptLanguageHeader) { 4 | return []; 5 | } 6 | // Split the header into locales based on commas 7 | const locales = acceptLanguageHeader.split(',').map((locale) => { 8 | // Remove whitespace and split by ';' to get only the locale part 9 | const [localePart] = locale.trim().split(';'); 10 | return localePart; 11 | }); 12 | 13 | // Filter out any empty strings and return the unique locales 14 | return [...new Set(locales.filter((locale) => locale && locale !== '*'))]; 15 | } 16 | -------------------------------------------------------------------------------- /packages/web/src/package/tools/isSSR.ts: -------------------------------------------------------------------------------- 1 | export function isSSR() { 2 | return typeof globalThis.window?.document?.createElement === 'undefined'; 3 | } 4 | 5 | export function throwIfSSR(origin: string) { 6 | if (isSSR()) { 7 | throw new Error(`${origin}: Can't run on the server`); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/web/src/package/tools/url.test.ts: -------------------------------------------------------------------------------- 1 | import { joinUrls } from './url'; 2 | 3 | describe('url module', () => { 4 | it('joins urls without double slash', () => { 5 | expect(joinUrls('a/b/', '/c')).toEqual('a/b/c'); 6 | }); 7 | 8 | it("doesn't remove last slash", () => { 9 | expect(joinUrls('a/b/', '/c/')).toEqual('a/b/c/'); 10 | }); 11 | 12 | it("doesn't touch the protocol", () => { 13 | expect(joinUrls('https://test.com/', '/c/')).toEqual('https://test.com/c/'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/web/src/package/tools/url.ts: -------------------------------------------------------------------------------- 1 | function composeUrl(base: string, path: string): string { 2 | // Ensure the base URL does not end with a slash 3 | base = base.replace(/\/+$/, ''); 4 | // Ensure the path does not start with a slash 5 | path = path.replace(/^\/+/, ''); 6 | // Combine the two parts with a single slash in between 7 | return `${base}/${path}`; 8 | } 9 | 10 | export function joinUrls(...parts: string[]): string { 11 | let result = parts[0]; 12 | parts.slice(1).forEach((part) => { 13 | result = composeUrl(result, part); 14 | }); 15 | return result; 16 | } 17 | 18 | export function createUrl(...parts: string[]): URL { 19 | const base = 20 | typeof window === 'undefined' ? undefined : window.location.origin; 21 | return new URL(joinUrls(...parts), base); 22 | } 23 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/KeyDialog/Link.tsx: -------------------------------------------------------------------------------- 1 | import { OpenInNew } from '@mui/icons-material'; 2 | import { styled } from '@mui/material'; 3 | 4 | type Props = { 5 | href: string; 6 | children: React.ReactNode; 7 | }; 8 | 9 | const StyledLink = styled('a')``; 10 | 11 | const StyledIcon = styled(OpenInNew)` 12 | width: 17px; 13 | height: 17px; 14 | position: relative; 15 | top: 3px; 16 | margin-left: 1px; 17 | `; 18 | 19 | export const NewTabLink = ({ href, children }: Props) => { 20 | return ( 21 | 22 | {children} 23 | 24 | 25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/KeyDialog/ScreenshotGallery/utils.ts: -------------------------------------------------------------------------------- 1 | export const MAX_FILE_COUNT = 20; 2 | 3 | export const dataTransferItemsToArray = ( 4 | items: DataTransferItemList 5 | ): File[] => { 6 | const result = [] as any[]; 7 | for (let i = 0; i < items.length; i++) { 8 | if (items[i].kind === 'file') { 9 | result.push(items[i].getAsFile()); 10 | } 11 | } 12 | return result; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/KeyDialog/Tags/CloseButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { styled } from '@mui/material'; 3 | import { Close } from '@mui/icons-material'; 4 | 5 | const StyledCloseIcon = styled(Close)` 6 | font-size: 20px; 7 | cursor: pointer; 8 | padding: 2px; 9 | `; 10 | 11 | type Props = { 12 | onClick?: React.MouseEventHandler; 13 | }; 14 | 15 | export const CloseButton: React.FC = ({ onClick }) => { 16 | return ( 17 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/KeyDialog/TranslationDialog.tsx: -------------------------------------------------------------------------------- 1 | import { TranslationDialogWrapper } from './TranslationDialogWrapper'; 2 | import { KeyForm } from './KeyForm'; 3 | import { ThemeProvider } from '../ThemeProvider'; 4 | 5 | export const TranslationDialog = () => { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/KeyDialog/editor/editorTheme.ts: -------------------------------------------------------------------------------- 1 | export const editorTheme = { 2 | variable: { 3 | border: '#7AD3C1', 4 | background: '#BEF3E9', 5 | text: '#008371', 6 | }, 7 | tag: { 8 | border: '#F27FA6', 9 | background: '#F9C4D6', 10 | text: '#822343', 11 | }, 12 | variant: { 13 | border: '#BBC2CB', 14 | background: '#F0F2F4', 15 | text: '#4D5B6E', 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/KeyDialog/languageHelpers.ts: -------------------------------------------------------------------------------- 1 | import { components } from '../client/apiSchema.generated'; 2 | 3 | type LanguageModel = components['schemas']['LanguageModel']; 4 | 5 | export const putBaseLangFirst = (languages: LanguageModel[] | undefined) => { 6 | const base = languages?.find((l) => l.base); 7 | if (base) { 8 | return [base, ...(languages || []).filter((val) => val !== base)]; 9 | } 10 | return languages; 11 | }; 12 | 13 | export const putBaseLangFirstTags = (strings: Array, base?: string) => { 14 | if (base && strings.includes(base)) { 15 | return [base, ...strings.filter((val) => val !== base)]; 16 | } 17 | return strings; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/common/FieldTitle.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/material'; 2 | import { HTMLFactory } from 'react'; 3 | 4 | export const ScFieldTitle = styled('div')` 5 | display: flex; 6 | margin-top: 16px; 7 | margin-bottom: 4px; 8 | font-size: 14px; 9 | color: ${({ theme }) => theme.palette.text.secondary}; 10 | justify-content: space-between; 11 | ` as unknown as HTMLFactory; 12 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/common/Tooltip.tsx: -------------------------------------------------------------------------------- 1 | import { Tooltip as TooltipMui } from '@mui/material'; 2 | import { DEVTOOLS_Z_INDEX } from '../../constants'; 3 | import { getRootElement } from '../getRootElement'; 4 | 5 | type Props = React.ComponentProps; 6 | 7 | export const Tooltip = (props: Props) => { 8 | return ( 9 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/screenshots/ScreenshotPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { styled } from '@mui/material'; 3 | 4 | const Img = styled('img')` 5 | width: 100px; 6 | height: 100px; 7 | object-fit: contain; 8 | padding: 2px; 9 | box-sizing: 'border-box'; 10 | `; 11 | 12 | type Props = { 13 | url: string; 14 | }; 15 | 16 | export const ScreenshotPreview: React.FC = ({ url }) => { 17 | return ; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/tools/checkPlatformVersion.ts: -------------------------------------------------------------------------------- 1 | const SEMVER_REGEX = /^v[0-9]+\.[0-9]+\.[0-9]+$/; 2 | 3 | export const checkPlatformVersion = ( 4 | requiredV: string, 5 | currentV: string | undefined 6 | ) => { 7 | if (!currentV || !SEMVER_REGEX.test(currentV)) { 8 | return undefined; 9 | } 10 | const result = requiredV.localeCompare(currentV, 'en', { 11 | numeric: true, 12 | sensitivity: 'base', 13 | }); 14 | 15 | if (result > 0) { 16 | return new Error( 17 | `Requires minimal platform version ${requiredV} (got ${currentV})` 18 | ); 19 | } 20 | return undefined; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/tools/isTranslationEmpty.ts: -------------------------------------------------------------------------------- 1 | import { TolgeeFormat } from '@tginternal/editor'; 2 | 3 | export function isTranslationEmpty( 4 | value: TolgeeFormat | undefined, 5 | isPlural: boolean 6 | ) { 7 | if (!value) { 8 | return true; 9 | } 10 | if (isPlural) { 11 | return !Object.values(value.variants).join(''); 12 | } else { 13 | return !value.variants.other; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/tools/permissions.ts: -------------------------------------------------------------------------------- 1 | export function isAuthorizedTo(scope: string, scopes: string[] | undefined) { 2 | return Boolean(scopes?.includes(scope)); 3 | } 4 | 5 | export const isLanguagePermitted = ( 6 | languageId: number | undefined, 7 | permittedLanguages: number[] | undefined 8 | ) => { 9 | if (!permittedLanguages?.length) { 10 | return true; 11 | } 12 | return permittedLanguages.includes(languageId as number); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/tools/sleep.ts: -------------------------------------------------------------------------------- 1 | export const sleep = (ms: number) => 2 | new Promise((resolve) => setTimeout(resolve, ms)); 3 | -------------------------------------------------------------------------------- /packages/web/src/package/ui/tools/validateUrl.ts: -------------------------------------------------------------------------------- 1 | import { createUrl } from '../../tools/url'; 2 | 3 | export function isUrlValid(url: string) { 4 | try { 5 | const result = createUrl(url); 6 | return result instanceof URL; 7 | } catch (e) { 8 | return false; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/web/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/web/tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "internal": true, 3 | "main": "../dist/tolgee-in-context-tools.umd.cjs", 4 | "type": "module", 5 | "types": "../types/tools.d.ts", 6 | "exports": { 7 | ".": { 8 | "import": "./../dist/tolgee-in-context-tools.esm.js", 9 | "require": "./../dist/tolgee-in-context-tools.umd.cjs", 10 | "types": "./../types/tools.d.ts" 11 | }, 12 | "./package.json": "./package.json" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | "esModuleInterop": true 18 | 19 | // /* Linting */ 20 | // "strict": true, 21 | // "noUnusedLocals": true, 22 | // "noUnusedParameters": true, 23 | // "noFallthroughCasesInSwitch": true 24 | }, 25 | "include": ["src"], 26 | "references": [{ "path": "./tsconfig.node.json" }] 27 | } 28 | -------------------------------------------------------------------------------- /packages/web/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts", "*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/web/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "compilerOptions": { 4 | "allowArbitraryExtensions": true, 5 | "declaration": true, 6 | "emitDeclarationOnly": true, 7 | "noEmit": false, 8 | "rootDir": "src/package", 9 | "outDir": "./lib" 10 | }, 11 | "include": ["src/package"], 12 | "exclude": ["./src/package/__test__"] 13 | } -------------------------------------------------------------------------------- /packages/web/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { TolgeePlugin } from '@tolgee/core'; 2 | import type { InContextOptions } from '../lib/types'; 3 | 4 | export declare const DevTools: (options?: InContextOptions) => TolgeePlugin; 5 | 6 | export * from '../lib/typedIndex'; 7 | -------------------------------------------------------------------------------- /packages/web/types/tools.d.ts: -------------------------------------------------------------------------------- 1 | import type { TolgeePlugin } from '@tolgee/core'; 2 | import type { InContextOptions } from '../lib/types'; 3 | 4 | export declare const ContextUi: () => TolgeePlugin; 5 | export declare const InContextTools: ( 6 | options?: InContextOptions 7 | ) => TolgeePlugin; 8 | -------------------------------------------------------------------------------- /packages/web/vite.config.production.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { buildPackage } from './rollup.common'; 3 | import { createConfig } from './vite.config'; 4 | 5 | export default createConfig({ 6 | entry: resolve(__dirname, 'src/package/entry-production.ts'), 7 | rollupOptions: buildPackage({ 8 | name: 'web', 9 | env: 'production', 10 | }), 11 | }); 12 | -------------------------------------------------------------------------------- /packages/web/vite.config.tools.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { buildPackage } from './rollup.common'; 3 | import { createConfig } from './vite.config'; 4 | 5 | export default createConfig({ 6 | entry: resolve(__dirname, 'src/package/entry-tools.ts'), 7 | rollupOptions: buildPackage({ 8 | name: 'in-context-tools', 9 | }), 10 | }); 11 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'packages/ngx/projects/ngx-tolgee' 4 | - 'testapps/*' 5 | - 'e2e' 6 | -------------------------------------------------------------------------------- /scripts/cleanTurbo.js: -------------------------------------------------------------------------------- 1 | const { searchRecursively } = require('./searchRecursively'); 2 | const fs = require('fs'); 3 | 4 | const CACHE_FOLDER = 'node_modules/.cache/turbo'; 5 | 6 | console.log('deleting', CACHE_FOLDER); 7 | fs.rmSync(CACHE_FOLDER, { recursive: true, force: true }); 8 | 9 | const files = searchRecursively('.', '.turbo', [], 5); 10 | 11 | files.forEach((file) => { 12 | console.log('deleting', file); 13 | fs.rmSync(file, { recursive: true, force: true }); 14 | }); 15 | -------------------------------------------------------------------------------- /scripts/customLinks.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | // pnpm doesn't handle "publicConfig.directory" correctly 5 | // so when library uses separate package.json in build folder we need to redirect 6 | // symlink directly there 7 | 8 | { 9 | const target = './packages/ngx/dist/ngx-tolgee'; 10 | const locationDir = './testapps/ngx/node_modules/@tolgee'; 11 | const location = path.join(locationDir, 'ngx'); 12 | 13 | if (fs.existsSync(location)) { 14 | fs.rmSync(location, { recursive: true, force: true }); 15 | fs.symlinkSync(path.relative(locationDir, target), location); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/e2eRunner/serviceRunner/checkOutput.ts: -------------------------------------------------------------------------------- 1 | export const checkOutput = (output: string, regexOrString: string | RegExp) => { 2 | if (typeof output === 'string') { 3 | if (regexOrString instanceof RegExp) { 4 | if (output.match(regexOrString)) { 5 | return true; 6 | } 7 | } else if (typeof regexOrString == 'string') { 8 | if (output.includes(regexOrString)) { 9 | return true; 10 | } 11 | } 12 | } 13 | return false; 14 | }; 15 | -------------------------------------------------------------------------------- /scripts/e2eRunner/types.ts: -------------------------------------------------------------------------------- 1 | export type DockerComposeServiceConfig = { 2 | waitForOutput: string | RegExp; 3 | timeout?: number; 4 | stdErrEnabled?: boolean; 5 | }; 6 | 7 | export type CommandLineServiceConfig = { 8 | command: string; 9 | cwd: string; 10 | waitForOutput?: string | RegExp; 11 | timeout?: number; 12 | environment?: Record; 13 | stdErrEnabled?: boolean; 14 | }; 15 | 16 | export type TestDefinition = { 17 | dockerComposeServices?: Record; 18 | commandLineServices?: Record; 19 | }; 20 | 21 | export type Config = { 22 | dockerComposeServices: Record; 23 | tests: Record; 24 | }; 25 | -------------------------------------------------------------------------------- /scripts/tolgeeUiVersion.js: -------------------------------------------------------------------------------- 1 | var pjson = require('../packages/web/package.json'); 2 | console.log(pjson.version); 3 | -------------------------------------------------------------------------------- /testapps/next-app-intl/.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_TOLGEE_API_URL=https://app.tolgee.io 2 | NEXT_PUBLIC_TOLGEE_API_KEY= -------------------------------------------------------------------------------- /testapps/next-app-intl/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | /dist-e2e 19 | 20 | # misc 21 | .DS_Store 22 | *.pem 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # local env files 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | -------------------------------------------------------------------------------- /testapps/next-app-intl/README.md: -------------------------------------------------------------------------------- 1 | # Tolgee with next.js 14 app router DEMO 2 | 3 | This repo demonstrates how to use `tolgee` with new `next.js` app router. 4 | 5 | An example based on `next14` app folder with `tolgee` and `next-intl` package. 6 | 7 | ## Setup 8 | 9 | 1. Clone this repo 10 | 2. Run `npm i` 11 | 3. Run `npm run dev` 12 | 13 | ## Setup tolgee credentials (optional) 14 | 15 | 4. Create project in Tolgee platform 16 | 5. Add `.env.development.local` file to base folder of this project with an API key to your project 17 | 18 | ``` 19 | NEXT_PUBLIC_TOLGEE_API_URL=https://app.tolgee.io 20 | NEXT_PUBLIC_TOLGEE_API_KEY= 21 | ``` 22 | 23 | 6. Re-run `npm run dev` 24 | -------------------------------------------------------------------------------- /testapps/next-app-intl/messages/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next-app-intl/messages/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next-app-intl/messages/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next-app-intl/messages/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next-app-intl/next.config.js: -------------------------------------------------------------------------------- 1 | const createNextIntlPlugin = require('next-intl/plugin'); 2 | 3 | const withNextIntl = createNextIntlPlugin(); 4 | 5 | /** @type {import('next').NextConfig} */ 6 | const nextConfig = { 7 | distDir: process.env.NEXT_BUILD_DIR || '.next', 8 | }; 9 | 10 | module.exports = withNextIntl(nextConfig); 11 | -------------------------------------------------------------------------------- /testapps/next-app-intl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tolgee/next-app-intl-testapp", 3 | "version": "6.2.5", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "develop": "next dev", 8 | "build": "next build", 9 | "build:e2e": "NEXT_BUILD_DIR=dist-e2e next build", 10 | "start": "next start", 11 | "clean": "rm -rf .next dist-e2e" 12 | }, 13 | "dependencies": { 14 | "@tolgee/format-icu": "6.2.5", 15 | "@tolgee/react": "6.2.5", 16 | "@tolgee/web": "6.2.5", 17 | "next": "15.1.0", 18 | "next-intl": "3.26.1", 19 | "react": "18.3.1", 20 | "react-dom": "18.3.1" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "^20", 24 | "@types/react": "^18.3.16", 25 | "@types/react-dom": "^18.3.5", 26 | "typescript": "^5.3.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /testapps/next-app-intl/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolgee/tolgee-js/ea8ffc97dcfec4a1ea7b06abde18d35e208cfe91/testapps/next-app-intl/public/favicon.ico -------------------------------------------------------------------------------- /testapps/next-app-intl/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/app/[locale]/[...rest]/page.tsx: -------------------------------------------------------------------------------- 1 | import { notFound } from 'next/navigation'; 2 | 3 | export default function CatchAllPage() { 4 | notFound(); 5 | } 6 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/app/[locale]/page.tsx: -------------------------------------------------------------------------------- 1 | import { getTranslate } from '@/tolgee/server'; 2 | import { Todos } from './Todos'; 3 | import { Link } from '@/navigation'; 4 | 5 | import { Navbar } from '@/components/Navbar'; 6 | 7 | export default async function IndexPage() { 8 | const t = await getTranslate(); 9 | return ( 10 |
11 |
12 | 13 | 14 | {t('menu-item-translation-methods')} 15 | 16 | 17 |
18 | 19 |

{t('app-title')}

20 |
21 | 22 |
23 |
24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/app/[locale]/translation-methods/page.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from '@/navigation'; 2 | import { Navbar } from '@/components/Navbar'; 3 | 4 | import { TranslationMethodsServer } from './TranslationMethodsServer'; 5 | import { TranslationMethodsClient } from './TranslationMethodsClient'; 6 | 7 | export default async function AboutPage() { 8 | return ( 9 |
10 | 11 |
12 | The example app 13 |
14 |
15 | 16 | 17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import './style.css'; 3 | 4 | type Props = { 5 | children: ReactNode; 6 | }; 7 | 8 | // Since we have a `not-found.tsx` page on the root, a layout file 9 | // is required, even if it's just passing children through. 10 | export default function RootLayout({ children }: Props) { 11 | return children; 12 | } 13 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import Error from 'next/error'; 4 | 5 | // Render the default Next.js 404 page when a route 6 | // is requested that doesn't match the middleware and 7 | // therefore doesn't have a locale associated with it. 8 | 9 | export default function NotFound() { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation'; 2 | 3 | // This page only renders when the app is built statically (output: 'export') 4 | export default function RootPage() { 5 | redirect('/en'); 6 | } 7 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { LangSelector } from './LangSelector'; 3 | 4 | export const Navbar = ({ children }: React.PropsWithChildren) => { 5 | return ( 6 |
7 | {children} 8 | 9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/i18n/request.ts: -------------------------------------------------------------------------------- 1 | import { getRequestConfig } from 'next-intl/server'; 2 | 3 | export default getRequestConfig(async ({ requestLocale }) => { 4 | const locale = await requestLocale; 5 | return { 6 | // do this to make next-intl not emmit any warnings 7 | messages: { locale: locale! }, 8 | }; 9 | }); 10 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/middleware.ts: -------------------------------------------------------------------------------- 1 | import createMiddleware from 'next-intl/middleware'; 2 | import { ALL_LANGUAGES, DEFAULT_LANGUAGE } from '@/tolgee/shared'; 3 | 4 | // read more about next-intl middleware configuration 5 | // https://next-intl-docs.vercel.app/docs/routing/middleware#locale-prefix 6 | export default createMiddleware({ 7 | locales: ALL_LANGUAGES, 8 | defaultLocale: DEFAULT_LANGUAGE, 9 | localePrefix: 'as-needed', 10 | }); 11 | 12 | export const config = { 13 | // Skip all paths that should not be internationalized 14 | matcher: ['/((?!api|_next|.*\\..*).*)'], 15 | }; 16 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/navigation.ts: -------------------------------------------------------------------------------- 1 | import { createNavigation } from 'next-intl/navigation'; 2 | import { ALL_LANGUAGES } from './tolgee/shared'; 3 | 4 | // read more about next-intl library 5 | // https://next-intl-docs.vercel.app 6 | export const { Link, redirect, usePathname, useRouter } = createNavigation({ 7 | locales: ALL_LANGUAGES, 8 | }); 9 | -------------------------------------------------------------------------------- /testapps/next-app-intl/src/tolgee/server.tsx: -------------------------------------------------------------------------------- 1 | import { getLocale } from 'next-intl/server'; 2 | import { createServerInstance } from '@tolgee/react/server'; 3 | import { TolgeeBase } from './shared'; 4 | 5 | export const { getTolgee, getTranslate, T } = createServerInstance({ 6 | getLocale: getLocale, 7 | createTolgee: async (language) => { 8 | return TolgeeBase().init({ 9 | observerOptions: { 10 | fullKeyEncode: true, 11 | }, 12 | language, 13 | }); 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /testapps/next-app/.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_TOLGEE_API_URL=https://app.tolgee.io 2 | NEXT_PUBLIC_TOLGEE_API_KEY= -------------------------------------------------------------------------------- /testapps/next-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | /dist-e2e 19 | 20 | # misc 21 | .DS_Store 22 | *.pem 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # local env files 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | -------------------------------------------------------------------------------- /testapps/next-app/messages/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next-app/messages/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next-app/messages/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next-app/messages/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next-app/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /testapps/next-app/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | distDir: process.env.NEXT_BUILD_DIR || '.next', 4 | }; 5 | 6 | module.exports = nextConfig; 7 | -------------------------------------------------------------------------------- /testapps/next-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tolgee/next-app-testapp", 3 | "version": "6.2.5", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "develop": "next dev", 8 | "build": "next build", 9 | "build:e2e": "NEXT_BUILD_DIR=dist-e2e next build", 10 | "start": "next start", 11 | "clean": "rm -rf .next dist-e2e" 12 | }, 13 | "dependencies": { 14 | "@tolgee/format-icu": "6.2.5", 15 | "@tolgee/react": "6.2.5", 16 | "@tolgee/web": "6.2.5", 17 | "next": "15.1.0", 18 | "react": "^18.3.1", 19 | "react-dom": "^18.3.1" 20 | }, 21 | "devDependencies": { 22 | "@types/node": "^20", 23 | "@types/react": "^18.3.16", 24 | "@types/react-dom": "^18.3.5", 25 | "typescript": "^5.7.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /testapps/next-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolgee/tolgee-js/ea8ffc97dcfec4a1ea7b06abde18d35e208cfe91/testapps/next-app/public/favicon.ico -------------------------------------------------------------------------------- /testapps/next-app/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/next-app/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { TolgeeNextProvider } from '@/tolgee/client'; 3 | import { getTolgee } from '@/tolgee/server'; 4 | import { getLanguage } from '@/tolgee/language'; 5 | import './style.css'; 6 | 7 | type Props = { 8 | children: ReactNode; 9 | }; 10 | 11 | export default async function LocaleLayout({ children }: Props) { 12 | const language = await getLanguage(); 13 | const tolgee = await getTolgee(); 14 | const staticData = await tolgee.loadRequired(); 15 | 16 | return ( 17 | 18 | 19 | 20 | {children} 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /testapps/next-app/src/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import Error from 'next/error'; 4 | 5 | // Render the default Next.js 404 page when a route 6 | // is requested that doesn't match the middleware and 7 | // therefore doesn't have a locale associated with it. 8 | 9 | export default function NotFound() { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /testapps/next-app/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { getTranslate } from '@/tolgee/server'; 2 | 3 | import { Navbar } from '@/components/Navbar'; 4 | import Link from 'next/link'; 5 | import { Todos } from './Todos'; 6 | 7 | export default async function IndexPage() { 8 | const t = await getTranslate(); 9 | return ( 10 |
11 |
12 | 13 | 14 | {t('menu-item-translation-methods')} 15 | 16 | 17 |
18 | 19 |

{t('app-title')}

20 |
21 | 22 |
23 |
24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /testapps/next-app/src/app/translation-methods/page.tsx: -------------------------------------------------------------------------------- 1 | import { Navbar } from '@/components/Navbar'; 2 | 3 | import { TranslationMethodsServer } from './TranslationMethodsServer'; 4 | import { TranslationMethodsClient } from './TranslationMethodsClient'; 5 | import Link from 'next/link'; 6 | 7 | export default async function AboutPage() { 8 | return ( 9 |
10 | 11 |
12 | The example app 13 |
14 |
15 | 16 | 17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /testapps/next-app/src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { LangSelector } from './LangSelector'; 3 | 4 | export const Navbar = ({ children }: React.PropsWithChildren) => { 5 | return ( 6 |
7 | {children} 8 | 9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /testapps/next-app/src/tolgee/server.tsx: -------------------------------------------------------------------------------- 1 | import { getLanguage } from './language'; 2 | import { TolgeeBase } from './shared'; 3 | import { createServerInstance } from '@tolgee/react/server'; 4 | 5 | export const { getTolgee, getTranslate, T } = createServerInstance({ 6 | getLocale: getLanguage, 7 | createTolgee: async (language) => { 8 | return TolgeeBase().init({ 9 | observerOptions: { 10 | fullKeyEncode: true, 11 | }, 12 | language, 13 | }); 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /testapps/next/.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_TOLGEE_API_URL=https://app.tolgee.io 2 | NEXT_PUBLIC_TOLGEE_API_KEY= -------------------------------------------------------------------------------- /testapps/next/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /dist 17 | /dist-e2e 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env.local 30 | .env.development.local 31 | .env.test.local 32 | .env.production.local 33 | 34 | # vercel 35 | .vercel -------------------------------------------------------------------------------- /testapps/next/messages/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next/messages/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next/messages/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next/messages/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/next/messages/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /testapps/next/messages/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /testapps/next/messages/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /testapps/next/messages/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /testapps/next/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /testapps/next/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | reactStrictMode: true, 4 | i18n: { 5 | locales: ['en', 'de', 'fr', 'cs'], 6 | localeDetection: false, 7 | defaultLocale: 'en', 8 | }, 9 | distDir: process.env.NEXT_BUILD_DIR || '.next', 10 | }; 11 | -------------------------------------------------------------------------------- /testapps/next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tolgee/next-testapp", 3 | "version": "6.2.5", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "develop": "next dev", 8 | "build": "next build", 9 | "build:e2e": "NEXT_BUILD_DIR=dist-e2e next build", 10 | "clean": "rm -rf build build-e2e dist dist-e2e lib .next", 11 | "start": "next start", 12 | "lint": "next lint" 13 | }, 14 | "dependencies": { 15 | "@tolgee/format-icu": "6.2.5", 16 | "@tolgee/react": "6.2.5", 17 | "next": "15.1.0", 18 | "react": "18.3.1", 19 | "react-dom": "18.3.1" 20 | }, 21 | "devDependencies": { 22 | "@types/react": "18.3.16", 23 | "eslint": "8.57.0", 24 | "eslint-config-next": "13.2.3", 25 | "typescript": "4.9.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /testapps/next/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/next/src/components/LangSelector.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useRouter } from 'next/router'; 3 | 4 | export const LangSelector: React.FC = () => { 5 | const router = useRouter(); 6 | const setLanguage = (lang: string) => { 7 | router.replace(router.pathname, undefined, { locale: lang }); 8 | }; 9 | 10 | return ( 11 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /testapps/next/src/components/Namespaces.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTranslate, T } from '@tolgee/react'; 3 | 4 | const Namespaces = () => { 5 | const { t } = useTranslate('namespaced'); 6 | 7 | return ( 8 |
9 |
10 |

t function with namespace

11 |
{t('this_is_a_key')}
12 |
13 | 14 |
15 |

t function with default namespace

16 |
{t('this_is_a_key', { ns: '' })}
17 |
18 | 19 |
20 |

T component with namespace

21 |
22 | 23 |
24 |
25 |
26 | ); 27 | }; 28 | 29 | export default Namespaces; 30 | -------------------------------------------------------------------------------- /testapps/next/src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { LangSelector } from './LangSelector'; 2 | 3 | export const Navbar = ({ children }: React.PropsWithChildren) => { 4 | return ( 5 |
6 | {children} 7 | 8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /testapps/next/src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import Document, { Html, Head, Main, NextScript } from 'next/document'; 2 | 3 | class MyDocument extends Document { 4 | render() { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | ); 16 | } 17 | } 18 | 19 | export default MyDocument; 20 | -------------------------------------------------------------------------------- /testapps/next/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Todos } from '../views/Todos'; 2 | 3 | const Page = () => { 4 | return ; 5 | }; 6 | 7 | export default Page; 8 | -------------------------------------------------------------------------------- /testapps/next/src/pages/translation-methods.tsx: -------------------------------------------------------------------------------- 1 | import { TranslationMethods } from '../views/TranslationMethods'; 2 | 3 | const Page = () => { 4 | return ; 5 | }; 6 | 7 | export default Page; 8 | -------------------------------------------------------------------------------- /testapps/next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "preserveSymlinks": true, 16 | "jsx": "preserve", 17 | "incremental": true 18 | }, 19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /testapps/ngx/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /testapps/ngx/.gitignore: -------------------------------------------------------------------------------- 1 | **/environment.stage.ts 2 | dist 3 | node_modules 4 | .angular 5 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | }) 7 | export class AppComponent { 8 | constructor() {} 9 | } 10 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/component/lang-selector/lang-selector.component.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/component/lang-selector/lang-selector.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { TranslateService } from '@tolgee/ngx'; 3 | 4 | @Component({ 5 | selector: 'app-lang-selector', 6 | templateUrl: './lang-selector.component.html', 7 | }) 8 | export class LangSelectorComponent implements OnInit { 9 | constructor(public translateService: TranslateService) {} 10 | 11 | ngOnInit(): void {} 12 | } 13 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/component/navbar/navbar.component.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/component/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-navbar', 5 | templateUrl: './navbar.component.html', 6 | }) 7 | export class NavbarComponent implements OnInit { 8 | constructor() {} 9 | 10 | ngOnInit(): void {} 11 | } 12 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/lazy/lazy-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { LazyComponent } from './lazy.component'; 4 | 5 | const routes: Routes = [{ path: '', component: LazyComponent }]; 6 | 7 | @NgModule({ 8 | imports: [RouterModule.forChild(routes)], 9 | exports: [RouterModule], 10 | }) 11 | export class LazyRoutingModule {} 12 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/lazy/lazy.component.html: -------------------------------------------------------------------------------- 1 |
2 | The example app 3 | 4 |
5 |
6 |

Namespaced key

7 |
8 |
9 |
10 |
11 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/lazy/lazy.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-lazy', 5 | templateUrl: './lazy.component.html', 6 | }) 7 | export class LazyComponent { 8 | constructor() {} 9 | } 10 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/lazy/lazy.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { LazyRoutingModule } from './lazy-routing.module'; 5 | import { LazyComponent } from './lazy.component'; 6 | import { NgxTolgeeModule } from '@tolgee/ngx'; 7 | 8 | @NgModule({ 9 | declarations: [LazyComponent], 10 | imports: [CommonModule, LazyRoutingModule, NgxTolgeeModule], 11 | }) 12 | export class LazyModule {} 13 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/app/wait.ts: -------------------------------------------------------------------------------- 1 | export const wait = (durationInMs: number) => 2 | new Promise((resolve) => { 3 | setTimeout(() => { 4 | resolve(); 5 | }, durationInMs); 6 | }); 7 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolgee/tolgee-js/ea8ffc97dcfec4a1ea7b06abde18d35e208cfe91/testapps/ngx/projects/sampleapp/src/assets/.gitkeep -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/assets/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | tolgeeApiKey: undefined, 4 | tolgeeApiUrl: undefined, 5 | }; 6 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/i18n/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/i18n/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/i18n/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/i18n/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/i18n/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular + Tolgee Example App 6 | 7 | 8 | 9 | 10 | Loading... 11 | 12 | 13 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | function bootstrap() { 12 | platformBrowserDynamic() 13 | .bootstrapModule(AppModule) 14 | // eslint-disable-next-line no-console 15 | .catch((err) => console.error(err)); 16 | } 17 | 18 | if (document.readyState === 'complete') { 19 | bootstrap(); 20 | } else { 21 | document.addEventListener('DOMContentLoaded', bootstrap); 22 | } 23 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting, 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | // First, initialize the Angular testing environment. 11 | getTestBed().initTestEnvironment( 12 | BrowserDynamicTestingModule, 13 | platformBrowserDynamicTesting() 14 | ); 15 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/app", 5 | "types": [ 6 | "node" 7 | ] 8 | }, 9 | "files": [ 10 | "src/main.ts", 11 | "src/polyfills.ts" 12 | ], 13 | "include": [ 14 | "src/**/*.d.ts" 15 | ], 16 | "exclude": [ 17 | "src/test.ts", 18 | "src/**/*.spec.ts" 19 | ], 20 | } 21 | -------------------------------------------------------------------------------- /testapps/ngx/projects/sampleapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": ["jasmine", "node"] 6 | }, 7 | "files": ["src/test.ts", "src/polyfills.ts"], 8 | "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /testapps/ngx/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "es2020", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "ES2022", 14 | "resolveJsonModule": true, 15 | "typeRoots": [ 16 | "node_modules/@types" 17 | ], 18 | "lib": [ 19 | "es2018", 20 | "dom" 21 | ], 22 | "useDefineForClassFields": false 23 | }, 24 | "angularCompilerOptions": { 25 | "fullTemplateTypeCheck": true, 26 | "strictInjectionParameters": true, 27 | "enableIvy": "ngtsc" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /testapps/react-i18next/.env: -------------------------------------------------------------------------------- 1 | VITE_APP_TOLGEE_API_URL=https://app.tolgee.io 2 | VITE_APP_TOLGEE_API_KEY= -------------------------------------------------------------------------------- /testapps/react-i18next/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /testapps/react-i18next/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testapps/react-i18next/public/i18n/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /testapps/react-i18next/public/i18n/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /testapps/react-i18next/public/i18n/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /testapps/react-i18next/public/i18n/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /testapps/react-i18next/public/i18n/translation/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/react-i18next/public/i18n/translation/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/react-i18next/public/i18n/translation/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/react-i18next/public/i18n/translation/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/react-i18next/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/react-i18next/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolgee/tolgee-js/ea8ffc97dcfec4a1ea7b06abde18d35e208cfe91/testapps/react-i18next/public/logo192.png -------------------------------------------------------------------------------- /testapps/react-i18next/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolgee/tolgee-js/ea8ffc97dcfec4a1ea7b06abde18d35e208cfe91/testapps/react-i18next/public/logo512.png -------------------------------------------------------------------------------- /testapps/react-i18next/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /testapps/react-i18next/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /testapps/react-i18next/src/components/LangSelector.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | export const LangSelector: React.FC = () => { 5 | const { i18n } = useTranslation(); 6 | 7 | return ( 8 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /testapps/react-i18next/src/components/Namespaces.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | 3 | const Namespaces = () => { 4 | const { t } = useTranslation('namespaced'); 5 | 6 | return ( 7 |
8 |
9 |

t function with namespace

10 |
{t('this_is_a_key', { ns: 'namespaced' })}
11 |
12 | 13 |
14 |

t function with default namespace

15 |
{t('this_is_a_key', { ns: 'translation' })}
16 |
17 |
18 | ); 19 | }; 20 | 21 | export default Namespaces; 22 | -------------------------------------------------------------------------------- /testapps/react-i18next/src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { LangSelector } from './LangSelector'; 2 | 3 | export const Navbar = ({ children }: React.PropsWithChildren) => { 4 | return ( 5 |
6 | {children} 7 | 8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /testapps/react-i18next/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import { App } from './App.tsx'; 4 | import './style.css'; 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /testapps/react-i18next/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /testapps/react-i18next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /testapps/react-i18next/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /testapps/react-i18next/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | clearScreen: false, 8 | }); 9 | -------------------------------------------------------------------------------- /testapps/react/.env: -------------------------------------------------------------------------------- 1 | VITE_APP_TOLGEE_API_URL=https://app.tolgee.io 2 | VITE_APP_TOLGEE_API_KEY= -------------------------------------------------------------------------------- /testapps/react/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /testapps/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testapps/react/public/i18n/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/react/public/i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/react/public/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/react/public/i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/react/public/i18n/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /testapps/react/public/i18n/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /testapps/react/public/i18n/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /testapps/react/public/i18n/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /testapps/react/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/react/src/components/LangSelector.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTolgee } from '@tolgee/react'; 3 | 4 | export const LangSelector: React.FC = () => { 5 | const tolgee = useTolgee(['pendingLanguage']); 6 | 7 | return ( 8 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /testapps/react/src/components/Namespaces.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslate, T } from '@tolgee/react'; 2 | 3 | export const Namespaces = () => { 4 | const { t } = useTranslate('namespaced'); 5 | 6 | return ( 7 |
8 |
9 |

t function with namespace

10 |
{t('this_is_a_key')}
11 |
12 | 13 |
14 |

t function with default namespace

15 |
{t('this_is_a_key', { ns: '' })}
16 |
17 | 18 |
19 |

T component with namespace

20 |
21 | 22 |
23 |
24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /testapps/react/src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { LangSelector } from './LangSelector'; 2 | 3 | export const Navbar = ({ children }: React.PropsWithChildren) => { 4 | return ( 5 |
6 | {children} 7 | 8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /testapps/react/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import { App } from './App.tsx'; 4 | import './style.css'; 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /testapps/react/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /testapps/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /testapps/react/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /testapps/react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | clearScreen: false, 8 | }); 9 | -------------------------------------------------------------------------------- /testapps/svelte/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | .netlify 7 | .wrangler 8 | /.svelte-kit 9 | /build 10 | 11 | # OS 12 | .DS_Store 13 | Thumbs.db 14 | 15 | # Env 16 | .env 17 | .env.* 18 | !.env.example 19 | !.env.test 20 | 21 | # Vite 22 | vite.config.js.timestamp-* 23 | vite.config.ts.timestamp-* 24 | -------------------------------------------------------------------------------- /testapps/svelte/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /testapps/svelte/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://svelte.dev/docs/kit/types#app.d.ts 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface PageState {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /testapps/svelte/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %sveltekit.head% 9 | 10 | 11 |
%sveltekit.body%
12 | 13 | 14 | -------------------------------------------------------------------------------- /testapps/svelte/src/component/LangSelector.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /testapps/svelte/src/component/Namespaces.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | {#if $isLoading} 7 |
Loading namespace...
8 | {:else} 9 |
10 |
11 |

t function with namespace

12 |
{$t('this_is_a_key')}
13 |
14 | 15 |
16 |

t function with default namespace

17 |
{$t('this_is_a_key', { ns: '' })}
18 |
19 | 20 |
21 |

T component with namespace

22 |
23 | 24 |
25 |
26 |
27 | {/if} 28 | -------------------------------------------------------------------------------- /testapps/svelte/src/component/Navbar.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 16 | -------------------------------------------------------------------------------- /testapps/svelte/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /testapps/svelte/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolgee/tolgee-js/ea8ffc97dcfec4a1ea7b06abde18d35e208cfe91/testapps/svelte/static/favicon.png -------------------------------------------------------------------------------- /testapps/svelte/static/i18n/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/svelte/static/i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/svelte/static/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/svelte/static/i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/svelte/static/i18n/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /testapps/svelte/static/i18n/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /testapps/svelte/static/i18n/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /testapps/svelte/static/i18n/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /testapps/svelte/static/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/svelte/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://svelte.dev/docs/kit/integrations 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. 12 | // If your environment is not supported, or you settled on a specific environment, switch out the adapter. 13 | // See https://svelte.dev/docs/kit/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /testapps/svelte/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "moduleResolution": "bundler" 13 | } 14 | // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias 15 | // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files 16 | // 17 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 18 | // from the referenced tsconfig.json - TypeScript does not merge them in 19 | } 20 | -------------------------------------------------------------------------------- /testapps/svelte/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | clearScreen: false, 7 | }); 8 | -------------------------------------------------------------------------------- /testapps/vanilla/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /lib 5 | 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? -------------------------------------------------------------------------------- /testapps/vanilla/apps/base/index.js: -------------------------------------------------------------------------------- 1 | import { Tolgee, DevTools, BackendFetch } from '@tolgee/web'; 2 | 3 | const bundleDivElement = document.createElement('div'); 4 | 5 | const tolgee = Tolgee() 6 | .use(DevTools()) 7 | .use(BackendFetch({ prefix: 'i18n' })) 8 | .init({ 9 | defaultLanguage: 'en', 10 | observerType: 'text', 11 | }); 12 | 13 | document.body.append(bundleDivElement); 14 | 15 | const htmlParagraphElement = document.createElement('p'); 16 | 17 | bundleDivElement.append(htmlParagraphElement); 18 | 19 | tolgee.run().then(() => { 20 | const translation = tolgee.t('test'); 21 | htmlParagraphElement.append(translation); 22 | bundleDivElement.append('%-%tolgee:test%-%'); 23 | }); 24 | -------------------------------------------------------------------------------- /testapps/vanilla/public/i18n/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": "Toto je text", 3 | "test_param": "Toto je text s parametrem: {param}." 4 | } 5 | -------------------------------------------------------------------------------- /testapps/vanilla/public/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": "This is test text!", 3 | "test_param": "This is text with param: {param}.", 4 | "this_is_mentioned_just_in_english": "This is just in english.", 5 | "missing_in_current": "I am missing in current" 6 | } 7 | -------------------------------------------------------------------------------- /testapps/vue-i18next/.env: -------------------------------------------------------------------------------- 1 | VUE_APP_TOLGEE_API_URL=https://app.tolgee.io 2 | VUE_APP_TOLGEE_API_KEY= -------------------------------------------------------------------------------- /testapps/vue-i18next/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /dist-e2e 5 | 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /testapps/vue-i18next/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /testapps/vue-i18next/public/i18n/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue-i18next/public/i18n/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue-i18next/public/i18n/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue-i18next/public/i18n/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /testapps/vue-i18next/public/i18n/translation/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/vue-i18next/public/i18n/translation/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/vue-i18next/public/i18n/translation/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/vue-i18next/public/i18n/translation/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/vue-i18next/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/vue-i18next/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Tolgee vue i18next example 10 | 11 | 12 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /testapps/vue-i18next/src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 26 | -------------------------------------------------------------------------------- /testapps/vue-i18next/src/components/LangSelector.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 24 | -------------------------------------------------------------------------------- /testapps/vue-i18next/src/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /testapps/vue-i18next/src/i18n.js: -------------------------------------------------------------------------------- 1 | import { 2 | BackendFetch, 3 | DevTools, 4 | I18nextPlugin, 5 | Tolgee, 6 | withTolgee, 7 | } from '@tolgee/i18next'; 8 | import i18next from 'i18next'; 9 | import ICU from 'i18next-icu'; 10 | 11 | export const tolgee = Tolgee() 12 | .use(DevTools()) 13 | .use(BackendFetch()) 14 | .use(I18nextPlugin()) 15 | .init({ 16 | apiUrl: process.env.VUE_APP_TOLGEE_API_URL, 17 | apiKey: process.env.VUE_APP_TOLGEE_API_KEY, 18 | }); 19 | 20 | withTolgee(i18next, tolgee) 21 | .use(ICU) 22 | .init({ 23 | lng: 'en', // or use i18next language detector 24 | supportedLngs: ['cs', 'en', 'fr', 'de'], 25 | }); 26 | 27 | export { i18next }; 28 | -------------------------------------------------------------------------------- /testapps/vue-i18next/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import i18nextVue from 'i18next-vue'; 3 | 4 | import { i18next } from './i18n'; 5 | import App from './App.vue'; 6 | 7 | createApp(App).use(i18nextVue, { i18next }).mount('#app'); 8 | -------------------------------------------------------------------------------- /testapps/vue-ssr/.env: -------------------------------------------------------------------------------- 1 | VITE_APP_TOLGEE_API_URL=https://app.tolgee.io 2 | VITE_APP_TOLGEE_API_KEY= -------------------------------------------------------------------------------- /testapps/vue-ssr/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | 30 | tsconfig.tsbuildinfo 31 | 32 | vite.config.ts.* 33 | tsconfig.tsbuildinfo -------------------------------------------------------------------------------- /testapps/vue-ssr/components/LangSelector.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /testapps/vue-ssr/components/Namespaces.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 27 | -------------------------------------------------------------------------------- /testapps/vue-ssr/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /testapps/vue-ssr/pages/+Layout.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /testapps/vue-ssr/pages/+data.ts: -------------------------------------------------------------------------------- 1 | import { getServerLocales } from '../tolgee'; 2 | 3 | export const data = async () => { 4 | const locales = await getServerLocales('en'); 5 | return locales; 6 | }; 7 | -------------------------------------------------------------------------------- /testapps/vue-ssr/pages/index/+Page.vue: -------------------------------------------------------------------------------- 1 | 4 | 7 | -------------------------------------------------------------------------------- /testapps/vue-ssr/pages/translation-methods/+Page.vue: -------------------------------------------------------------------------------- 1 | 4 | 7 | -------------------------------------------------------------------------------- /testapps/vue-ssr/public/i18n/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/vue-ssr/public/i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/vue-ssr/public/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/vue-ssr/public/i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}" 12 | } -------------------------------------------------------------------------------- /testapps/vue-ssr/public/i18n/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue-ssr/public/i18n/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue-ssr/public/i18n/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue-ssr/public/i18n/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /testapps/vue-ssr/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/vue-ssr/renderer/+config.ts: -------------------------------------------------------------------------------- 1 | import vikeVue from 'vike-vue/config'; 2 | 3 | export default { 4 | extends: [vikeVue], 5 | passToClient: ['lang'], 6 | }; 7 | -------------------------------------------------------------------------------- /testapps/vue-ssr/renderer/+onCreateApp.ts: -------------------------------------------------------------------------------- 1 | import { VueTolgee } from '@tolgee/vue'; 2 | import { createTolgee } from '../tolgee'; 3 | 4 | export const onCreateApp = (pageContext) => { 5 | const { app } = pageContext; 6 | const tolgee = createTolgee(); 7 | 8 | app.use(VueTolgee, { tolgee, enableSSR: true }); 9 | }; 10 | -------------------------------------------------------------------------------- /testapps/vue-ssr/server/root.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-when-using-the-experimental-modules-flag/50052194#50052194 2 | 3 | import { dirname } from "path"; 4 | import { fileURLToPath } from "url"; 5 | const __dirname = dirname(fileURLToPath(import.meta.url)); 6 | export const root = `${__dirname}/..`; 7 | -------------------------------------------------------------------------------- /testapps/vue-ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.node.json", 3 | "include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "types": ["node"], 7 | "skipLibCheck": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /testapps/vue-ssr/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url'; 2 | 3 | import { defineConfig } from 'vite'; 4 | import vue from '@vitejs/plugin-vue'; 5 | import vueJsx from '@vitejs/plugin-vue-jsx'; 6 | import vike from 'vike/plugin'; 7 | 8 | // https://vitejs.dev/config/ 9 | export default defineConfig({ 10 | plugins: [vue(), vueJsx(), vike()], 11 | resolve: { 12 | alias: { 13 | '@': fileURLToPath(new URL('./src', import.meta.url)), 14 | }, 15 | }, 16 | clearScreen: false, 17 | }); 18 | -------------------------------------------------------------------------------- /testapps/vue/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | -------------------------------------------------------------------------------- /testapps/vue/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import type { TFnType, TolgeeInstance } from '@tolgee/vue'; 4 | -------------------------------------------------------------------------------- /testapps/vue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vite App 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /testapps/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tolgee/vue-testapp", 3 | "version": "6.2.5", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite", 7 | "develop": "vite dev", 8 | "build": "run-p type-check build-only", 9 | "preview": "vite preview", 10 | "build-only": "vite build", 11 | "type-check": "vue-tsc --noEmit" 12 | }, 13 | "dependencies": { 14 | "@tolgee/format-icu": "6.2.5", 15 | "@tolgee/vue": "6.2.5", 16 | "vue": "^3.2.45" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^18.11.12", 20 | "@vitejs/plugin-vue": "^4.0.0", 21 | "@vitejs/plugin-vue-jsx": "^3.0.0", 22 | "@vue/tsconfig": "^0.1.3", 23 | "npm-run-all": "^4.1.5", 24 | "typescript": "~4.7.4", 25 | "vite": "^4.0.0", 26 | "vue-tsc": "^1.0.12" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /testapps/vue/public/i18n/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Přidat", 3 | "add-item-input-placeholder" : "Nová položka seznamu", 4 | "app-title" : "Co sbalit", 5 | "delete-item-button" : "Smazat", 6 | "menu-item-translation-methods" : "Metody překládání", 7 | "send-via-email" : "Odeslat e-mailem", 8 | "share-button" : "Sdílet", 9 | "this_is_a_key" : "Toto je klíč", 10 | "this_is_a_key_with_params" : "Toto je klíč s parametry {key} {key2}", 11 | "this_is_a_key_with_tags" : "Toto je klíč s tagy bold {key}", 12 | "value": "hodnota" 13 | } -------------------------------------------------------------------------------- /testapps/vue/public/i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Einfügen", 3 | "add-item-input-placeholder" : "Neuer Eintrag", 4 | "app-title" : "Was mitnehmen", 5 | "delete-item-button" : "Löschen", 6 | "menu-item-translation-methods" : "Übersetzungsmethoden", 7 | "send-via-email" : "Per Email abschicken", 8 | "share-button" : "Teilen", 9 | "this_is_a_key" : "Dies ist ein Schlüssel", 10 | "this_is_a_key_with_params" : "Dies ist ein Schlüssel mit den Parametern {key} {key2}", 11 | "this_is_a_key_with_tags" : "Dies ist ein Schlüssel mit den Tags bold {key}", 12 | "value": "Wert" 13 | } -------------------------------------------------------------------------------- /testapps/vue/public/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Add", 3 | "add-item-input-placeholder" : "New list item", 4 | "app-title" : "What To Pack", 5 | "delete-item-button" : "Delete", 6 | "menu-item-translation-methods" : "Translation methods", 7 | "send-via-email" : "Send via e-mail", 8 | "share-button" : "Share", 9 | "this_is_a_key" : "This is a key", 10 | "this_is_a_key_with_params" : "This is key with params {key} {key2}", 11 | "this_is_a_key_with_tags" : "This is a key with tags bold {key}", 12 | "value": "value" 13 | } -------------------------------------------------------------------------------- /testapps/vue/public/i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "add-item-add-button" : "Ajouter", 3 | "add-item-input-placeholder" : "Nouveau élément de la liste", 4 | "app-title" : "Quoi emballer", 5 | "delete-item-button" : "Supprimer", 6 | "menu-item-translation-methods" : "Méthodes de la traduction", 7 | "send-via-email" : "Envoyer par e-mail", 8 | "share-button" : "Partager", 9 | "this_is_a_key" : "C'est un clé", 10 | "this_is_a_key_with_params" : "C'est la clé avec paramètres {key} {key2}", 11 | "this_is_a_key_with_tags" : "C'est la clé avec des tags bold {key}", 12 | "value": "valeur" 13 | } -------------------------------------------------------------------------------- /testapps/vue/public/i18n/namespaced/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Toto je klíč v namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue/public/i18n/namespaced/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Dies ist ein Schlüssel im Namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue/public/i18n/namespaced/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "This is a key in namespace" 3 | } -------------------------------------------------------------------------------- /testapps/vue/public/i18n/namespaced/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "this_is_a_key" : "Ceci est une clé dans l'espace de noms" 3 | } -------------------------------------------------------------------------------- /testapps/vue/public/img/iconMail.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /testapps/vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 23 | -------------------------------------------------------------------------------- /testapps/vue/src/components/LangSelector.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /testapps/vue/src/components/Namespaces.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 27 | -------------------------------------------------------------------------------- /testapps/vue/src/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /testapps/vue/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import { Tolgee, DevTools, VueTolgee, BackendFetch } from '@tolgee/vue'; 4 | import { FormatIcu } from '@tolgee/format-icu'; 5 | 6 | const tolgee = Tolgee() 7 | .use(DevTools()) 8 | .use(FormatIcu()) 9 | .use(BackendFetch()) 10 | .init({ 11 | language: 'en', 12 | apiUrl: import.meta.env.VITE_TOLGEE_API_URL, 13 | apiKey: import.meta.env.VITE_TOLGEE_API_KEY, 14 | }); 15 | 16 | const app = createApp(App); 17 | 18 | app.use(VueTolgee, { tolgee }); 19 | app.mount('#app'); 20 | -------------------------------------------------------------------------------- /testapps/vue/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module '*.vue' { 3 | import type { DefineComponent } from 'vue' 4 | const component: DefineComponent<{}, {}, any> 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /testapps/vue/tsconfig.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.node.json", 3 | "include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "types": ["node"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /testapps/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.web.json", 3 | "include": ["env.d.ts", "src/**/*.ts", "src/**/*.vue"], 4 | "compilerOptions": { 5 | "allowJs": true, 6 | "baseUrl": ".", 7 | "paths": { 8 | "@/*": ["./src/*"] 9 | }, 10 | }, 11 | 12 | "references": [ 13 | { 14 | "path": "./tsconfig.config.json" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /testapps/vue/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url'; 2 | 3 | import { defineConfig } from 'vite'; 4 | import vue from '@vitejs/plugin-vue'; 5 | import vueJsx from '@vitejs/plugin-vue-jsx'; 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [vue(), vueJsx()], 10 | resolve: { 11 | alias: { 12 | '@': fileURLToPath(new URL('./src', import.meta.url)), 13 | }, 14 | }, 15 | clearScreen: false, 16 | }); 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "esModuleInterop": true 5 | }, 6 | 7 | } --------------------------------------------------------------------------------