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

Proper way to add locale #134

Open
Happy-Ferret opened this issue Sep 12, 2017 · 5 comments
Open

Proper way to add locale #134

Happy-Ferret opened this issue Sep 12, 2017 · 5 comments

Comments

@Happy-Ferret
Copy link

I'm desperately trying to add locales to my code, using .properties files.

What is the proper way to do this?

So far I've been trying to manually load a chrome.manifest file in the root directory, however that fails.

Here's the code I put inside main.js for a PoC.

const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm } = Components;
const ChromeRegistry = Cc['@mozilla.org/chrome/chrome-registry;1'].getService(Ci.nsIXULChromeRegistry);

const { console } = Cu.import('resource://gre/modules/Console.jsm', {});
const { Runtime } = Cu.import('resource://qbrt/modules/Runtime.jsm', {});
const { Services } = Cu.import('resource://gre/modules/Services.jsm', {});

Cu.import("resource://gre/modules/FileUtils.jsm");

var chrome = chromeToPath("chrome://app/content/chrome.manifest")
var file = new FileUtils.File(chrome);

Cm.QueryInterface(Ci.nsIComponentRegistrar).autoRegister(file);
  ChromeRegistry.checkForNewChrome();

const BUNDLE_URI = "chrome://app/locale/app.properties";
const BUNDLE = Services.strings.createBundle(BUNDLE_URI);

function chromeToPath(aPath) {
    if (!aPath || !(/^chrome:/.test(aPath)))
        return; //not a chrome url
    var rv;

    var ios = Cc['@mozilla.org/network/io-service;1'].getService(Ci["nsIIOService"]);
    var uri = ios.newURI(aPath, "UTF-8", null);
    var cr = Cc['@mozilla.org/chrome/chrome-registry;1'].getService(Ci["nsIChromeRegistry"]);
    rv = cr.convertChromeURL(uri).spec;

    if (/^file:/.test(rv))
        rv = urlToPath(rv);
    else
        rv = urlToPath("file://" + rv);
    return rv;
}

function urlToPath(aPath) {
    if (!aPath || !/^file:/.test(aPath))
        return;
    var rv;
    var ph = Cc["@mozilla.org/network/protocol;1?name=file"]
        .createInstance(Ci.nsIFileProtocolHandler);
    rv = ph.getFileFromURLSpec(aPath).path;
    return rv;
}
@Happy-Ferret
Copy link
Author

Happy-Ferret commented Sep 12, 2017

I also tried l20n (which seems to be where it's going anyways).
No dice. Despite following the tutorial, I cannot seem to instantiate the translations. Neither with dist/web nor dist/gecko.

EDIT: Correction. l20n's dist/web build does indeed work here. I just had to load it as defer

i e <script defer src="node_modules/l20n/dist/web/l20n.js"></script>

@Happy-Ferret
Copy link
Author

console.log(window.navigator.language returns nothing, thus my app always uses the <meta name="defaultLanguage" rather than the appropriate client language.

I've already tried inserting a few prefs but none of them seem to work.

      "intl.locale.matchOS": true,
      "intl.regional_prefs.use_os_locales": true,
      "services.sync.prefs.sync.intl.accept_languages": true,
      "intl.accept_languages": en-US, en",
      "general.useragent.locale": "en-US"

@mykmelez
Copy link
Contributor

So far I've been trying to manually load a chrome.manifest file in the root directory, however that fails.

Hmm, how does it fail? Does it report an error, fail silently, or do something else?

var chrome = chromeToPath("chrome://app/content/chrome.manifest")
var file = new FileUtils.File(chrome);
Cm.QueryInterface(Ci.nsIComponentRegistrar).autoRegister(file);
ChromeRegistry.checkForNewChrome(); const BUNDLE_URI = "chrome://app/locale/app.properties";

Hmm, as I understand it, this should work, if your chrome.manifest file is in the top-level directory of your app, and it contains an instruction like locale app en-US path/to/locale/, and path/to/locale/ is relative to the top-level directory of your app. If you can point me to your source, I can debug further.

Nevertheless, you're right that l20n is the future of localization for Firefox, so it's probably a better solution for your use case as well.

@mykmelez
Copy link
Contributor

console.log(window.navigator.language returns nothing, thus my app always uses the <meta name="defaultLanguage" rather than the appropriate client language.

I've already tried inserting a few prefs but none of them seem to work.

It looks like intl.accept_languages is a "complex value" pref whose value isn't the literal string to which it's set but rather comes from a file that is referenced by the pref:

http://searchfox.org/mozilla-central/source/modules/libpref/init/all.js#2312

After a bit of searching the codebase, I found some code that does something like this:

var setLocalizedPref = function (pref, value) {
  let pls = Cc["@mozilla.org/pref-localizedstring;1"]
            .createInstance(Ci.nsIPrefLocalizedString);
  pls.data = value;
  Services.prefs.setComplexValue(pref, Ci.nsIPrefLocalizedString, pls);
}
this.setLocalizedPref("intl.accept_languages", "de-de");
console.log(window.navigator.language);

Adding that to the end of examples/hello-world-html/main.js causes this line to be output on the console:

console.log: de-DE

@Happy-Ferret
Copy link
Author

It blocks the UI and displays the following error message

/qbrt/dist/win32/runtime/omni.ja!/components/nsPrompter.js, line 350: NS_ERROR_NOT_AVAILABLE: Cannot call openModalWindow on a hidden window

And thanks. The other code works. Now to figure out how to actually make use of that.
Ideally, that value should always reflect the system locale.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants