how to re-use a language file in multiple languages without doubling of files with Titanium - internationalization

So I'm using a language file in Titanium to serve TSS properties I want to re-use throughout the entire app at different locations. These language file variables should be used in the themes folder (or any other TSS file for that matter).
Currently it works with a single language, but my app has multiple languages. But I don't want to duplicate the language file for all languages. Can I re-use the same file in multiple languages without having to copy the file somewhere?

Use i18n files at ISO 639-1
representation.
That files allow you have any languages and use each "labels" with Ti.Locale.getString().
Also, you can use a require of file at app.js and put this variable like global.
language.js (for example):
var language = (function() {
var self = {
currentLanguage: 'en' // by default
};
var labels = {
msgHello: {
en: 'Hello World',
es: 'Hola Mundo'
}
};
self.changeLanguage = function changeLanguage(newLanguage){
self.currentLanguage = newLanguage;
};
self.getLabel = function getLabel(key, language){
if(typeof language !== 'undefined') {
return labels[key][language];
}
else return labels[key][self.currentLanguage];
};
return self;
}());
module.exports = language;
app.js (for example):
var appLanguage = require('language.js');
(function() {
Ti.API.info("Language: "+appLanguage.currentLanguage);
Ti.API.info("MSG Hello World (English): "+appLanguage.getLabel(msgHello));
Ti.API.info("MSG Hello World (Spanish): "+appLanguage.getLabel(msgHello, es));
}());
You can use appLanguage variable directly on any file.

It appears it is not possible to reuse a language file without copying it to all languages. However, the best solution to create a global go-to for parameters to be used in TSS files is to add a section to the config.json file.
A proper way to do this is:
"global": {
"design": {
"primaryColor": "red"
}
},
This can then be used by accessing Alloy.CFG.design.primaryColor.
The benefit for using the config.json file is that you can also theme the files, as described by Fokke Zandbergen.
This way, it is even better than using language files, because those couldn't be themed.

No, but you could use default strings like:
L('my_string','my default for this string');
In this example 'my_string' is a string withing your language file. If you only provide a file for English, you'll get the default setting for all other languages.
R

Related

Complex query variables in GraphQL (via Gatsby)

I am building a localized static website using Gatsby, with the help of gatsby-plugin-intl. This plugin adds a context variable named intl to pages (including template-based pages), which is an object: https://github.com/wiziple/gatsby-plugin-intl/blob/master/src/gatsby-node.js#L27-L34
I would like to access the intl.language variable from the context within a page query. This is my (failing) code at this stage:
query($slug: String!, $intl: String) {
contentfulPerson(slug: {eq: $slug}, node_locale: {eq: $intl.language}) {
name
}
}
Contentful is the headless CMS I use and from which I would like to fetch data in the correct locale.
Obviously this code has two problems: $intl is not a string, and $intl.language is not syntactically correct. But I don't know how to fix either problem.
I guess I could either fork the plugin or do something in my own gatsby-node.js to make the language available as a top-level variable in the context, but I'm interested to know if there is a way to do it directly.
The Gatsby docs say that query variables can be complex (https://www.gatsbyjs.org/docs/graphql-reference/#query-variables) but in the example they provide, they don't show how the types are defined or how to access a property within these variables.
EDIT : I tried moving the language to a top-level context variable in my gatsby-node.js using this code:
exports.onCreatePage = ({page, actions}) => {
const { createPage, deletePage } = actions
deletePage(page)
createPage({
...page,
context: {
...page.context,
language: page.context.intl.language
}
})
}
but the program runs out of memory (even when increasing max_old_space_size)
You can move the language field to a top-level context by doing this:
exports.onCreatePage = ({ page, actions }) => {
const { createPage, deletePage } = actions
const oldPage = Object.assign({}, page)
page.context.language = page.context.intl.language;
if (page.context.language !== oldPage.context.language) {
// Replace new page with old page
deletePage(oldPage)
createPage(page)
}
}
Checking if the field has changed avoids the infinity loop.

Constants in Parse Cloud Code

How do I implement global constants in Parse's cloud code? I have my cloud code functions divided into a few files to keep things manageable. I have constants that I need to use across these files. What's the best way to implement that in cloud code?
I figured it out. I created a module file called constants.js
module.exports = {
initialize: function() {
return this;
},
version: '1.0.0'
}
// Some constant
module.exports.SOME_CONSTANT = 0;
Then in whatever file I need it in.
var Constants = require('cloud/constants.js');
Constants.SOME_CONSTANT; // 0

Skip single file from Minifying?

I'm trying to use ASP.Nets BundleTable to optomize some javascript files, but have run into a problem where a specific addon (jQuery-Timepicker) fails to work when the code has been minified. See here.
Bundle code is currently similar to:
// Add our commonBundle
var commonBundle= new Bundle("~/CommonJS" + culture.ToString());
// JQuery and related entries.
commonBundle.Include("~/Scripts/jquery-1.7.2.js");
commonBundle.Include("~/Scripts/jquery-ui-1.8.22.js");
commonBundle.Include("~/Scripts/jquery.cookie.js");
commonBundle.Include("~/Scripts/jquery-ui/jquery-ui-timepicker-addon.js"); // This is the one that does not work when bundled
// JS Transformer
commonBundle.Transforms.Add(new JsMinify());
BundleTable.Bundles.Add(commonBundle);
If I remove the jquery-ui-timepicker-addon.js file, then include it separate in my webpage, then it works properly. (Otherwise I get the Uncaught TypeError: undefined is not a function error).
I'm wondering if I can somehow setup my bundling code to skip minifying this one file (but still have it included in the bundle)? I've been looking around but have not come up with any solutions for doing so.
So the issue is that all the files are bundled together, and then the entire bundle is minimized. As a result you aren't going to easily be able to skip minification of just one file. Probably the best way to do this would be to create a new Transform that appended the contents of this file you want unminified. Then you would append this Transform to your registered ScriptBundle:
commonBundle.Transforms.Add(new AppendFileTransform(""~/Scripts/jquery-ui/jquery-ui-timepicker-addon.js""));
AppendFileTransform would simply append the contents of the file to the bundled response. You would no longer include the timepicker in the bundle explicitly, but instead this transform would be including it, and this would effectively give you the behavior you are looking since the JsMinify transform would run first and minify the bundle, and then you would add the file you want at the end unminified.
This can be solved better from the other direction - instead of trying to not minify a single file, add transforms for individual items instead.
First - create a class that implements IItemTransform and uses the same code to minify the given input:
public class JsItemMinify : System.Web.Optimization.IItemTransform
{
public string Process(string includedVirtualPath, string input)
{
var min = new Microsoft.Ajax.Utilities.Minifier();
var result = min.MinifyJavaScript(input);
if (min.ErrorList.Count > 0)
return "/*minification failed*/" + input;
return result;
}
}
Second - add this item transform to the individual files and remove the bundle transform:
var commonBundle= new Bundle("~/CommonJS");
// the first two includes will be minified
commonBundle.Include("~/Scripts/jquery-1.7.2.js", new JsItemMinify());
commonBundle.Include("~/Scripts/jquery-ui-1.8.22.js", new JsItemMinify());
// this one will not
commonBundle.Include("~/Scripts/jquery.cookie.js");
// Remove the default JsMinify bundle transform
commonBundle.Transforms.Clear();
BundleTable.Bundles.Add(commonBundle);
You cannot setup Bundle to skip minifying certain files and to minify rest of the files.
You could implement your own Bundle or Transform by overriding Bundle.ApplyTransform or JsMinify.Process methods, but you would need to take care not to break change-tracking of files, key generation, cache invalidation, etc... (or doing some ugly hack). It's not worth the effort.
I would keep separate js file, as you already mentioned.
This is just complete example based on Hao Kung's answer
var myBundle = new ScriptBundle("~/bundles/myBundle").Include(
"~/Scripts/script1.js",
"~/Scripts/script2.js",
);
myBundle.Transforms.Add(new AppendFileTransform("~/Scripts/excludedFile.min.js"));
bundles.Add(myBundle);
And here is example implementation of the AppendFileTransform:
public class AppendFileTransform : IBundleTransform
{
private readonly string _filePath;
public AppendFileTransform(string filePath)
{
_filePath = filePath;
}
public void Process(BundleContext context, BundleResponse response)
{
response.Content += File.ReadAllText(context.HttpContext.Server.MapPath(_filePath));
}
}

Get Firefox to run XUL type script on startup

With Firefox 17.0.1 I am using an add-on called KeyConfig 20110522 to set some new hot keys and also set the acceltext of menuitems for my new keys as well as for add-ons that do not bother to do so.
I want the acceltext of the menuitems to be set when Firefox starts, but currently I am just using a hot key to execute the following code against the UI via KeyConfig:
document.getElementById("tabmix-menu")
.setAttribute("acceltext","Alt+Ctrl+Shift+T");
// more of the same...
I need a couple of beginners tips:
How can I execute arbitrary code against the UI in the same way as I execute against an HTML page via the console?
Is there a sneaky way to get a clump of code to execute on browser start-up without delving into XUL development?
Is there a way to trace commands executed against the UI so I can get at command calls instead of using triggers when I set my hot keys like so:
document.getElementById("tabmix-menu").click();
Any other tips on this type of low-level hacking would also be welcome.
You can execute arbitrary code against the Firefox UI from an addon, but as you say, doing all the XUL related stuff is a bit boring :-)
Enter "Bootstrapped" extensions!
Part 1:
A "Bootstrapped" (or re-startless) extension needs only an install.rdf file to identify the addon, and a bootstrap.js file to implement the bootstrap interface.
Bootstrapped Extension: https://developer.mozilla.org/en-US/docs/Extensions/Bootstrapped_extensions
Good example: http://blog.fpmurphy.com/2011/02/firefox-4-restartless-add-ons.html
The bootstrap interface can be implemented very simply:
function install() {}
function uninstall() {}
function shutdown(data, reason) {}
function startup(data, reason) { /* YOUR ARBITRARY CODE HERE! */ }
You compile the extension by putting install.rdf and bootstrap.js into the top-level of a new zip file, and rename the zip file extension to .xpi.
Part 2:
Your code is privileged and can use any of the Mozilla platform APIs. There is however an issue of timing. The moment-in-time at which the "startup" function is executed is one at which no Chrome window objects exist yet!
If it's important for your code that you have a Chrome Window, we need to wait for it to appear:
// useful services.
Cu.import("resource://gre/modules/Services.jsm");
var loader = Cc["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
var wmSvc = Cc["#mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var logSvc = Cc["#mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
// get the first gBrowser
var done_startup = 0;
var windowListener;
function do_startup(win) {
if (done_startup) return;
done_startup = 1;
wmSvc.removeListener(windowListener);
var browserEnum = wmSvc.getEnumerator("navigator:browser");
var browserWin = browserEnum.getNext();
var tabbrowser = browserWin.gBrowser;
/* your code goes here! */
}
// window listener implementation
windowListener = {
onWindowTitleChange: function(aWindow, aTitle) {},
onCloseWindow: function(aWindow) {},
onOpenWindow: function(aWindow) {
var win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
win.addEventListener("load", function(aEvent) {
win.removeEventListener("load", arguments.callee, false);
if (aEvent.originalTarget.nodeName != "#document") return;
do_startup();
}
};
// CODE ENTRY POINT (put this in bootstrap "startup" function)
wmSvc.addListener(windowListener);

Load an external JS library into a page using Greasemonkey

I want a translator in my Firefox. I find some code from internet. but it doesn't run in my Firefox. I have installed Greasemonkey.
function loadBingTranslator() {
script = document.createElement('script');
script.src = 'http://dict.bing.com.cn/cloudwidget/Scripts/Generated/BingTranslate_Selection_ShowIcon.js';
script.onload = initBingTranslator;
document.body.appendChild(script);
};
function initBingTranslator() {
BingCW.Init({
MachineTranslation: true,
WebDefinition: true
});
}
loadBingTranslator();
Such a script must account for the GM sandbox, and also (usually) allow time for the library to load and initialize.   See Avoid Common Pitfalls (in Greasemonkey).
So, you would use this library like so:
//--- Load the library.
var D = document;
var appTarg = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
var jsNode = D.createElement ('script');
jsNode.src = 'http://dict.bing.com.cn/cloudwidget/Scripts/Generated/BingTranslate_Selection_ShowIcon.js';
jsNode.addEventListener ("load", initBingTranslatorOnDelay, false);
appTarg.appendChild (jsNode);
//--- Allow some time for the library to initialize after loading.
function initBingTranslatorOnDelay () {
setTimeout (initBingTranslator, 666);
}
//--- Call the library's start-up function, if any. Note needed use of unsafeWindow.
function initBingTranslator () {
unsafeWindow.BingCW.Init ( {
AppID: "GM Foo",
MachineTranslation: true,
WebDefinition: true
} );
}
Issues, some specific to this question:
onload is not available; See the pitfalls. Event handlers cannot be set this way in GM. Also, addEventListener() is the best practice anyway.
Accessing JS (including libraries we load) in the page scope, requires unsafeWindow.
That app appears to want an AppID.
Sometimes, libraries like this can be loaded in the GM scope instead of the page scope, using the // #require directive.
I did not try that with this library, but with others, it may be possible.   Do not try this with untrusted libraries, as they gain extra abilities to infect your machine, once inside the GM scope.
Don't use reserved words, like "script", for variable names.
My JavaScript Console is outputting a "Component is not available"
line 10: script.onload = initBingTranslator;
So I fixed changed it to ... = initBingTranslator() because it is a function.
Now it says "BingCW is not definded"
Line 15: BingCW.Init({
MachineTranslation: true,
WebDefinition: true
});
And it is right, not sure if something is missing or this is supposed to only work in IE, I would find a Google translator solution personally (or just use an existing add-on).
Bing Dictionary hasd published a Firefox addon.
You can use it directly.

Resources