As @sascha mentions, Picat has the option to save a SAT model to CNF, using the dump(file.cnf) option (or just dump to print the CNF to stdout). It's described a little more in the Picat Guide section 12.6.3 "Solving Options for sat" (See http://picat-lang.org/download/picat_guide.pdf)
Here's a small example how to use this for a Picat model:
import sat.
main => queens(8,Q).
queens(N, Q) =>
Q=new_list(N),
Q :: 1..N,
all_different(Q),
all_different($[Q[I]-I : I in 1..N]),
all_different($[Q[I]+I : I in 1..N]),
solve($[dump("sat_dump.cnf"),ff],Q).
The output file sat_dump.cnf then contains the CNF for this model. Note that when using the dump/1 option, the model don't solves the problem, it just creates the CNF file.
With a little tweaking one can use this to generate CNF for a MiniZinc model using the PicatSAT program, see https://github.com/nfzhou/fzn_picat/ . The fix is to add the option dump(file.cnf) to the options (Option = ... ) in the file fzn_picat_sat.pi . Note that with this simple fix, after the program generated the CNF file, there will probably be an error when the program tries to print out the solution (since there is no created solution that can be printed).