问题
Currently I am using just plain text in my Closure application. I want to add localizations to those text. I just found several articles about goog.getMsg function which is used to do this kind of localization. As far as I understood it is done in compile time. How can we change language in run-time when user clicks a button? What is the easiest way to do this using Closure?
回答1:
I have actually achieved a runtime i18n. I use .soy templates with {msg}
tags in them. When you compile .soy to .js, these calls get compiled to goog.getMsg calls. What I had to do was:
- Find all
.js
files that hadgoog.getMsg(
in them - Prepend
goog.require("myApp.i18n");\n
- Replace all
goog.getMsg(
calls withmyApp.i18n.translate(
- Replace all
MSG_*
property names withmyprefix_MSG_*
Why all this: One cannot override goog.getMsg directly, because it is considered a compiler primitive and does not allow any manipulation whatsoever. Same applies for MSG_*
properties.
myApp.i18n.translate
is a function that accepts string, tries to look it up in a locale map (which is passed in runtime) and returns goog.getMsg
result using the localized string (goog.getMsg
does some handy placeholder replacements).
While this is not a very pretty solution, it works and allows me to change language in runtime, using only one compiled file for all languages.
The actual code includes a few hacks that allows me to use the generated description and use JSON files instead of the strange-looking closure file format, but the gist is the same.
However!
What you really should do is to compile several files from your app and load different .js file for every language.
I had to use this solution, because I need to support hundreds of different configurations and several languages: it would be insane to compile thousands of .js files, when one compilation takes 30+ seconds.
回答2:
Although this is not a single click language switch solution, I find it very comfortable as it allows to use same source of localized texts for both Soy templates and goog.getMsg()
in JS code. It is sort of undocumented way of using Googles own XML format of translations called XTB.
You will end up with different compiled .js file for each language, so to switch locale you have to reload different JS file.
Apart from standard Closure tools there is 3rd party tool called XtbGenerator, which can be found here: https://github.com/kuzmisin/xtbgenerator.
Now the workflow:
Compile your templates using
SoyToJsSrcCompiler.jar
with--shouldGenerateGoogMsgDefs --bidiGlobalDir 1
options. No locale yet.Create dependecies file using
calcdeps.py
Run
closurebuilder.py
with--compiler_jar
set toXtbGenerator.jar
file and with--compiler_flags="--xtb_output_file=origin.xtb"
parameter.This will create a file called
origin.xtb
, which you can then use as a base for your translations. It will contain all texts both from Soy templates (in{msg}
blocks) and your JS files (wherevar MSG_TEST = goog.getMsg('Text');
is used).Copy
origin.xtb
to for exampletranslated.cs_CZ.xtb
, change thelang
attribute in the file and translate all the texts there.Compile the app for given locale the standard way using
closurebuilder.py
andcompiler.jar
. Use parameters:--compiler_flags="--translations_file=translated.cs_CZ.xtb"
--compiler_flags="--define=goog.LOCALE='cs_CZ'"
This will create you compiled version for single locale.
Nice examples of all these steps are here: http://www.closurecheatsheet.com/skeleton
It is unfortunate that there is almost no official documentation for this.
XTB format:
The format is following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE translationbundle>
<translationbundle lang="cs">
<translation id="4127240967364168948" key="MSG_6LRZ706911HM" source="..\test.soy.js" desc="description">test</translation>
</translationbundle>
id
and for soy templates also key
attribute is autogenerated by compiler/extractor
This is most probably some Google internal format with tools for this not yet open-sourced.
Note about XtbGenerator:
It internally uses the Closure Compiler code to go through your JS codes and extract the messages. The dowloadable version however is built with older version of Closure Compiler, so it was throwing some errors for me.
I did a quick and dirty hack by copying goog
directories from current version of compiler.jar
to XtbGenerator.jar
.
来源:https://stackoverflow.com/questions/18645568/how-to-do-localization-in-google-closure