Learning to be a Djangonaut: Localisation/translation – locale for Chile

Djangonaut
A person who is expert in Django web framework.
He is a Djangonaut dude.

In my pursuit to become a gun djangonaut and get my knowledge of the framework sound and stable I have been following along Marina Mele’s fantastic series “TaskBuster Django Tutorial”. It covers a lot of topics that I am keen to understand and be able to explain one day.

My current goal is to have a django web app that has a Restful API that will allow various types of authentication. On top of this I will create an iOS app that can talk to it.

I had started to follow along with a post that Félix Descôteaux had written titled “A Rest API using Django and authentication with OAuth2 AND third parties!”. As I was getting into it I realised that I had better spend some time get a better basic understanding of Django and some other key concepts of python and web app development I had yet to explore. Geez the internet is just so cool when you want to learn something!

Along the way following Marina’s series I hit a bit trouble getting “Localizations” to work – when a site works across multiple languages. Django seems to have a easy to use mechanism but I was having issues with the locale for Chilean Spanish (I always am really…). 🙂

So in an effort to try to give back a little to the wonderful internet for anyone else who may stumble across this post with the same issue…

Basically:

It was a combination of using “es-CL”, “es_CL” & “es-cl” in various places.

 

Property Value
Base locale ID es-CL
Language es
Language Spanish
Country CL
Country Chile

In the base.py (settings file):

LANGUAGES = (
('en', _('English')),
('<strong>es-CL</strong>', _('Spanish (Chile)')),
)

Then in the test_all_users.py I used ‘es-cl‘ wherever necessary.

Then in the tb_test virtual env shell:

$ python manage.py makemessages -l es_CL

I edited the django.po with my translated strings.
(I had to laugh when I read the “po” in django.po for this Chilean translation :] )

Then in the tb_test virtual env shell:

$ python manage.py compilemessages -l es_CL

Now I am passing the tests and seeing the translated page in the browser.

I hope that helps someone out one day!

fcp 7 to nuke

Scenario
A FCP 7 timeline with 20 shots in it (all in one video layer).
I need to comp them all separately in nuke.
I want to have each shot in a separate numbered directory, with subdirectories for “scripts” and “renders”

Here is a little python script i wrote this morning to export a basic FCP 7 timeline as a series of nuke scripts into numbered shot directories.
This script parses an XML file that I exported from FCP 7 (the sequence/edit).

I have only used this for the purposes i needed, but it works.
Perhaps it could be expanded to incorporate multiple video layers.

Each nuke script that is generated is just a read node, with the nuke.root frame range set to the duration of the clip in FCP 7.

Even if the script doesn’t help everyone’s fcp7-nuke needs I found that i learnt a lot about Python’s elementTree XML library. Nice clean simple.
And also this page was a big help to get things going:
http://drumcoder.co.uk/blog/2010/jun/17/using-elementtree-python/

The script needs to be run from a shell/terminal:
python /path/to/the/script/fcpNuke.py /path/to/you/xmlfile.xml

*file re-uploaded 11 May 2012

The script:
fcp7toNuke (349 downloads)

some Nuke Python snippets (and other general coolness)

If anyone has some cool snippets to share please feel free to leave them in a comment below.

*last updated: 23 December 2016

user knob value in an expression / particle expression  

[value yourUserKnob]

random particle colour with particle expression node

*** a blendMat node must be applied before the emitter:

 operation: plus
 surface blend: modulate

the “color” parameter of a particleExpression node can be set using a 3dVector:
v( r, g, b )

and each channel can be referenced like this:
the red value for example :
x(color)

give the colour parameter a random value – (needs to be a 3dVector)
v(random*2, random, random/1.4 )

iterate over the animation curve of a Transform node copying the value of the Y position to a parameter of another Transform node.

dest = nuke.nodes.Transform()
destTransform = dest["translate"]
destTransform.setAnimated()
destAnim = dest["translate"].animation(1)
 
a = nuke.selectedNode()["translate"]
ypos = a.animation(1)
keys = ypos.keys()
 
for a in range(0,42):
    dest["translate"].animation(1).setKey(a, ypos.evaluate(a))

 

display the current duration since the first frame (useful when sequence doesn’t start at zero/one)
put this in a text node or in a node’s “label” tab

[python {int( nuke.frame() - nuke.root()['first_frame'].value() ) }]

 

take a RotoPaint and change each layer’s RGBA to a grey level based on it’s “depth” – useful for prep’ing for a stereo conversion i’d imagine

import random
a = nuke.selectedNode()
if a.Class() == "RotoPaint":
    knob = a['curves']
    i = 0.0
    for c in knob.rootLayer:
 
        pos = float ((len(knob.rootLayer) - i) / len(knob.rootLayer))
        i = i+1
 
        attrs = c.getAttributes()
        attrs.set(1, attrs.kRedOverlayAttribute, pos)
        attrs.set(1, attrs.kRedAttribute, pos)
        attrs.set(1, attrs.kGreenOverlayAttribute, pos)
        attrs.set(1, attrs.kGreenAttribute, pos)
        attrs.set(1, attrs.kBlueOverlayAttribute, pos)
        attrs.set(1, attrs.kBlueAttribute, pos)
        attrs.set(1, attrs.kAlphaOverlayAttribute, pos)
        attrs.set(1, attrs.kAlphaAttribute, pos)

for all selected Tracker nodes multiply their track values by a factor of 4

for a in nuke.selectedNodes():
    if a.Class()=="Tracker3":
 
	def scaleMe(track):
		if track.isAnimated():
			for j in range (0,2):
		        anim = track.animation(j)
		        keys = anim.keys()
		        scaleFactor = 4
		        while keys:
		            keys.pop().y *= scaleFactor
	#i am sure there is a much nicer way of iterating over all the knobs but this worked for what i quickly needed
	t1 = a['track1']
	t2 = a['track2']
	t3 = a['track3']
	t4 = a['track4']
	scaleMe(t1)
	scaleMe(t2)
	scaleMe(t3)
	scaleMe(t4)

set bbox to “B” for nodes inside all Group nodes

import nuke
 
def bboxGroup():
  for b in nuke.allNodes():
    if b.Class() == "Group":
      for a in nuke.toNode(b.name()).nodes():
        classTypes = ['Merge' , 'Keymix', 'Copy', ]
        print a.name()
        for n in classTypes:
          if n in a.Class():
            try:
              for p in a['bbox'].values():
                if 'B' in p:
                  a['bbox'].setValue(a['bbox'].values().index(p))
            except:
              pass

“Autowrite” node
Copy the following line into the python “beforeRender” field in a write node.
The write node’s “file” field will be filled based on the script’s name/path.
Obviously this all depends on your pipeline etc.

For my current situation each vfx shot has it’s own directory, which is then populated with “renders” & “scripts” subdirectories.
So for me I can do this:

nuke.thisNode()["file"].setValue(nuke.root().name().replace("scripts","renders").replace(".nk",".mov"))

delete all nodes that are not selected

s = nuke.selectedNodes()
b = nuke.allNodes()
 
for n in b:
    if n not in s:
        nuke.delete(n)

selects all dependencies (input nodes & their parents) from a selected node

a = nuke.selectedNode()
nodesToSelect = []
 
nodesToSelect.append(a)
def climb(node):
    # print node.name()
    for n in node.dependencies():
        nodesToSelect.append(a)
        climb(n)
 
climb(a)
 
for x in nodesToSelect:
	print x.name()
    # x.setSelected(1)

set all Read nodes to cache locally

for a in nuke.allNodes():
    if a.Class()=='Read':
        a['cached'].setValue(1)
        a['cacheLocal'].setValue(0)

print last frame of script

print nuke.root()['last_frame'].value()

create a backdrop based on selected Nodes

margin = 100
xpMax = nuke.selectedNode().xpos()
xpMin = nuke.selectedNode().xpos()
ypMax = nuke.selectedNode().ypos()
ypMin = nuke.selectedNode().ypos()
 
for a in nuke.selectedNodes():
    if a.xpos() &gt; xpMax:
        xpMax = a.xpos()
    if a.xpos() &lt; xpMin: xpMin = a.xpos() if a.ypos() &gt; ypMax:
        ypMax = a.ypos()
    if a.ypos() &lt; ypMin:
        ypMin = a.ypos()
 
bd = nuke.nodes.BackdropNode(bdwidth=(xpMax-xpMin)+margin, bdheight=(ypMax-ypMin)+margin) 
bd.setXpos(xpMin-margin/2)
bd.setYpos(ypMin-margin/2)

disable “postage stamps” on only “Read” nodes

for a in nuke.allNodes():
   if a.Class()=='Read':
       a['postage_stamp'].setValue(0)

disable “postage stamps” on all nodes

for a in nuke.allNodes():
    try:
        a['postage_stamp'].setValue(0)
    except:
        pass

“unhide” all nodes’ inputs – useful when receiving a sneaky comp/lighting script

for a in nuke.allNodes():
    try:
        a['hide_input'].setValue(0)
    except:
        pass

change the “first” frame of all selected nodes that are “Read” nodes:
(example changes the first frame to 1018)

for a in nuke.selectedNodes():
    if a.Class() == 'Read':
        a['first'].setValue(1018)

print a selected nodes’ methods

import struct
node = nuke.selectedNode()
for a in node['lookup'].animations():
    print dir(a)

print inputs (dependencies) of a selected node:

for a in nuke.selectedNode().dependencies():
    print a.name()

print outputs (dependents) of a selected node:

for a in nuke.selectedNode().dependent():
    print a.name()

find all the TimeOffset nodes in a Group called “Group2”, and change the value of each offset based on it’s position in the array of found time offsets

tos = []
for a in nuke.toNode('Group2').nodes():
	if a.Class()=='TimeOffset':
		tos.append(a)
for b in tos:
	b['time_offset'].setValue(tos.index(b))

set the ‘bbox’ for any selected Merge, Keymix & Copy nodes to “B”

for a in nuke.selectedNodes():
	classTypes = ['Merge' , 'Keymix', 'Copy', ]
	for n in classTypes:
		if n in a.Class():
			for p in a['bbox'].values():
				if 'B' in p:
					a['bbox'].setValue(a['bbox'].values().index(p))

remove all animation from a selected nodes

for a in nuke.selectedNode().knobs():
	nuke.selectedNode()[a].clearAnimated()

add keyframes – animate a mix

for a in nuke.selectedNodes():
	a['mix'].setAnimated()
	a['mix'].setValueAt(1,nuke.frame())
	a['mix'].setValueAt(0,(nuke.frame() - 1))

half the colour value of all the Constant nodes in a script

for a in nuke.allNodes():
	if a.Class() == "Constant":
		a['color'].setValue(a['color'].value()[0] / 2 , 0)
		a['color'].setValue(a['color'].value()[1] / 2 , 1)
		a['color'].setValue(a['color'].value()[2] / 2 , 2)

find all the transform nodes in a script, and if their input is a Crop, set the ‘scale’ value to be twice it’s current value (also checks if the scale is a list/array or a float)

for a in nuke.allNodes():
	if a.Class() == "Transform":
		if a.input(0).Class() == "Crop":
			x = a['scale'].value()
			if type(x).__name__ == 'list':
				a['scale'].setValue(x[0] * 2 , 0)
				a['scale'].setValue(x[1] * 2 , 1)
			if type(x).__name__ == 'float':
				a['scale'].setValue(x*2)

set all the gain values of all ColorCorrect nodes to be twice their current value

for a in nuke.allNodes():
	if a.Class() == "ColorCorrect":
		a['gain'].setValue(a['gain'].value() * 2)

print files with ‘mov’ in filename

for a in nuke.allNodes():
	if 'Read' in a['name'].value():
		if 'mov' in a['file'].value():
			print a['file'].value()

change font size of all “write” nodes in script

for a in nuke.selectedNodes():
	if "Write" in a['name'].value():
		a['note_font_size'].setValue(60)

create 20 constants with incrementing colour values

def makeConstants(amount):
	for i in range(amount):
		a= nuke.nodes.Constant()
		color= float( float(i) / float(amount) )
		a['color'].setValue(color)
makeConstants(20)

change the name of all Text nodes to contents the text “message”

for a in nuke.allNodes():
    if a.Class()=='Text':
        a.setName(a['message'].value())

##Expressions
(in an expression node) – alpha channel – if the y value of the pixel is even, make it 0, else make it 1 (for viewing fields?)
y%2==1?0:1