Open lorddoig opened 10 years ago
Hey there, thanks for the suggestion! Could you try [com.taoensso/tower "3.1.0-SNAPSHOT"]
(on Clojars now), and let me know if that does the job?
Cheers :-)
Hey thanks for the super quick response. Eval! Of course. All those hours watching SICP lectures on youtube were wasted on me apparently...
No success, but for other reasons:
[com.taoensso/tower "3.1.0-SNAPSHOT"]
seems to be pulling in the v3.1.0-alpha1 branch instead of dev? This branch is missing your eval
patch.Also I see the macro's changed from dict-compile
to dict-compile*
which caught me out for a minute.
I've only ever had headaches using the leiningen checkouts feature otherwise I'd give that a go. Sorry I can't be more useful.
No problem :-)
Eval! Of course. All those hours watching SICP lectures on youtube were wasted on me apparently...
Not at all - Clojure macros don't generally use eval
much, actually. It's called only twice in core.clj
's ~7.3k loc for example.
This is a bit of an unusual case since we're using a macro to dump the entire compiled dict into the ClojureScript source during ClojureScript compile time. I.e. we don't need the dictionary compilation to actually run under ClojureScript - if that makes sense.
[com.taoensso/tower "3.1.0-SNAPSHOT"] seems to be pulling in the v3.1.0-alpha1 branch instead of dev? This branch is missing your eval patch.
It's possible I didn't upload it correctly - just tried again and it does seem to be up now: https://clojars.org/com.taoensso/tower/versions/3.1.0-SNAPSHOT
I didn't know this before, but apparently dependency ordering matters to leiningen? How old school. Sente and Tower were competing for Encore and screwing each other up.
Ahh, yeah - you can add [com.taoensso/encore "1.15.1"]
as a Lein dependency above any other com.taoensso
libs and you should be fine.
Also I see the macro's changed from dict-compile to dict-compile* which caught me out for a minute.
Sorry, yeah - there's a number of changes (improvements) pending in the dev branch. It's stable (I'm using it now), but I haven't documented the changes yet.
This is the only breaking change iirc.
Hope that helps, cheers! :-)
Awesome reply, thanks man. Alright I've got it, but still no dice.
(some) dependencies:
[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.346.0-17112a-alpha"]
[org.clojure/clojurescript "0.0-2371"]
[com.taoensso/encore "1.15.1"]
[com.taoensso/sente "1.2.0"]
[com.taoensso/tower "3.1.0-SNAPSHOT"]
i18n.cljx:
(ns myns.i18n
#+cljs (:require-macros [taoensso.tower :as tower-macros])
(:require [taoensso.tower :as tower])
)
(def dict
{:en
{:test-msgs
{:one "One" :two "Two"}
}
}
)
#+clj
(def tconfig
{:dictionary "i18n-dict.clj"
:dev-mode? true ; FIXME: Make this dynamic
:fallback-locale :en
})
#+cljs
(def tconfig
{:compiled-dictionary (tower-macros/dict-compile* dict)
:fallback-locale :en})
(def t (tower/make-t tconfig))
error:
Caused by: clojure.lang.ExceptionInfo: java.lang.RuntimeException: Unable to resolve symbol: dict in this context, compiling:(/private/var/folders/43/b72s05yn3kz96bx_wx66wqbc0000gn/T/form-init4639629360688432507.clj:29:53) at line 29 /.........../i18n.cljs {:tag :cljs/analysis-error, :file "/.........../i18n.cljs", :line 29, :column 25}
I'm not sure how to read this error - does that mean it doesn't know what dict
is before it passes it to dict-compile*
(suggesting it's my fault), or is it bubbling up from inside dict-compile*
? Regarding the former, I can't see how that can be the case: I've inspected the generated i18n.cljs and it clearly defines dict
before passing it in to dict-compile*
. Just to be safe, and perhaps displaying my lack of understanding of macros, I changed the name of dict
to be sure no variable capture/other weirdness was going on but it made no difference.
For the record I've run this (overly safe) command multiple times to the same effect
lein -U do clean, deps, compile
The compile step in my setup is:
I hope this helps, if it's something I'm doing wrong I'd be grateful for the heads up.
Hi there,
Not really sure what the problem is - just ran a test and it does appear to be working on my end (no CLJS compilation errors). Would be happy to debug it with you, but I'm pretty swamped / on an urgent project atm.
I'd start by checking that the dict
var is showing up in your .clj file (since that's where it needs to be for the macro-time dictionary compilation).
As an alternative, I'd recommend just sticking your dictionary in a separate .clj file in your <project.clj-root>/resources
path and using
(def tconfig
{:compiled-dictionary (tower-macros/dict-compile* "my-dictionary.clj")
:fallback-locale :en})
;; where `my-dictionary.clj` is at <project.clj-root>/my-dictionary.clj
This has a number of advantages and is the approach I take + tend to recommend. Any particular reason you're hesitant to go that route?
I am getting the same exception as @lorddoig. I found that if I just structure the dict in the same fashion that dict-compile* produces then I can bypass using the macro all together.
So
(def dict
{:en
{:test-msgs
{:one "One" :two "Two"}
}
}
)
becomes
(def dict {
{:test-msgs/one {:en "One" }}
{:test-msgs/two {:en "Two" }}})
@smbecker Hi Shaun, I'd caution against that approach. Dictionary compilation involves more than just map restructuring (Markdown support & html escaping for example). In any case the compiled dictionary format is an implementation detail, so future versions may break compatibility with your pre-compiled dict. I'd suggest using a resource file if you can.
Hope that helps, cheers!
The basic problem that I am trying to solve is to write a macro that creates an accessor function for each of my localized strings. Since the clojurescript support doesn't support formatting, I have to manually format before passing the args to tower. Also, I am doing language detection on the browser to determine active locale. I don't want the rest of my code to have to worry about either of these details. That is why I was attempting to wrap all of that behind an a macro generated accessor. In order to generate the accessor's, I need access to the dict as well. I'm VERY much a clojure noob so I may be approaching it wrong in the first place (be patient with me). One thing that just occurred to me to try so I can accomplish what I want but still adhere to your caution is to still rely on dict-compile but to save the result of that to a variable the change my macro to be more of post processor rather than pre. Granted, I would still need to take some reliance on how dict-compile structures the output but I don't know any other way unless you have any suggestions.
Still seeing this problem. Passing anything but anything but a map literal to dict-compile*
results in
Caused by: clojure.lang.ExceptionInfo: java.lang.RuntimeException: Unable to resolve symbol: [name] in this context
Still seeing this problem. Passing anything but anything but a map literal to dict-compile* results in
Hi Okal, what version of Tower are you running? I have [com.taoensso/tower "3.1.0-beta2"]
in production with a (tower/dict-compile* "i18n-dict.clj")
call working as expected.
Hm. I'm probably doing it wrong. I assumed it would be able to accept single language translation files of the following form:
;; en.clj
{:page-title "Home"}
I'm attempting to call dict-compile*
on individual language file paths.
Added it properly, now it works. Thanks :smile:
Happy to hear you've got it working. What inconsistency do you have in mind though? You should be able to inline a whole dictionary if you want, I just wouldn't normally recommend going that route unless you have a good reason.
In CLJ, I can have arbitrary depth nesting in the lang maps, but that doesn't seem to be the case with CLJS. So, I can do (translate :sw :top-level/mid-level/key)
, but I can only go as far as the second level in CLJS. That arbitrary depth nesting isn't something I found documented, just a convenience I stumbled upon. I edited it out from the comment for that reason. It's irrelevant to this thread.
To illustrate:
{:main-navigation {:dropdown {:profile-link-text "Profile}}}
:main-navigation/dropdown/profile-link
text is accessible from CLJ but not CLJS.
Cljs absolutely also supports arbitrary-depth nesting, but you must use valid keyword syntax: so :main-navigation.dropdown/profile-link
. Keywords can have at most one "/" to separate the namespace and name parts (you can use as many .'s as you like).
Not sure if that's the specific issue you're running into, but it wouldn't surprise me if that keyword form were getting rejected in Cljs.
I'm sure the title is explanation enough for seasoned macro-writers like yourselves, but for completeness:
fails because the library functions that actually compile the dictionary are given the symbol
dict
instead of the map.I'm new enough to Clojure that anything but simple macros make my head spin: I've tried and failed to fix this. I know it's easily worked around by just putting the dictionary in another file and passing in a string but I'm filing this anyway as I'm guessing this should be fixed/documented at some point.