motorefi-lit 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +170 -0
- data/Rakefile +38 -0
- data/app/assets/images/lit/famfamfam_flags/ad.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ae.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/af.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ag.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ai.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/al.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/am.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/an.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ao.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ar.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/as.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/at.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/au.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/aw.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ax.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/az.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ba.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bb.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bd.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/be.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bf.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bh.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bi.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bj.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bo.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/br.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bs.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bt.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bv.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bw.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/by.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/bz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ca.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/catalonia.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cc.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cd.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cf.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ch.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ci.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ck.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cl.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/co.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cs.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cu.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cv.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cx.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cy.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/cz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/da.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/de.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/dj.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/dk.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/dm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/do.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/dz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ec.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ee.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/eg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/eh.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/en.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/england.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/er.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/es.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/et.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/europeanunion.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/fam.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/fi.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/fj.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/fk.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/fm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/fo.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/fr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ga.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gb.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gd.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ge.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gf.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gh.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gi.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gl.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gp.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gq.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gs.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gt.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gu.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gw.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/gy.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/hk.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/hm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/hn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/hr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ht.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/hu.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/id.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ie.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/il.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/in.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/io.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/iq.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ir.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/is.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/it.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ja.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/jm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/jo.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/jp.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ke.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/kg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/kh.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ki.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/km.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/kn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/kp.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/kr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/kw.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ky.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/kz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/la.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/lb.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/lc.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/li.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/lk.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/lr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ls.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/lt.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/lu.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/lv.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ly.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ma.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mc.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/md.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/me.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mh.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mk.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ml.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mo.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mp.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mq.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ms.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mt.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mu.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mv.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mw.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mx.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/my.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/mz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/na.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/nc.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ne.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/nf.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ng.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ni.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/nl.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/no.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/np.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/nr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/nu.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/nz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/om.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pa.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pe.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pf.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ph.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pk.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pl.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ps.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pt.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/pw.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/py.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/qa.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/re.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ro.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/rs.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ru.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/rw.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sa.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sb.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sc.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/scotland.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sd.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/se.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sh.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/si.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sj.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sk.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sl.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/so.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/st.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sv.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sy.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/sz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tc.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/td.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tf.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/th.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tj.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tk.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tl.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/to.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tr.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tt.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tv.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tw.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/tz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ua.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ug.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/um.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/us.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/uy.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/uz.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/va.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/vc.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ve.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/vg.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/vi.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/vn.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/vu.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/wales.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/wf.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ws.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/ye.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/yt.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/za.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/zm.png +0 -0
- data/app/assets/images/lit/famfamfam_flags/zw.png +0 -0
- data/app/assets/images/lit/jquery-te.png +0 -0
- data/app/assets/javascripts/lit/application.js +19 -0
- data/app/assets/javascripts/lit/backend/bootstrap.js.coffee +4 -0
- data/app/assets/javascripts/lit/backend/dashboard.js +2 -0
- data/app/assets/javascripts/lit/backend/jquery-te-1.4.0.min.js +9 -0
- data/app/assets/javascripts/lit/backend/localizations.js.coffee +26 -0
- data/app/assets/javascripts/lit/backend/sources.js.coffee +24 -0
- data/app/assets/javascripts/lit/lit_frontend.js +103 -0
- data/app/assets/javascripts/lit/mousetrap.js +1044 -0
- data/app/assets/stylesheets/lit/application.css +59 -0
- data/app/assets/stylesheets/lit/backend/jquery-te-1.4.0.css.scss +457 -0
- data/app/assets/stylesheets/lit/lit_frontend.css +86 -0
- data/app/controllers/lit/api/v1/base_controller.rb +19 -0
- data/app/controllers/lit/api/v1/locales_controller.rb +14 -0
- data/app/controllers/lit/api/v1/localization_keys_controller.rb +15 -0
- data/app/controllers/lit/api/v1/localizations_controller.rb +18 -0
- data/app/controllers/lit/application_controller.rb +49 -0
- data/app/controllers/lit/concerns/request_info_store.rb +16 -0
- data/app/controllers/lit/concerns/request_keys_store.rb +16 -0
- data/app/controllers/lit/dashboard_controller.rb +9 -0
- data/app/controllers/lit/incomming_localizations_controller.rb +49 -0
- data/app/controllers/lit/locales_controller.rb +31 -0
- data/app/controllers/lit/localization_keys_controller.rb +117 -0
- data/app/controllers/lit/localizations_controller.rb +60 -0
- data/app/controllers/lit/sources_controller.rb +77 -0
- data/app/helpers/lit/application_helper.rb +4 -0
- data/app/helpers/lit/dashboard_helper.rb +4 -0
- data/app/helpers/lit/frontend_helper.rb +71 -0
- data/app/helpers/lit/localization_keys_helper.rb +5 -0
- data/app/helpers/lit/localizations_helper.rb +15 -0
- data/app/helpers/lit/sources_helper.rb +7 -0
- data/app/jobs/lit/synchronize_source_job.rb +11 -0
- data/app/models/lit/incomming_localization.rb +77 -0
- data/app/models/lit/locale.rb +48 -0
- data/app/models/lit/localization.rb +103 -0
- data/app/models/lit/localization_key.rb +107 -0
- data/app/models/lit/localization_version.rb +12 -0
- data/app/models/lit/source.rb +111 -0
- data/app/views/kaminari/lit/_first_page.html.erb +5 -0
- data/app/views/kaminari/lit/_gap.html.erb +3 -0
- data/app/views/kaminari/lit/_last_page.html.erb +6 -0
- data/app/views/kaminari/lit/_next_page.html.erb +5 -0
- data/app/views/kaminari/lit/_page.html.erb +3 -0
- data/app/views/kaminari/lit/_paginator.html.erb +17 -0
- data/app/views/kaminari/lit/_prev_page.html.erb +5 -0
- data/app/views/layouts/lit/_messages.html.erb +6 -0
- data/app/views/layouts/lit/_navigation.html.erb +23 -0
- data/app/views/layouts/lit/application.html.erb +46 -0
- data/app/views/lit/dashboard/index.html.erb +5 -0
- data/app/views/lit/incomming_localizations/accept.js.erb +2 -0
- data/app/views/lit/incomming_localizations/destroy.js.erb +1 -0
- data/app/views/lit/incomming_localizations/index.html.erb +52 -0
- data/app/views/lit/locales/_hide_link.html.erb +1 -0
- data/app/views/lit/locales/hide.js.erb +1 -0
- data/app/views/lit/locales/index.html.erb +20 -0
- data/app/views/lit/localization_keys/_localization_row.html.erb +14 -0
- data/app/views/lit/localization_keys/destroy.js.erb +1 -0
- data/app/views/lit/localization_keys/index.html.erb +127 -0
- data/app/views/lit/localization_keys/star.js.erb +1 -0
- data/app/views/lit/localizations/_form.html.erb +23 -0
- data/app/views/lit/localizations/_previous_versions_rows.html.erb +15 -0
- data/app/views/lit/localizations/edit.js.erb +7 -0
- data/app/views/lit/localizations/previous_versions.js.erb +3 -0
- data/app/views/lit/localizations/update.js.erb +4 -0
- data/app/views/lit/sources/_form.html.erb +35 -0
- data/app/views/lit/sources/edit.html.erb +6 -0
- data/app/views/lit/sources/index.html.erb +42 -0
- data/app/views/lit/sources/new.html.erb +5 -0
- data/app/views/lit/sources/show.html.erb +19 -0
- data/config/routes.rb +49 -0
- data/db/migrate/20180101010101_lit_create_lit_locales.rb +16 -0
- data/db/migrate/20180101010102_lit_create_lit_localization_keys.rb +18 -0
- data/db/migrate/20180101010103_lit_create_lit_localizations.rb +24 -0
- data/db/migrate/20180101010104_lit_add_is_completed_and_is_starred_to_localization_keys.rb +17 -0
- data/db/migrate/20180101010105_lit_add_is_hidden_to_locales.rb +12 -0
- data/db/migrate/20180101010106_lit_create_lit_localization_versions.rb +20 -0
- data/db/migrate/20180101010107_lit_create_lit_sources.rb +19 -0
- data/db/migrate/20180101010108_lit_create_lit_incomming_localizations.rb +34 -0
- data/db/migrate/20180101010109_lit_add_sync_complete_to_lit_sources.rb +12 -0
- data/lib/generators/lit/install/templates/initializer.rb +52 -0
- data/lib/generators/lit/install_generator.rb +66 -0
- data/lib/lit.rb +65 -0
- data/lib/lit/adapters/hash_storage.rb +12 -0
- data/lib/lit/adapters/redis_storage.rb +99 -0
- data/lib/lit/cache.rb +356 -0
- data/lib/lit/engine.rb +28 -0
- data/lib/lit/i18n_backend.rb +192 -0
- data/lib/lit/loader.rb +16 -0
- data/lib/lit/rails.rb +17 -0
- data/lib/lit/railtie.rb +12 -0
- data/lib/lit/version.rb +3 -0
- data/lib/tasks/lit_tasks.rake +29 -0
- metadata +478 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
class LitAddIsHiddenToLocales < Rails::VERSION::MAJOR >= 5 ?
|
2
|
+
ActiveRecord::Migration[4.2] :
|
3
|
+
ActiveRecord::Migration
|
4
|
+
def up
|
5
|
+
return if column_exists?(:lit_locales, :is_hidden)
|
6
|
+
add_column :lit_locales, :is_hidden, :boolean, default: false
|
7
|
+
end
|
8
|
+
|
9
|
+
def down
|
10
|
+
remove_column :lit_locales, :is_hidden
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class LitCreateLitLocalizationVersions < Rails::VERSION::MAJOR >= 5 ?
|
2
|
+
ActiveRecord::Migration[4.2] :
|
3
|
+
ActiveRecord::Migration
|
4
|
+
def up
|
5
|
+
return if table_exists?(:lit_localization_versions)
|
6
|
+
create_table :lit_localization_versions do |t|
|
7
|
+
t.text :translated_value
|
8
|
+
t.integer :localization_id
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :lit_localization_versions, :localization_id
|
14
|
+
end
|
15
|
+
|
16
|
+
def down
|
17
|
+
remove_index :lit_localization_versions, :localization_id
|
18
|
+
drop_table :lit_localization_versions
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class LitCreateLitSources < Rails::VERSION::MAJOR >= 5 ?
|
2
|
+
ActiveRecord::Migration[4.2] :
|
3
|
+
ActiveRecord::Migration
|
4
|
+
def up
|
5
|
+
return if table_exists?(:lit_sources)
|
6
|
+
create_table :lit_sources do |t|
|
7
|
+
t.string :identifier
|
8
|
+
t.string :url
|
9
|
+
t.string :api_key
|
10
|
+
t.datetime :last_updated_at
|
11
|
+
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def down
|
17
|
+
drop_table :lit_sources
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class LitCreateLitIncommingLocalizations < Rails::VERSION::MAJOR >= 5 ?
|
2
|
+
ActiveRecord::Migration[4.2] :
|
3
|
+
ActiveRecord::Migration
|
4
|
+
def up
|
5
|
+
return if table_exists?(:lit_incomming_localizations)
|
6
|
+
create_table :lit_incomming_localizations do |t|
|
7
|
+
t.text :translated_value
|
8
|
+
t.integer :locale_id
|
9
|
+
t.integer :localization_key_id
|
10
|
+
t.integer :localization_id
|
11
|
+
t.string :locale_str
|
12
|
+
t.string :localization_key_str
|
13
|
+
t.integer :source_id
|
14
|
+
t.integer :incomming_id
|
15
|
+
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
add_index :lit_incomming_localizations, :locale_id
|
20
|
+
add_index :lit_incomming_localizations, :localization_key_id
|
21
|
+
add_index :lit_incomming_localizations, :localization_id
|
22
|
+
add_index :lit_incomming_localizations, :source_id
|
23
|
+
add_index :lit_incomming_localizations, :incomming_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def down
|
27
|
+
remove_index :lit_incomming_localizations, :locale_id
|
28
|
+
remove_index :lit_incomming_localizations, :localization_key_id
|
29
|
+
remove_index :lit_incomming_localizations, :localization_id
|
30
|
+
remove_index :lit_incomming_localizations, :source_id
|
31
|
+
remove_index :lit_incomming_localizations, :incomming_id
|
32
|
+
drop_table :lit_incomming_localizations
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class LitAddSyncCompleteToLitSources < Rails::VERSION::MAJOR >= 5 ?
|
2
|
+
ActiveRecord::Migration[4.2] :
|
3
|
+
ActiveRecord::Migration
|
4
|
+
def up
|
5
|
+
return if column_exists?(:lit_sources, :sync_complete)
|
6
|
+
add_column :lit_sources, :sync_complete, :boolean
|
7
|
+
end
|
8
|
+
|
9
|
+
def down
|
10
|
+
remove_column :lit_sources, :sync_complete
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
# Which authentication function to use (ie. :authenticate_user!)? When set to
|
3
|
+
# `nil` will let everyone in.
|
4
|
+
Lit.authentication_function = <%= @authentication_function || 'nil' %>
|
5
|
+
|
6
|
+
# Which authentication verification function to use (ie. :user_signed_in)?
|
7
|
+
# This is used together with frontend translation module to determine, if
|
8
|
+
# helper button should be applied and translations wrapped in custom span
|
9
|
+
Lit.authentication_verification = <%= @authentication_verification || 'nil' %>
|
10
|
+
|
11
|
+
# Either 'redis' or 'hash'. Hash is the fastest, but will fail in multiprocess
|
12
|
+
# environment
|
13
|
+
Lit.key_value_engine = '<%= @key_value_engine %>'
|
14
|
+
|
15
|
+
# Pass extra options to key_value_neinge, ie. prefix for redis (only one
|
16
|
+
# supported at the moment)
|
17
|
+
# Lit.storage_options = { prefix: "my_project" }
|
18
|
+
|
19
|
+
# If true all translations are returned as html_safe strings
|
20
|
+
Lit.all_translations_are_html_safe = false
|
21
|
+
|
22
|
+
# Translations without default will be humanized (default string will be added)
|
23
|
+
# ie. scope.page_header will become "Page header"
|
24
|
+
# If `false` then will serve nil instead (but translation will be wrapped in
|
25
|
+
# <span title="translation missing string"></span>
|
26
|
+
Lit.humanize_key = false
|
27
|
+
|
28
|
+
# If set to `true` will always parse yaml files upon startup and update cache
|
29
|
+
# values with ones with yaml - but only, if those keys haven't been changed via
|
30
|
+
# web ui before
|
31
|
+
Lit.ignore_yaml_on_startup = true
|
32
|
+
|
33
|
+
# API enabled? API allows third party browsing your translations, as well as
|
34
|
+
# synchronizing them between environments
|
35
|
+
Lit.api_enabled = false
|
36
|
+
|
37
|
+
# API key is required to authorize third party, if API is enabled
|
38
|
+
Lit.api_key = '<%= @api_key %>'
|
39
|
+
|
40
|
+
# If true, last_updated_at column of synchronizaton source will be set to now
|
41
|
+
# upon record creation
|
42
|
+
Lit.set_last_updated_at_upon_creation = true
|
43
|
+
|
44
|
+
# Store request info - this will store in cache additional info about request
|
45
|
+
# path that triggered translation key to be displayed / accessed
|
46
|
+
# For more infor please check README.md
|
47
|
+
Lit.store_request_info = false
|
48
|
+
|
49
|
+
# Initialize lit
|
50
|
+
Lit.init
|
51
|
+
|
52
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
module Lit
|
3
|
+
module Generators
|
4
|
+
class InstallGenerator < ::Rails::Generators::Base
|
5
|
+
class_option 'key-value-engine', type: :string
|
6
|
+
class_option 'authentication-function', type: :string
|
7
|
+
class_option 'no-migrate', type: :boolean
|
8
|
+
|
9
|
+
source_root File.expand_path('../install/templates', __FILE__)
|
10
|
+
|
11
|
+
desc 'Automates Lit installation'
|
12
|
+
|
13
|
+
def set_authentication_function
|
14
|
+
@authentication_function = options['authentication-function'].presence ||
|
15
|
+
ask("What's the authentication function, ie. :authenticate_user! :").presence ||
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_key_value_engine
|
20
|
+
@key_value_engine = options['key-value-engine'].presence ||
|
21
|
+
ask("What's the key value engine? ([hash] OR redis):").presence ||
|
22
|
+
:hash
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_redis_dependency
|
26
|
+
if @key_value_engine == 'redis'
|
27
|
+
puts 'Adding redis dependency'
|
28
|
+
gem 'redis'
|
29
|
+
Bundler.with_clean_env do
|
30
|
+
run 'bundle install'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def generate_api_key
|
36
|
+
@api_key = SecureRandom.base64 32
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_lit_initializer
|
40
|
+
path = "#{::Rails.root}/config/initializers/lit.rb"
|
41
|
+
if File.exist?(path)
|
42
|
+
puts 'Skipping config/initializers/lit.rb creation, file already exists!'
|
43
|
+
else
|
44
|
+
puts 'Adding lit initializer (config/initializers/lit.rb)...'
|
45
|
+
template 'initializer.rb', path
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def run_migrations
|
50
|
+
unless options['no-migrate']
|
51
|
+
puts 'Running rake db:migrate'
|
52
|
+
`rake db:migrate`
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def clear_cache
|
57
|
+
Lit.init.cache.reset
|
58
|
+
end
|
59
|
+
|
60
|
+
def mount_engine
|
61
|
+
puts "Mounting Lit::Engine at \"/lit\" in config/routes.rb..."
|
62
|
+
route "mount Lit::Engine => '/lit'"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/lit.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'lit/engine'
|
2
|
+
require 'lit/loader'
|
3
|
+
|
4
|
+
module Lit
|
5
|
+
mattr_accessor :authentication_function
|
6
|
+
mattr_accessor :authentication_verification
|
7
|
+
mattr_accessor :key_value_engine
|
8
|
+
mattr_accessor :storage_options
|
9
|
+
mattr_accessor :humanize_key
|
10
|
+
mattr_accessor :ignored_keys
|
11
|
+
mattr_accessor :ignore_yaml_on_startup
|
12
|
+
mattr_accessor :api_enabled
|
13
|
+
mattr_accessor :api_key
|
14
|
+
mattr_accessor :all_translations_are_html_safe
|
15
|
+
mattr_accessor :set_last_updated_at_upon_creation
|
16
|
+
mattr_accessor :store_request_info
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :loader
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.init
|
23
|
+
@@table_exists ||= check_if_table_exists
|
24
|
+
if loader.nil? && @@table_exists
|
25
|
+
self.loader ||= Loader.new
|
26
|
+
Lit.humanize_key = false if Lit.humanize_key.nil?
|
27
|
+
if Lit.ignored_keys.is_a?(String)
|
28
|
+
keys = Lit.ignored_keys.split(',').map(&:strip)
|
29
|
+
Lit.ignored_keys = keys
|
30
|
+
end
|
31
|
+
Lit.ignore_yaml_on_startup = true if Lit.ignore_yaml_on_startup.nil?
|
32
|
+
Lit.ignored_keys = [] unless Lit.ignored_keys.is_a?(Array)
|
33
|
+
# if loading all translations on start, migrations have to be already
|
34
|
+
# performed, fails on first deploy
|
35
|
+
# self.loader.cache.load_all_translations
|
36
|
+
Lit.storage_options ||= {}
|
37
|
+
end
|
38
|
+
self.loader
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.check_if_table_exists
|
42
|
+
Lit::Locale.table_exists?
|
43
|
+
rescue
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.get_key_value_engine
|
48
|
+
case Lit.key_value_engine
|
49
|
+
when 'redis'
|
50
|
+
require 'lit/adapters/redis_storage'
|
51
|
+
return RedisStorage.new
|
52
|
+
else
|
53
|
+
require 'lit/adapters/hash_storage'
|
54
|
+
return HashStorage.new
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.fallback=(_value)
|
59
|
+
::Rails.logger.error "[DEPRECATION] Lit.fallback= has been deprecated, please use `config.i18n.fallbacks` instead"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if defined? Rails
|
64
|
+
require 'lit/rails'
|
65
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'redis'
|
2
|
+
module Lit
|
3
|
+
extend self
|
4
|
+
def redis
|
5
|
+
$redis ||= nil
|
6
|
+
$redis = Redis.new(url: determine_redis_provider) unless $redis
|
7
|
+
$redis
|
8
|
+
end
|
9
|
+
|
10
|
+
def determine_redis_provider
|
11
|
+
ENV[ENV['REDIS_PROVIDER'] || 'REDIS_URL']
|
12
|
+
end
|
13
|
+
|
14
|
+
class RedisStorage
|
15
|
+
def initialize
|
16
|
+
Lit.redis
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
if Lit.redis.exists(_prefixed_key_for_array(key))
|
21
|
+
Lit.redis.lrange(_prefixed_key(key), 0, -1)
|
22
|
+
elsif Lit.redis.exists(_prefixed_key_for_nil(key))
|
23
|
+
nil
|
24
|
+
else
|
25
|
+
Lit.redis.get(_prefixed_key(key))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def []=(k, v)
|
30
|
+
delete(k)
|
31
|
+
if v.is_a?(Array)
|
32
|
+
Lit.redis.set(_prefixed_key_for_array(k), '1')
|
33
|
+
v.each do |ve|
|
34
|
+
Lit.redis.rpush(_prefixed_key(k), ve.to_s)
|
35
|
+
end
|
36
|
+
elsif v.nil?
|
37
|
+
Lit.redis.set(_prefixed_key_for_nil(k), '1')
|
38
|
+
Lit.redis.set(_prefixed_key(k), '')
|
39
|
+
else
|
40
|
+
Lit.redis.set(_prefixed_key(k), v)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete(k)
|
45
|
+
Lit.redis.del(_prefixed_key_for_array(k))
|
46
|
+
Lit.redis.del(_prefixed_key_for_nil(k))
|
47
|
+
Lit.redis.del(_prefixed_key(k))
|
48
|
+
end
|
49
|
+
|
50
|
+
def clear
|
51
|
+
Lit.redis.del(keys) unless keys.empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def keys
|
55
|
+
Lit.redis.keys(_prefixed_key + '*')
|
56
|
+
end
|
57
|
+
|
58
|
+
def has_key?(key)
|
59
|
+
Lit.redis.exists(_prefixed_key(key))
|
60
|
+
end
|
61
|
+
alias key? has_key?
|
62
|
+
|
63
|
+
def incr(key)
|
64
|
+
Lit.redis.incr(_prefixed_key(key))
|
65
|
+
end
|
66
|
+
|
67
|
+
def sort
|
68
|
+
Lit.redis.keys.sort.map do |k|
|
69
|
+
[k, self.[](k)]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def prefix
|
74
|
+
_prefix
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def _prefix
|
80
|
+
prefix = 'lit:'
|
81
|
+
if Lit.storage_options.is_a?(Hash) && Lit.storage_options.key?(:prefix)
|
82
|
+
prefix += "#{Lit.storage_options[:prefix]}:"
|
83
|
+
end
|
84
|
+
prefix
|
85
|
+
end
|
86
|
+
|
87
|
+
def _prefixed_key(key = '')
|
88
|
+
_prefix + key.to_s
|
89
|
+
end
|
90
|
+
|
91
|
+
def _prefixed_key_for_array(key = '')
|
92
|
+
_prefix + 'array_flags:' + key.to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
def _prefixed_key_for_nil(key = '')
|
96
|
+
_prefix + 'nil_flags:' + key.to_s
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/lit/cache.rb
ADDED
@@ -0,0 +1,356 @@
|
|
1
|
+
module I18n
|
2
|
+
class << self
|
3
|
+
@@cache_store = nil
|
4
|
+
|
5
|
+
def cache_store
|
6
|
+
@@cache_store || I18n.backend.cache
|
7
|
+
end
|
8
|
+
|
9
|
+
def cache_store=(store)
|
10
|
+
@@cache_store = store
|
11
|
+
end
|
12
|
+
|
13
|
+
def perform_caching?
|
14
|
+
!cache_store.nil?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Lit
|
20
|
+
class Cache
|
21
|
+
def initialize
|
22
|
+
@hits_counter = Lit.get_key_value_engine
|
23
|
+
@request_info_store = Lit.get_key_value_engine
|
24
|
+
@hits_counter_working = true
|
25
|
+
@keys = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](key)
|
29
|
+
key_without_locale = split_key(key).last
|
30
|
+
update_hits_count(key)
|
31
|
+
store_request_info(key_without_locale)
|
32
|
+
localization = localizations[key]
|
33
|
+
update_request_keys(key_without_locale, localization)
|
34
|
+
localization
|
35
|
+
end
|
36
|
+
|
37
|
+
def []=(key, value)
|
38
|
+
update_locale(key, value)
|
39
|
+
end
|
40
|
+
|
41
|
+
def init_key_with_value(key, value)
|
42
|
+
update_locale(key, value, true)
|
43
|
+
end
|
44
|
+
|
45
|
+
def has_key?(key)
|
46
|
+
localizations.has_key?(key)
|
47
|
+
end
|
48
|
+
|
49
|
+
def sync
|
50
|
+
localizations.clear
|
51
|
+
end
|
52
|
+
|
53
|
+
def keys
|
54
|
+
return @keys if @keys.present?
|
55
|
+
@keys = localizations.keys
|
56
|
+
return @keys if localizations.prefix.nil?
|
57
|
+
@keys = @keys.map do |k|
|
58
|
+
k.gsub(/^#{localizations.prefix}/, '')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_locale(key, value, force_array = false, startup_process = false)
|
63
|
+
key = key.to_s
|
64
|
+
locale_key, key_without_locale = split_key(key)
|
65
|
+
locale = find_locale(locale_key)
|
66
|
+
localization = find_localization(locale, key_without_locale, value: value, force_array: force_array, update_value: true)
|
67
|
+
return localization.get_value if startup_process && localization.is_changed?
|
68
|
+
localizations[key] = localization.get_value if localization
|
69
|
+
end
|
70
|
+
|
71
|
+
def update_cache(key, value)
|
72
|
+
key = key.to_s
|
73
|
+
localizations[key] = value
|
74
|
+
end
|
75
|
+
|
76
|
+
def delete_locale(key)
|
77
|
+
key = key.to_s
|
78
|
+
keys.delete(key)
|
79
|
+
locale_key, key_without_locale = split_key(key)
|
80
|
+
locale = find_locale(locale_key)
|
81
|
+
delete_localization(locale, key_without_locale)
|
82
|
+
end
|
83
|
+
|
84
|
+
def load_all_translations
|
85
|
+
first = Localization.order(id: :asc).first
|
86
|
+
last = Localization.order(id: :desc).first
|
87
|
+
if !first || (!localizations.has_key?(first.full_key) ||
|
88
|
+
!localizations.has_key?(last.full_key))
|
89
|
+
Localization.includes([:locale, :localization_key]).find_each do |l|
|
90
|
+
localizations[l.full_key] = l.get_value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def refresh_key(key)
|
96
|
+
key = key.to_s
|
97
|
+
locale_key, key_without_locale = split_key(key)
|
98
|
+
locale = find_locale(locale_key)
|
99
|
+
localization = find_localization(locale, key_without_locale, default_fallback: true)
|
100
|
+
localizations[key] = localization.get_value if localization
|
101
|
+
end
|
102
|
+
|
103
|
+
def delete_key(key)
|
104
|
+
key = key.to_s
|
105
|
+
localizations.delete(key)
|
106
|
+
key_without_locale = split_key(key).last
|
107
|
+
localization_keys.delete(key_without_locale)
|
108
|
+
I18n.backend.reload!
|
109
|
+
end
|
110
|
+
|
111
|
+
def reset
|
112
|
+
@locale_cache = {}
|
113
|
+
localizations.clear
|
114
|
+
localization_keys.clear
|
115
|
+
load_all_translations
|
116
|
+
end
|
117
|
+
alias_method :clear, :reset
|
118
|
+
|
119
|
+
def find_locale(locale_key)
|
120
|
+
locale_key = locale_key.to_s
|
121
|
+
@locale_cache ||= {}
|
122
|
+
unless @locale_cache.key?(locale_key)
|
123
|
+
locale = Lit::Locale.where(locale: locale_key).first_or_create!
|
124
|
+
@locale_cache[locale_key] = locale
|
125
|
+
end
|
126
|
+
@locale_cache[locale_key]
|
127
|
+
end
|
128
|
+
|
129
|
+
# this comes directly from copycopter.
|
130
|
+
def export
|
131
|
+
reset
|
132
|
+
localizations_scope = Lit::Localization
|
133
|
+
unless ENV['LOCALES'].blank?
|
134
|
+
locale_keys = ENV['LOCALES'].to_s.split(',') || []
|
135
|
+
locale_ids = Lit::Locale.where(locale: locale_keys).pluck(:id)
|
136
|
+
localizations_scope = localizations_scope.where(locale_id: locale_ids) unless locale_ids.empty?
|
137
|
+
end
|
138
|
+
db_localizations = {}
|
139
|
+
localizations_scope.find_each do |l|
|
140
|
+
db_localizations[l.full_key] = l.get_value
|
141
|
+
end
|
142
|
+
exported_keys = nested_string_keys_to_hash(db_localizations)
|
143
|
+
exported_keys.to_yaml
|
144
|
+
end
|
145
|
+
|
146
|
+
def nested_string_keys_to_hash(db_localizations)
|
147
|
+
# http://subtech.g.hatena.ne.jp/cho45/20061122
|
148
|
+
deep_proc = proc do |_k, s, o|
|
149
|
+
if s.is_a?(Hash) && o.is_a?(Hash)
|
150
|
+
next s.merge(o, &deep_proc)
|
151
|
+
end
|
152
|
+
next o
|
153
|
+
end
|
154
|
+
nested_keys = {}
|
155
|
+
db_localizations.sort.each do |k, v|
|
156
|
+
key_parts = k.to_s.split('.')
|
157
|
+
converted = key_parts.reverse.reduce(v) { |a, n| { n => a } }
|
158
|
+
nested_keys.merge!(converted, &deep_proc)
|
159
|
+
end
|
160
|
+
nested_keys
|
161
|
+
end
|
162
|
+
|
163
|
+
def get_global_hits_counter(key)
|
164
|
+
@hits_counter['global_hits_counter.' + key]
|
165
|
+
end
|
166
|
+
|
167
|
+
def get_hits_counter(key)
|
168
|
+
@hits_counter['hits_counter.' + key]
|
169
|
+
end
|
170
|
+
|
171
|
+
def stop_hits_counter
|
172
|
+
@hits_counter_working = false
|
173
|
+
end
|
174
|
+
|
175
|
+
def restore_hits_counter
|
176
|
+
@hits_counter_working = true
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
def localizations
|
182
|
+
@localizations ||= Lit.get_key_value_engine
|
183
|
+
end
|
184
|
+
|
185
|
+
def localization_keys
|
186
|
+
@localization_keys ||= Lit.get_key_value_engine
|
187
|
+
end
|
188
|
+
|
189
|
+
def find_localization(locale, key_without_locale, value: nil, force_array: false, update_value: false, default_fallback: false)
|
190
|
+
return nil if value.is_a?(Hash)
|
191
|
+
ActiveRecord::Base.transaction do
|
192
|
+
localization_key = find_localization_key(key_without_locale)
|
193
|
+
localization = Lit::Localization.where(locale_id: locale.id). \
|
194
|
+
where(localization_key_id: localization_key.id).first_or_initialize
|
195
|
+
if update_value || localization.new_record?
|
196
|
+
if value.is_a?(Array)
|
197
|
+
value = parse_array_value(value) unless force_array
|
198
|
+
elsif !value.nil?
|
199
|
+
value = parse_value(value, locale)
|
200
|
+
else
|
201
|
+
if ::Rails.application.config.i18n.fallbacks
|
202
|
+
value = fallback_localization(locale, key_without_locale)
|
203
|
+
elsif default_fallback
|
204
|
+
value = fallback_to_default(localization_key, localization)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
localization.update_default_value(value)
|
208
|
+
end
|
209
|
+
return localization
|
210
|
+
end
|
211
|
+
nil
|
212
|
+
end
|
213
|
+
|
214
|
+
# fallback to translation in different locale
|
215
|
+
def fallback_localization(locale, key_without_locale)
|
216
|
+
value = nil
|
217
|
+
return nil unless fallbacks = ::Rails.application.config.i18n.fallbacks
|
218
|
+
keys = fallbacks == true ? @locale_cache.keys : fallbacks
|
219
|
+
keys.map(&:to_s).each do |lc|
|
220
|
+
if lc != locale.locale && value.nil?
|
221
|
+
nk = "#{lc}.#{key_without_locale}"
|
222
|
+
v = localizations[nk]
|
223
|
+
value = v if v.present? && value.nil?
|
224
|
+
end
|
225
|
+
end
|
226
|
+
value
|
227
|
+
end
|
228
|
+
|
229
|
+
# tries to get `default_value` from localization_key - checks other
|
230
|
+
# localizations
|
231
|
+
def fallback_to_default(localization_key, localization)
|
232
|
+
localization_key.localizations.where.not(default_value: nil). \
|
233
|
+
where.not(id: localization.id).first&.default_value
|
234
|
+
end
|
235
|
+
|
236
|
+
def find_localization_for_delete(locale, key_without_locale)
|
237
|
+
localization_key = find_localization_key_for_delete(key_without_locale)
|
238
|
+
return nil unless localization_key
|
239
|
+
Lit::Localization.find_by(locale_id: locale.id,
|
240
|
+
localization_key_id: localization_key.id)
|
241
|
+
end
|
242
|
+
|
243
|
+
def delete_localization(locale, key_without_locale)
|
244
|
+
localization = find_localization_for_delete(locale, key_without_locale)
|
245
|
+
return unless localization
|
246
|
+
localizations.delete("#{locale.locale}.#{key_without_locale}")
|
247
|
+
localization_keys.delete(key_without_locale)
|
248
|
+
localization.destroy # or localization.default_value = nil; localization.save!
|
249
|
+
end
|
250
|
+
|
251
|
+
## checks parameter type and returns value basing on it
|
252
|
+
## symbols are beeing looked up in db
|
253
|
+
## string are returned directly
|
254
|
+
## procs are beeing called (once)
|
255
|
+
## hashes are converted do string (for now)
|
256
|
+
def parse_value(v, locale)
|
257
|
+
new_value = nil
|
258
|
+
case v
|
259
|
+
when Symbol then
|
260
|
+
lk = Lit::LocalizationKey.where(localization_key: v.to_s).first
|
261
|
+
if lk
|
262
|
+
loca = Lit::Localization.where(locale_id: locale.id).
|
263
|
+
where(localization_key_id: lk.id).first
|
264
|
+
new_value = loca.get_value if loca && loca.get_value.present?
|
265
|
+
end
|
266
|
+
when String then
|
267
|
+
new_value = v
|
268
|
+
when Hash then
|
269
|
+
new_value = nil
|
270
|
+
when Proc then
|
271
|
+
new_value = nil # was v.call - requires more love
|
272
|
+
else
|
273
|
+
new_value = v.to_s
|
274
|
+
end
|
275
|
+
new_value
|
276
|
+
end
|
277
|
+
|
278
|
+
def parse_array_value(value)
|
279
|
+
new_value = nil
|
280
|
+
value_clone = value.dup
|
281
|
+
while (v = value_clone.shift) && v.present?
|
282
|
+
pv = parse_value(v, locale)
|
283
|
+
new_value = pv unless pv.nil?
|
284
|
+
end
|
285
|
+
new_value
|
286
|
+
end
|
287
|
+
|
288
|
+
def find_localization_key(key_without_locale)
|
289
|
+
unless localization_keys.key?(key_without_locale)
|
290
|
+
find_or_create_localization_key(key_without_locale)
|
291
|
+
else
|
292
|
+
Lit::LocalizationKey.find_by(id: localization_keys[key_without_locale]) || find_or_create_localization_key(key_without_locale)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def find_localization_key_for_delete(key_without_locale)
|
297
|
+
lk = Lit::LocalizationKey.find_by(id: localization_keys[key_without_locale]) if localization_keys.has_key?(key_without_locale)
|
298
|
+
lk || Lit::LocalizationKey.where(localization_key: key_without_locale).first
|
299
|
+
end
|
300
|
+
|
301
|
+
def split_key(key)
|
302
|
+
Lit::Cache.split_key(key)
|
303
|
+
end
|
304
|
+
|
305
|
+
def find_or_create_localization_key(key_without_locale)
|
306
|
+
localization_key = Lit::LocalizationKey.where(localization_key: key_without_locale).first_or_create!
|
307
|
+
localization_keys[key_without_locale] = localization_key.id
|
308
|
+
localization_key
|
309
|
+
end
|
310
|
+
|
311
|
+
def update_hits_count(key)
|
312
|
+
return unless @hits_counter_working
|
313
|
+
key_without_locale = split_key(key).last
|
314
|
+
@hits_counter.incr('hits_counter.' + key)
|
315
|
+
@hits_counter.incr('global_hits_counter.' + key_without_locale)
|
316
|
+
end
|
317
|
+
|
318
|
+
def store_request_info(key_without_locale)
|
319
|
+
return unless Lit.store_request_info
|
320
|
+
return unless Thread.current[:lit_current_request_path].present?
|
321
|
+
info = get_request_info(key_without_locale)
|
322
|
+
parts = info.split(' ').push(Thread.current[:lit_current_request_path]).uniq
|
323
|
+
parts.shift if parts.count > 10
|
324
|
+
@request_info_store['request_info.' + key_without_locale] = parts.join ' '
|
325
|
+
end
|
326
|
+
|
327
|
+
def update_request_keys(key_without_locale, localization)
|
328
|
+
return if Thread.current[:lit_request_keys].nil?
|
329
|
+
Thread.current[:lit_request_keys] ||= {}
|
330
|
+
Thread.current[:lit_request_keys][key_without_locale] = localization
|
331
|
+
end
|
332
|
+
|
333
|
+
def request_keys
|
334
|
+
Thread.current[:lit_request_keys] || {}
|
335
|
+
end
|
336
|
+
public :request_keys
|
337
|
+
|
338
|
+
def get_request_info(key_without_locale)
|
339
|
+
@request_info_store['request_info.' + key_without_locale].to_s
|
340
|
+
end
|
341
|
+
public :get_request_info
|
342
|
+
|
343
|
+
def self.split_key(key)
|
344
|
+
key.split('.', 2)
|
345
|
+
end
|
346
|
+
|
347
|
+
def self.flatten_hash(hash_to_flatten, parent = [])
|
348
|
+
hash_to_flatten.flat_map do |key, value|
|
349
|
+
case value
|
350
|
+
when Hash then flatten_hash(value, parent + [key])
|
351
|
+
else [(parent + [key]).join('.'), value]
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|