taoensso / tower

i18n & L10n library for Clojure/Script
https://www.taoensso.com/tower
Eclipse Public License 1.0
278 stars 24 forks source link

Clarification #32

Closed clojens closed 10 years ago

clojens commented 10 years ago

Really the README introduction could use a little more work. I would love to do it and already started adding some semi-colons to the examples for better cargo-cult copy/paste but.... for example:

(ns my-app (:require [taoensso.tower :as tower
                      :refer (with-locale with-tscope t *locale*)])) ; ns

and

(def my-tconfig
  {:dev-mode? true
   :fallback-locale :en
   :scope-var #'*tscope*
  ...

will fail. What is earmuffed tscope? How does this relate to the lib? The term is never properly introduced, nor is the map. The Var my-tconfig is declared and assigned a value but then never used again in any of the examples? Also the (Date.) doesn't work out of the box without java.util namespaces and I would love to pull request some of those changes but it would be a bit helpful as to explain why using e.g. (t :en-US :example/foo) doesn't give the result that is claimed in the README.

Something left in old documentation from the 1.7 version?? Either way, this write-up really needs to get a bit better introduction of those concepts, e.g. begin by showing how to load an inline map, and only after that more to how to load a file. Now, only the latter form is briefly clear to me, the other (memory) I'm left in the dark.

ptaoussanis commented 10 years ago

Hi Rob,

I would love to do it and already started adding some semi-colons to the examples for better cargo-cult copy/paste

Sorry, not really sure what that means. You mean you want to add comments? I'd be happy with that if they're helpful, sure.

will fail

Sorry, don't follow. The namespace form is failing?

What is earmuffed tscope?

I'll remove that. It's a relatively advanced, experimental feature and hasn't been documented yet. Basically just provides a way of supporting multiple translation scope bindings for lib authors or folks with large/complicated apps where that may be useful.

The Var my-tconfig is declared and assigned a value but then never used again in any of the examples?

Ahh, thanks for pointing that out - that's a mistake, sorry. Will correct: it should be an arg for all the t calls.

and I would love to pull request some of those changes

That'd be great. Had to rush through the v2 docs, so would appreciate help cleaning them up.

e.g. (t :en-US :example/foo) doesn't give the result that is claimed in the README.

That should be fixable by adding a my-tconfig arg: (t :en-US my-tconfig :example/foo).


Just shout if you have any other questions or need any other clarification for your PR. Cheers!

ptaoussanis commented 10 years ago

Fixed:

PR welcome if there's anything else you still want to improve!

clojens commented 10 years ago

Thanks! Sorry if I'm not very clear at some points, half the time I'm asking myself if I've missed something, or some concept is still settling down in my brain and I clearly overlook stuff. Perhaps that's why my posts can be either lengthy or open-ended, maybe why I'm more comfortable with technical writing since I need to assure those things and sometimes spelled out literally for myself to get the feeling I grasp it sufficiently enough. I could have, of course checked the source and dug in a little deeper... ah the woes of man. Anyway sometimes I miss a step or two.

It appears there was a problem with that app I was using so I just bootstrapped a lein new application and used the stable 1.7 version. I had LigthTable complain earlier about some dynamic var thing but it seems to be gone now.

Ok so I just had to do a quick learning of git stash so I can modify your most recent document. Some little stuff I'd change is in the config object the ... if you'd like to demonstrate the idea of "do your own stuff here" is to #_ ... instead. That won't break anything that does insta-evaluation of code and while its no cargo-cult in the sense that I'm well aware of what stuff does in general, there is always some initial learning and copy/pasting of code. It's nice that it works instantly so like (+ 1 2) => 3 rather becomes (+ 1 2) ;=> 3 preferably. I can do those tho and do a pull request.

If I find anything I don't really get or can be worded perhaps a bit different/better/explained I'll do those and you can judge them or perhaps clarify :)

Thanks, Rob

clojens commented 10 years ago

Ok so I've rewritten a few sections to be a bit more newbie friendly, now one thing I found (strangely enough again, the Git <<<<<HEAD stuff got parsed in) was that you made some changes to the (t :en my-tconfig :example/foo) to include my-tconfig. That's good but still refuses to find the right string. Here is a 'little' screenshot.

selection_023

ptaoussanis commented 10 years ago

That's good but still refuses to find the right string. Here is a 'little' screenshot.

Hi Rob, that looks okay to me - should be working... is it possible you're not running the latest version of Tower (2.0.0-beta1)?

Some little stuff I'd change is in the config object the ...

Sure - you can just remove the ... altogether, it's not especially necessary.

Cheers

clojens commented 10 years ago

Peter,

Ok. No I wasn't, this was 1.7 but that was part of the confusion, since it tries to import the t Var in the ns directives, which is 1.7 (or so I thought since it mentioned it was breaking) so I figured this example was too. This helps a little, knowing what goes where. P.s. I'm acting dumb here, half the things I would have guessed correct probably, just that I needed to make sure.

A few last questions (for now). The explicit locale, can we set a dynamic var somewhere to have it loaded in not per wrapper function by on a global level? E.g. *locale*? Isn't my assumption correct, that perhaps the fallback should cover for any lacking of the :locale in (t)? So I get that at a multi-lang site one might wish to do something like

(t :en-US my-tconfig :example/buy-me-please)
(t :de-DE my-tconfig :example/kauf-mich-bitte)

even though any sensible design school will tell you to tuck the functionality under a flag, it seems plausible enough that people might want to use different locales throughout a single rendered web page e.g. 3 paragraphs of travel directions, one for each language of English/German/French might not be uncommon for certain European businesses. So imho this should work as expected as well:

(t :example/foo) ; both language and map are fallen-back upon (everything implied)
(t :nl-NL :example/koop-mij-aub) ; fallback on the config map?
(t :nl-NL my-tconfig :example/foebarbar) ; no fallbacks, everything explicit

Any thoughts on this?

Also I was thinking if it was perhaps handy to use a gettext-like convention for wrapping strings? I think you can wrap gettext strings using the form _("...") which will, at a later stage, gather all the required translatable strings on a single page for easier translation. I thought I might be able to utilize a #_("Standard description") or (easier I guess, a real function perhaps ($ "string to translate"), (stt "String To Translate") like convention. Or does tower already take such a thing into account with 'missing translation' or is that only on the central config-map side of things and not throughout the entire collection of pages?

clojens commented 10 years ago

Note that :foo_note "Hello translator, please do x" does not render properly:

selection_032

Dunno, doesn't seem to be the underscore. I never see them appear in keywords but seems they are perfectly legit.

ptaoussanis commented 10 years ago

No I wasn't, this was 1.7 but that was part of the confusion

Okay, yeah - there's been big API changes since 1.7 and the README reflects the current (2.x) version. You can find 1.x examples here, but I'd suggest the 2.x version instead where possible.

P.s. I'm acting dumb here, half the things I would have guessed correct probably, just that I needed to make sure.

No problem, ask away :-) It's also helpful for me to see where folks are struggling to understand the current docs.

The explicit locale, can we set a dynamic var somewhere to have it loaded in not per wrapper function by on a global level?

There's two dynamic vars: *locale* and *tscope*. These can be set with with-locale and with-tscope respectively. The locale will usually be set by the Ring middleware for web apps though.

Isn't my assumption correct, that perhaps the fallback should cover for any lacking of the :locale in (t)?

Sorry, not sure I understand what you're asking here. t can take an explicit locale or use the bound*locale*, as convenient. Fallback will occur as described in the README: so :en-US-var1 will fallback to :en-US then :en, then to the final :fallback-locale in the config map.

Any thoughts on this?

As the low-level fn, t fn takes all args explicitly. You can make partials/anonymous fns around this if you want to provide defaults for certain args - that's how I use it myself.

You can look at the source of the Ring middleware as an example of how this'd be done - it provides a partial'ed version of t to requests that closes over the config map and locale.

gettext-like convention for wrapping strings?

I'm not a big fan of gettext style translation tbh, especially with how easy it is to use a (more powerful) Tower-style translation fn in a macro language like Clojure.

This'd be a long discussion, but my biggest criticism of gettext translation is that it complects translations with the key used to id those transactions. This can (and often does) become a serious headache when text is changing rapidly as it often does/should in modern web app design, etc. It's a particular PITA for A/B testing.

gettext's usual advantage is its convenience for the developer, but I think we're already matching or exceeding that convenience with Tower.

Note that :foo_note "Hello translator, please do x" does not render properly:

The _note decorator is designed to not generate an actual translation. It's there to carry metadata to help translators - for example "Please be careful with X for this translation, yadda yadda". Actually, _comment might be a clearer name for this - will look into changing it.

Cheers! :-)

clojens commented 10 years ago

Peter, that answers everything I needed to know ;) Sorry for being a lame-ass not checking the code too much myself, I could have just looked it up. Anyway, I'll include some of those in the write-up and probably send something over which you can check out. It's not like there is a standard though, so I've tried and use some of the stuff other libraries used for outline, and use anchors to point to locations of reference. One thing that bothers me though, is the #line-number anchors I've got to point at docstrings now though,... I just realized that those change as the file content does, and may not be in line/sync with any in the README. Hmmm.....

There's two dynamic vars...

Gotcha! Nice for me to finally learn what 'root binding' means now:

(binding [tower/*locale* :en]
 (set! tower/*locale* :en))

(alter-var-root #'tower/*locale*
                (constantly :en))

That works both great. Also I get

As the low-level fn, t fn takes all args explicitly.

That seems fine then, if intended this way as low level, indeed I can easily wrap it in any form that I wish so no biggies.

The _note decorator is designed to not generate an actual translation.

Aha! That explains it :)

but my biggest criticism of gettext translation is that it complects translations with the key used to id those transactions. This can (and often does) become a serious headache when text is changing rapidly as it often does/should in modern web app design, etc. It's a particular PITA for A/B testing.

Great, thanks for pointing that out as my knowledge of gettext is limited and this would be a subject I haven't familiarized myself too much with; I'll take your word on it :)

ptaoussanis commented 10 years ago

No problem, happy to help :-) Will keep an eye out for your PR. Feel free to ping me if any other questions come up. Have an awesome day, cheers!