Fork me on GitHub
#re-frame
<
2022-12-22
>
mac13:12:20

We are using re-frame and tempura for internationalization. Since re-frame 1.3.0 we are getting a warning "core.cljs:3953 re-frame: Subscribe was called outside of a reactive context." We are indeed subscribing to the language choice in the function that creates a partial of tempura/tr. Is there an approach that would allow us to do this without having to subscribe to / pass around the language choice in/to all components?

p-himik14:12:47

Yes, you can have a :tr sub that returns the right tr function.

p-himik14:12:23

Of course, you'd use that sub only in views. And you can wrap it in a function so that it's easier to use, something like:

(defn <tr []
  @(rf/subscribe [:tr]))

mac14:12:19

So there is a difference between returning the fn from a subscription and having a plain fn use the subscription to build the tr?

p-himik14:12:07

Only if you have code like

(def tr @(rf/subscribe [:tr]))
The only difference is where you use subscriptions. It's either in a reactive context (views, reactions - the intended usage) or not (the usage that produces that warning).

mac14:12:27

OK, but then I don't see how I can avoid subscribing in every component or at the top lvl and passing tr to sub-components? Or are you saying build a component that calls defn ? Sorry if I am being dense.

mac14:12:29

Right now I am doing a require [dict :refer tr] in all view files and just use that whenever I render text. Ideally I would like to preserve that somehow.

p-himik14:12:32

> I don't see how I can avoid subscribing in every component Why would you want to avoid it? Just do it. :) Actually, this is roughly what I'm doing in one of my projects (not exactly what I proposed above, but similar):

(ns my-app.i18n
  (:require [re-frame.core :as rf]))

(rf/reg-sub :tr
  (fn [db [_ key]]
    ... call some actual `tr` function on the `key` ...)

(defn tr [key]
  @(rf/subscribe [:tr key]))
(ns my-app.views
  (:require [my-app.i18n :refer [tr]]))

(defn button
  [:button {:on-click #()}
   (tr [:the-button-label])])

mac14:12:08

Ah, I think I got it. Use the subscription to perform the actual translation. And have the sub look up the key and the current language.

p-himik14:12:39

Yep. And if you have so many strings to translate that it starts to affect performance, you can always put the i18n stuff outside of re-frame. Either in a plain ratom or even an atom (then you'd have to re-render the whole app manually on language change).

1
mac14:12:25

Thanks, much apreciated.

👍 1