Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: Change default English(US) Language (Properties->Details) #672

Closed
dharders opened this issue Aug 16, 2016 · 15 comments · Fixed by con-cis/mc-docu#27 · 4 remaining pull requests
Closed

Windows: Change default English(US) Language (Properties->Details) #672

dharders opened this issue Aug 16, 2016 · 15 comments · Fixed by con-cis/mc-docu#27 · 4 remaining pull requests

Comments

@dharders
Copy link

dharders commented Aug 16, 2016

  • Version: 5.26.0
  • Target: Windows

This is a follow up to #655

I'm working on a fix to enable Windows users to set the default language of the App.exe, Setup.exe etc. (currently set to English (US) for all exe's).

atom/rcedit would be the ideal repo to take care of this, but I grew tired of waiting for a response from the maintainers. So here is my simple node script to modify the language / locale id :

'use strict';

const fs = require('fs'); 
                      // T r a n s l a t i o n  0x09 0x04    ( English (US) 16-bit word suffix )     
const keywordBuffer = [0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04]; 
const keywordLength = keywordBuffer.length;
var buffer;

try {
  var filename = './App.exe';  // hard-coded for simplicity  (script variable TODO)
  var fd = fs.openSync(filename, 'r+'); // read + write
  buffer = fs.readFileSync(fd);
  console.log(`Input File read: ${buffer.length} bytes`);

  var modified = false;
  for (var i = 0; i < buffer.length - keywordLength; i++) {
    if (keywordMatch(i)) {
      console.log('Language found at decimal address', i);
      buffer[i + 26] = 0x09;   // Language: English
      buffer[i + 27] = 0x0c;   // Sublanguage: Australia   see https://msdn.microsoft.com/en-au/goglobal/bb964664.aspx?f=255&MSPPError=-2147217396   for all valid hex locale ids 
      modified = true;
    }
  }
  if (modified) {
    fs.writeSync(fd, buffer, 0, buffer.length, 0);
    console.log('Language Updated!');
  } else {
    console.log('US language not found. File NOT modified!');
  } 
  fs.closeSync(fd);
} catch (err) {
  console.log(`There was an error: ${err}`);
}

function keywordMatch(index) {
  var i = 0;
  while (i < keywordLength) {
    if (keywordBuffer[i] === buffer[index]) {
      i++;
      index++;
    } else {
      return false;
    }
  }
  return true;
}

Notes:

  • I've hard-coded the filename above for simplicity. This should accept a variable.
  • This script is set to overwrite the file (can be easily modified not to)
  • The new language is hard-coded to English (Australia) for simplicity. (again, will be variable)
  • The Windows Locale ID's can be found here (I'm using HEX, also note the ordering)
  • I'd imagine this could be expanded to an optional build.win.localeId = "0x0c09" where the user looks the locale id up manually ?
  • App.exe, Setup.exe (Squirrel), Setup.exe (NSIS) all display the new Language when you right-click->Properties->Details
  • App.exe and Setup.exe (Squirrel) both function as normal

Remaining Issues To Solve

  • NSIS performs some sort of CRC check at startup. Any modification after build, results in an error on setup file open. Any idea how to get around this ?
@develar
Copy link
Member

develar commented Aug 16, 2016

NSIS

For NSIS installer we don't use rcedit. VIAddVersionKey (or another NSIS instruction) should be used instead.

I'm working on a fix to enable Windows users to set the default language of the App.exe, Setup.exe etc.

Does it matter? Where this key is used?

I've hard-coded the filename above for simplicity. This should accept a command-line arg

Script will be and should be used not as CLI, but as in-process. It can be integrated into electron-builder sources. But I don't like it — it is better just fix rcedit. We bundle own version of rcedit in any case (not from npm).

@dharders
Copy link
Author

VIAddVersionKey (or another NSIS instruction) should be used instead.

I agree. In the past I had to create my own English_AU.nlf file and manually set the localeid (as explained here. Are you intending to implement this into electron-builder ? That would be great !

Where this key is used?

When the user opens or views the file properties (Properties->Details). Everything else electron-builder sets (file version, trademark etc) is listed there so why not language too ?

Does it matter?

It's not a deal breaker for myself (since English US is acceptable for English Australia where my company is located) but I would imagine it's more professional for devs who wish to release other than English.

Script will be and should be used

Makes it easier then.

it is better just fix rcedit

Sure, just trying to help ;)

@develar
Copy link
Member

develar commented Aug 16, 2016

Are you intending to implement this into electron-builder ? That would be great !

PR welcome. Thanks for info, I was not aware of that.

it is better just fix rcedit

I am afraid that your approach is not so robust as rcedit, so, it is better to fix rcedit than manually change bytes.

@dharders
Copy link
Author

rcedit

I did attempt this at first, but my c++ skills are lacking (I've been using c# too long now!) and it made my head hurt

PR welcome. Thanks for info, I was not aware of that.

It shouldn't be too hard to automate a script to make a copy of the ${NSISDIR}\Contrib\Language Files\English.nlf file and set the localeid. Might have to investigate other language templates.

The same technique could be used for the ${NSISDIR}\Contrib\Contrib\Modern UI\Language files\English.nsh file too, instead updating the contents with MUI_LANGUAGEFILE_BEGIN "ENGLISH{{suffix}}".

I'll see what I can do, but I'm pretty short on time at the moment (I'm sure you are too!).

@dharders
Copy link
Author

dharders commented Aug 17, 2016

Found an easy fix for NSIS language setting (No need to create own language files etc).

Change src/targets/nsis.ts#L122-L130 From:

const versionKey = [
  `ProductName "${appInfo.productName}"`,
  `ProductVersion "${appInfo.version}"`,
  `CompanyName "${appInfo.companyName}"`,
  `LegalCopyright "${appInfo.copyright}"`,
  `FileDescription "${appInfo.description}"`,
  `FileVersion "${appInfo.buildVersion}"`,
]
use(this.packager.platformSpecificBuildOptions.legalTrademarks, it => versionKey.push(`LegalTrademarks "${it}"`))

To:

const localeId = appInfo.localeId;     // arg from build.win  (decimal)
const versionKey = [
  `/LANG=${localeId} ProductName "${appInfo.productName}"`,
  `/LANG=${localeId} ProductVersion "${appInfo.version}"`,
  `/LANG=${localeId} CompanyName "${appInfo.companyName}"`,
  `/LANG=${localeId} LegalCopyright "${appInfo.copyright}"`,
  `/LANG=${localeId} FileDescription "${appInfo.description}"`,
  `/LANG=${localeId} FileVersion "${appInfo.buildVersion}"`,
]
use(this.packager.platformSpecificBuildOptions.legalTrademarks, it => versionKey.push(`/LANG=${localeId} LegalTrademarks "${it}"`))

This now works without CRC check fail!

@dharders
Copy link
Author

dharders commented Aug 18, 2016

it is better to fix rcedit than manually change bytes.

Looking at the atom/rcedit source code, essentially they seem to just change bytes too.

your approach is not so robust as rcedit

I agree it appears hacky, but it works (it only changes 2-bytes). As long as you only use it on the files that you use rcedit for (i.e. non-NSIS) AND only use it BEFORE code-signing.

Remaining Issues To Solve - NSIS performs some sort of CRC check at startup

Now solved with the code above this comment by setting /LANG=${localeId} before each versionKey.

Since it's now possible to set the Language for all Windows targets with the above solutions I'm unlikely to do anymore work on this. I understand if you want to wait for an official rcedit solution.

@develar
Copy link
Member

develar commented Aug 20, 2016

language added to build.nsis.
screen shot 2016-08-20 at 18 16 31

@dharders
Copy link
Author

Great. Small correction on your latest commit: you missed a /LANG=${localeId} on the trademark, which is outside of the versionKey array, just below in the use(this.packager.platformSpecificBuildOptions.legalTrademarks, ...)

I don't think this oversight results in changing anything though. But best to be complete. AFAIK it's the FileVersion that actually sets the language, but it's best to set them all.

@dharders
Copy link
Author

Actually, it errors when build.nsis.language is set to something other than 1033 AND legalTrademarks is set (electron-builder 5.34.1):

nsiserror
(click to zoom)

Fix: Change src/targets/nsis.ts#L131 From:

use(this.packager.platformSpecificBuildOptions.legalTrademarks, it => versionKey.push(`LegalTrademarks "${it}"`))

To:

use(this.packager.platformSpecificBuildOptions.legalTrademarks, it => versionKey.push(`/LANG=${localeId} LegalTrademarks "${it}"`))

Also, small correction in docs/Options.md#L147. Change:

Hex LCID

To:

LCID Dec

NSIS expects decimal LCID (and I couldn't find any HEX->Decimal conversion in your code).

@dharders
Copy link
Author

dharders commented Aug 30, 2016

Ping @develar

Latest 6.3.0 release still erroring when legalTrademarks is set. See fix above.

(I would submit a PR but my dev env is windows, and currently broken)

@dharders
Copy link
Author

Thanks @develar for the fast response!

However, I think the issue should still remain open until rcedit sets language too. Currently, only NSIS does.

Thanks for your amazing work!

@develar
Copy link
Member

develar commented Aug 30, 2016

However, I think the issue should still remain open until rcedit sets language too.

Moved to backlog, marked as help-wanted and closed. I really want to finish work on #529 and currently no short-terms plans to fix it :)

@goldylucks
Copy link

goldylucks commented Jul 21, 2018

@develar is german the fallback language when a user's locale is rtl?

You posted German in this comment and our Hebrew users are seeing installer text in German.

Is there a workaround for this?
Can we set default fallback to English if user's OS language isn't supported?

btw specifically for Hebrew I can translate the text if that's all we need to get support for Hebrew language. I can't help with PR for rtl support tho, me don't know c++ :(

@develar
Copy link
Member

develar commented Jul 22, 2018

@goldylucks do you use latest electron builder?

@goldylucks
Copy link

updating tov20.24.4 seemed to do the trick, thanks @develar !!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment