tolgee / tolgee-js

Tolgee JavaScript libraries monorepo
https://tolgee.io
MIT License
224 stars 26 forks source link

Staging build disables fetch from backend #3180

Closed pennal closed 1 year ago

pennal commented 1 year ago

Hi,

we currently have a Nuxt app that uses Tolgee for translations. We also have three different stages: dev, staging and prod. To configure Tolgee, we use the following code:

import {
  DevTools,
  FormatSimple,
  T,
  Tolgee,
  TolgeeProvider,
  VueTolgee,
} from "@tolgee/vue";

const language = useLanguage();

export default defineNuxtPlugin((nuxtApp) => {
  const { tolgee: config, isProduction } = useRuntimeConfig();

  // Tolgee config that depends on the current NUXT_DEPLOYMENT_ENV
  const tolgeeConfig = isProduction
    ? {
        // Production
        staticData: importAvailableLanguages(),
      }
    : {
        // Development
        apiUrl: config.apiUrl,
        apiKey: config.apiKey,
      };
  const tolgee = Tolgee()
    .use(DevTools())
    .use(FormatSimple())
    .init({
      language: language.value || "en",
      ...tolgeeConfig,
    });

  nuxtApp.vueApp.use(VueTolgee, { tolgee });

  nuxtApp.vueApp.component("T", T).component("TolgeeProvider", TolgeeProvider);

  return {
    provide: {
      // useTranslate: str => useTranslate(str),
      t: (str) => tolgee.t(str),
    },
  };
});

Our package.json is as follows:

"scripts": {
    "build-production": "nuxi build  --dotenv .env.production",
    "build-staging": "nuxi build --dotenv .env.staging",
    "build-dev": "nuxi build --dotenv .env",
    "dev": "nuxi dev --dotenv .env.development",
    // ...
}

Our goal is to have two different behaviours:

For staging, we want that whoever accesses the page can see the translations but not edit them. Therefore we have a read only key, that at least can display the translations. For some reason, the plugin does not fetch the translations from the backend, and therefore shows the keys we have assigned to them.

My suspicion is that once we run the build-staging script, nuxi sets the NODE_ENV to production and Tolgee then automatically switches off some setting. Is this the case? I found something that may be related in #3153, but I am not sure.

stepan662 commented 1 year ago

Hey, yes once you do production build, the DevTools are ommited based on NODE_ENV.

What you can do in this case is to use InContextTools exported in @tolgee/web/tools, which is essentialy the same thing as DevTools only independent on NODE_ENV.

https://tolgee.io/js-sdk/api/web_package/tools#incontexttools

However this will increase your bundle size significantly, so i would do this through dynamic import only if isProduction is true.

Something like this:

  const tolgee = Tolgee()
    .use(FormatSimple())
    .init({
      language: language.value || "en",
      ...tolgeeConfig,
    });

...

if (isProduction) {
  import('@tolgee/web/tools').then((module) => {
    tolgee.addPlugin(module.InContextTools())
  })
}
stepan662 commented 1 year ago

However, be aware that your staging shouldn't be publicly visible as your key will be included in the page.

pennal commented 1 year ago

Thank you, that solved the issue!

I understand that keys will be leaked, but this is a staging env that is behind auth. So I am not really worried about leaking data.

Maybe it would be good to add this info in the Docs? I know I would have appreciated seeing this a few days ago

stepan662 commented 1 year ago

Cool, thanks for feedback. I'll make an issue for that 👍

4F2E4A2E commented 6 months ago

Could someone provide a nuxt example? This is how far I've come:

"devDependencies": {
    "@nuxt/devtools": "1.0.8",
    "nuxt": "3.11.1",
    "typescript": "^5.4.2",
    "vue": "3.4.21",
    "vue-router": "4.3.0",
    "vue-tsc": "^2.0.6"
  },
  "dependencies": {
    "@tolgee/vue": "^5.22.0",
    "@formkit/nuxt": "1.6.0",
    "@nuxtjs/i18n": "8.2.0",
    "@nuxt/ui": "2.14.2"
  }
// nuxt.config.ts

export default defineNuxtConfig({
    ssr: false,
    srcDir: "src",
    css: ["~/assets/css/main.css"],
    devtools: {enabled: true},
    modules: ["@nuxt/ui"],
    colorMode: {
        preference: "light",
    },
    typescript: {
        typeCheck: false,
        strict: true,
    },
    plugins: [
        '~/plugins/tolgee.ts'
    ],
});
// plugins/tolgee.ts
import {FormatSimple} from "@tolgee/core";
import {DevTools, Tolgee} from "@tolgee/web";
import {T, TolgeeProvider, VueTolgee} from "@tolgee/vue/lib";

export default defineNuxtPlugin((nuxtApp) => {
    const {tolgee: config, isProduction} = useRuntimeConfig();

    const tolgee = Tolgee()
        .use(DevTools())
        .use(FormatSimple())
        .init(({
            language: 'en',
            apiUrl: process.env.VUE_APP_TOLGEE_API_URL,
            apiKey: process.env.VUE_APP_TOLGEE_API_KEY,
        }));

    nuxtApp.vueApp.use(VueTolgee, {tolgee});
    nuxtApp.vueApp.component("T", T).component("TolgeeProvider", TolgeeProvider);

    return {
        provide: {
            // useTranslate: str => useTranslate(str),
            t: (str: string) => tolgee.t(str),
        },
    };
});
[8:16:47 PM]  ERROR  Nuxt Build Error: [vite]: Rollup failed to resolve import "src/plugins/tolgee.ts" from "virtual:nuxt:.nuxt/plugins/client.mjs".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
build.rollupOptions.external

  This is most likely unintended because it can break your application at runtime.
  If you do want to externalize this module explicitly add it to
  build.rollupOptions.external
  at viteWarn (node_modules/vite/dist/node/chunks/dep-jvB8WLp9.js:67190:27)
  at onRollupWarning (node_modules/vite/dist/node/chunks/dep-jvB8WLp9.js:67218:9)
  at onwarn (node_modules/vite/dist/node/chunks/dep-jvB8WLp9.js:66922:13)
  at node_modules/rollup/dist/es/shared/node-entry.js:18303:13
  at Object.logger [as onLog] (node_modules/rollup/dist/es/shared/node-entry.js:19950:9)
  at ModuleLoader.handleInvalidResolvedId (node_modules/rollup/dist/es/shared/node-entry.js:18893:26)
  at node_modules/rollup/dist/es/shared/node-entry.js:18851:26

error: script "build" exited with code 1
4F2E4A2E commented 6 months ago

I have also come across this nuxt-tolgee package, but I have not tried it yet: https://git.deditoolbox.fr/mlcsthor/nuxt-tolgee

stepan662 commented 6 months ago

Hi, I'm not able to provide nuxt example, but I think this is not correct import {T, TolgeeProvider, VueTolgee} from "@tolgee/vue/lib";. It should be @tolgee/vue

pennal commented 6 months ago

This is what we are using in a nuxt app. It is stripped to the bare minimum, so you might have to adapt it to your situation:

// package.json
// ...
"dependencies": {
    // ...
    "@tolgee/vue": "^5.2.1"
   // ...
}
// ...
// plugins/vue-tolgee.js
import { FormatSimple, T, Tolgee, TolgeeProvider, VueTolgee } from '@tolgee/vue';

export default defineNuxtPlugin((nuxtApp) => {
  const tolgee = Tolgee()
    .use(FormatSimple())
    .init({
      language: 'en', // You need to supply your own way of switching the language
      apiUrl:'<YOUR_API_URL>',
      apiKey: '<YOUR_API_KEY>',
    });

  nuxtApp.vueApp.use(VueTolgee, { tolgee });

  nuxtApp.vueApp.component('T', T).component('TolgeeProvider', TolgeeProvider);

  return {
    provide: {
      // useTranslate: str => useTranslate(str),
      t: str => tolgee.t(str),
    },
  };
});

Since plugins are autoregistered (docs) in theory there is no need to import it manually.

Then to translate your text:

<p>{{ $t('your.translation.key') }}</p>
4F2E4A2E commented 6 months ago

Hi, I'm not able to provide nuxt example, but I think this is not correct import {T, TolgeeProvider, VueTolgee} from "@tolgee/vue/lib";. It should be @tolgee/vue

You're right, after git cloning and reinstalling everything the import error is gone. Thank you!

Now I have the plugin as typescript loaded, but nothing happens. It does not even try to fetch the translations.

// plugins/vue-tolgee.ts

import {FormatSimple, T, Tolgee, TolgeeProvider, useTranslate, VueTolgee} from "@tolgee/vue";

export default defineNuxtPlugin(nuxtApp => {
    const tolgee = Tolgee()
        .use(FormatSimple())
        .init({
            language: 'en',
            apiUrl: process.env.TOLGEE_API_URL,
            apiKey: process.env.TOLGEE_API_KEY,
        });

    nuxtApp.vueApp.use(VueTolgee, {tolgee});
    nuxtApp.vueApp.component('T', T).component('TolgeeProvider', TolgeeProvider);

    console.log('Tolgee initialized', tolgee.t('login-title'));

    return {
        provide: {
            useTranslate: (str: string) => useTranslate(str),
            t: (str: string) => tolgee.t(str),
        },
    };
})
<script lang="ts" setup>
const { $t, $useTranslate } = useNuxtApp()
console.log($useTranslate("login-title"))
</script>