Giter Club home page Giter Club logo

Comments (12)

reZach avatar reZach commented on September 13, 2024 1

Thanks for reporting this @lags. I've pushed an update and I'm now seeing the translation files output when npm run dist-windows (and other platforms should work as well). Please re-open this if you continue to experience problems with this template 😄

image

from secure-electron-template.

reZach avatar reZach commented on September 13, 2024 1

Thanks @pczyzyk. Your code looks good for me and so I pushed a new version of the template with it in there. You should be good now.

from secure-electron-template.

pczyzyk avatar pczyzyk commented on September 13, 2024 1

@dotexe0 finally your i18n.mainconfig.js should look like:

const isMac = process.platform === 'darwin'
const isDev = process.env.NODE_ENV === 'development'
const prepend = isMac && !isDev ? path.join(process.resourcesPath, '..') : '.'

i18n.use(backend).init({
  backend: {
    loadPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.json',
    addPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.missing.json',
  },`

but the i18n.config.js is a little more tricky:

const isMac = window.api.platform === 'darwin'
const isDev = process.env.NODE_ENV === 'development'

const prepend = isMac && !isDev ? window.api.app.appExtraFilesPath : '.'

i18n
  .use(i18nBackend)
  .use(reactI18Next.initReactI18next)
  .init({
    backend: {
      loadPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.json',
      addPath:
        prepend + '/app/localization/locales/{{lng}}/{{ns}}.missing.json',
      ipcRenderer: window.api.i18nextElectronBackend,
    },

then you need to set those two variables (window.api.platform and window.api.app.appExtraFilesPath) in main.js and preload.js. Platform is really straightforward, but for appExtraFilesPath I use:

path.join(process.resourcesPath, '..')

Everything is working just fine in both dev and prod with that setup

from secure-electron-template.

dotexe0 avatar dotexe0 commented on September 13, 2024 1

@reZach Here's what I did -- it is working as expected:

preload.js The important part is the last 2 fields (app & platform)

...
contextBridge.exposeInMainWorld('api', { 
  sendIpcMessage: async function (name, requestData) {
    return new Promise((resolve) => {
      ipcRenderer.send(name, requestData);
      ipcRenderer.on(name, (event, responseData) => {
        resolve(responseData);
      });
    });
  },

  receiveIpcMessage: function (name, callback) {
    ipcRenderer.on(name, (event, responseData) => {
      callback(responseData);
    });
  },
  i18nextElectronBackend: i18nextBackend.preloadBindings(ipcRenderer),
  app: {
    appExtraFilesPath: path.join(process.resourcesPath, '..')
  },
  platform: process.platform
});

i18n.config.js

import i18n from 'i18next';
import * as reactI18Next from 'react-i18next';
import i18nBackend from 'i18next-electron-fs-backend';

// On Mac, the folder for resources isn't
// in the same directory as Linux/Windows;
// https://www.electron.build/configuration/contents#extrafiles

const isMac = window.api.platform === 'darwin'; // <-- field is sourced from preload.js
const isDev = process.env.NODE_ENV === 'development';

const prependPath = isMac && !isDev ? window.api.app.appExtraFilesPath : '.'; <-- field is sourced from preload.js

i18n
  .use(i18nBackend)
  .use(reactI18Next.initReactI18next)
  .init({
    backend: {
      loadPath: prependPath + '/app/localization/locales/{{lng}}/{{ns}}.json',
      addPath: prependPath + '/app/localization/locales/{{lng}}/{{ns}}.missing.json',
      ipcRenderer: window.api.i18nextElectronBackend
    },
    debug: true,
    ns: ['common', 'external'],
    lng: ['en', 'fr', 'es'],
    interpolation: {
      escapeValue: false
    },
    fallbackLng: false // set to false when generating translation files locally
  });

window.api.i18nextElectronBackend.onLanguageChange((args) => {
  i18n.changeLanguage(args.lng, (error, t) => {
    if (error) {
      console.warn('t function', t);
      console.error('translation error', error);
    }
  });
});

export { i18n };

The other files were left as-is since they were already working.

from secure-electron-template.

pczyzyk avatar pczyzyk commented on September 13, 2024 1

@dotexe0 's solution is fine, but I needed to use some more platform specific paths all over the app, so I used electron-cfg module and set three parameters in main.js:

const cfg = require('electron-cfg')
async function createWindow() {
(...)
  cfg.file('app.json')
  cfg.set('appPath', app.getAppPath().replace('/Resources/app.asar', ''))
  cfg.set('appExecPath', process.execPath)
  cfg.set('appExtraFilesPath', path.join(process.resourcesPath, '..'))
(...)
}

Then I'm setting a window.api.app variable in preload.js like this:

const appCfg = JSON.parse(fs.readFileSync(pathApp, 'utf8'))
contextBridge.exposeInMainWorld('api', {
  i18nextElectronBackend: i18nextBackend.preloadBindings(ipcRenderer),
  store: store.preloadBindings(ipcRenderer, fs),
  contextMenu: ContextMenu.preloadBindings(ipcRenderer),
  app: appCfg,
  platform: process.platform,
})

I'm not sure if that is the most efficient way to do that, but it enables me to access appPath appExecPath and appExtraFilesPath throughout the app and at the same time dump values to config file.

from secure-electron-template.

reZach avatar reZach commented on September 13, 2024 1

Thanks @pczyzyk and @dotexe0. This new release has these values in the template now, thanks for making this template better for all who use it. I tested this both in dev mode and after packaging the app in Windows & Mac and both changed the language (header/page) successfully.

i18n.config.js

const i18n = require("i18next").default;
const reactI18Next = require("react-i18next");
const i18nBackend = require("i18next-electron-fs-backend").default;
const whitelist = require("./whitelist");

// On Mac, the folder for resources isn't
// in the same directory as Linux/Windows;
// https://www.electron.build/configuration/contents#extrafiles
const isMac = window.api.i18nextElectronBackend.clientOptions.platform === "darwin";
const isDev = window.api.i18nextElectronBackend.clientOptions.environment === "development";
const prependPath = isMac && !isDev ? window.api.i18nextElectronBackend.clientOptions.resourcesPath : ".";

i18n
  .use(i18nBackend)
  .use(reactI18Next.initReactI18next)
  .init({
    backend: {
      loadPath: prependPath + "/app/localization/locales/{{lng}}/{{ns}}.json",
      addPath: prependPath + "/app/localization/locales/{{lng}}/{{ns}}.missing.json",
      ipcRenderer: window.api.i18nextElectronBackend
    },
    debug: false,
    namespace: "translation",
    saveMissing: true,
    saveMissingTo: "current",
    lng: "en",
    fallbackLng: false, // set to false when generating translation files locally
    whitelist: whitelist.langs
  });

window.api.i18nextElectronBackend.onLanguageChange((args) => {
  i18n.changeLanguage(args.lng, (error, t) => {
    if (error) {
      console.error(error);
    }
  });
});

module.exports = i18n;

preload.js

const { contextBridge, ipcRenderer } = require("electron");
const i18nextBackend = require("i18next-electron-fs-backend");

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld("api", {
  i18nextElectronBackend: i18nextBackend.preloadBindings(ipcRenderer, process),
});

from secure-electron-template.

pczyzyk avatar pczyzyk commented on September 13, 2024

@reZach for Darwin it is still not working correctly after npm run dist-mac. All files are there inside the package, but i18next does not seem to load them correctly. For npm run dev seems to be working just fine though.
image

That is probably because extraFiles are being copied to a slightly different location on Mac: https://www.electron.build/configuration/contents#extrafiles

from secure-electron-template.

reZach avatar reZach commented on September 13, 2024

@pczyzyk good catch. It would appear as app/localization/i18n.config.js and app/localization/i18n.mainconfig.js need to be updated in the case where the app is run from the generated application.

In these files, can you prepend "Contents" to see if this works? If it does, then I imagine a solution needs to be thought of to handle MacOS post-build, and all other scenarios that work today. I'm not yet sure what the solution would be..

 backend: {
      loadPath: "./Contents/app/localization/locales/{{lng}}/{{ns}}.json",
      addPath: "./Contents/app/localization/locales/{{lng}}/{{ns}}.missing.json",
      ipcRenderer: window.api.i18nextElectronBackend
},

from secure-electron-template.

pczyzyk avatar pczyzyk commented on September 13, 2024

@reZach that was not that trivial.
It seems that on Mac you need to provide a full path in order to reach the files in Contents folder.
So I did some quick fixes in app/localization/i18n.config.js and app/localization/i18n.mainconfig.js
eg. i18n.mainconfig.js:

const isMac = process.platform === 'darwin';
const isDev = process.env.NODE_ENV === 'development';
const prepend = isMac && !isDev ? path.join(process.resourcesPath, '..') : '.';

i18n.use(backend).init({
  backend: {
    loadPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.json',
    addPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.missing.json',
  },

I confirm that this solution is working fine on Mac dist

from secure-electron-template.

dotexe0 avatar dotexe0 commented on September 13, 2024

@reZach @pczyzyk I see it working in development mode, but not in the production build and it's pretty straightforward to replicate. Just running npm run dist-mac and running the app will show the Language menu working with i18n changes but selecting a different language will not change the language in the window (i.e. 'Hello' -> 'Hallo').

I believe it's because the logic that leverages process.resourcePath and process.platform is not available to the React application, so those values are undefined. These process values are available however to electron, so it makes sense that the menu portion works.

// app/localization/i18n.mainconfig.js
const isMac = process.platform === 'darwin'; <-- value present in process -- OK
const isDev = process.env.NODE_ENV === 'development'; <-- value present in process -- OK
const prepend = isMac && !isDev ? path.join(process.resourcesPath, '..') : '.'; <-- value present in process -- OK

i18n.use(backend).init({
  backend: {
    loadPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.json',
    addPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.missing.json',
  },
// app/localization/i18n.config.js
const isMac = process.platform === 'darwin';
const isDev = process.env.NODE_ENV === 'development'; 
const prepend = isMac && !isDev ? path.join(process.resourcesPath, '..') : '.'; 
console.log(process.platform) // <-- undefined
console.log(process.resourcePath) // <-- undefined


i18n.use(backend).init({
  backend: {
    loadPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.json',
    addPath: prepend + '/app/localization/locales/{{lng}}/{{ns}}.missing.json',
  },

Am I missing something?

from secure-electron-template.

reZach avatar reZach commented on September 13, 2024

@pczyzyk Can you share your preload.js how you helped @dotexe0? I'd like to somehow incorporate your changes into the template/proper location so this change can be used by others.

from secure-electron-template.

reZach avatar reZach commented on September 13, 2024

I re-opened this issue to keep note that this is something I need to fix in the template, thanks!

from secure-electron-template.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.