Replace String

Article Content

Command that allows replace string in template with keeping translation assigned to it.


  • current_string - Full string you want to replace,
  • replace_string - New string to put instead current_string


  • current_string argument must be full string that exists in template, that string in template should be placed with {% blocktrans %}  and no whitespaces around it,
  • django project must have set translations with generated locale folders


# -*- coding: utf-8 -*-

from import BaseCommand, CommandError
from django.conf import settings
import os, sys, shutil
import re
import codecs
import unicodedata
import time
from import call_command

#global vars
findStr = None
repStr = None
found = False

def replaceStringInFile(findStr, repStr, filePath):
    '''replaces all findStr by repStr in file filePath'''
    global found
    tempName = filePath+'~~'
    backupName = filePath+'~'
    inputFile = open(filePath)
    outputFile = open(tempName, 'w')

    for thisLine in inputFile:
        if findStr in thisLine:
            found = True
        outputFile.write(thisLine.replace(findStr, repStr))

    shutil.copy2(filePath, backupName)
    os.rename(tempName, filePath)
    print "file processed: {}".format(filePath)

def filterFile(dummyArg, thisDir, dirChildrenList):
     '''search for html files in projects and launching replaceStringInFile'''
     for thisChild in dirChildrenList:
         if '.html' == os.path.splitext(thisChild)[1] and os.path.isfile(thisDir+'/'+thisChild):
             replaceStringInFile(findStr, repStr, thisDir+'/'+thisChild)

def find_languages_folders(path):
    Collecting folder names in specified locale path
    :param path: path to locale
    :return: dict with key(languages folder names) and None values
    languageDict = {}
    for language in os.listdir(path):
        if not os.path.isfile(language) and language[0] != '.' and language is not None:
            languageDict[language] = None
    return languageDict

def collect_translations(path,languageDict):
    Collecting current translations for replaced string
    :param path: path to locale
    :param languageDict: dict with language codes as keys
    :return: languageDict with current translations as values
    for key, value in languageDict.iteritems():
        fo = + '/' + key + '/LC_MESSAGES/django.po', encoding='utf-8')
        lines = fo.readlines()
        for index, line in enumerate(lines):
            line = re.split('\n|\"|', line)[1]
            if line == findStr:
                print line
                translation = re.split('\n|\"|', lines[index + 1])[1]
                languageDict[key] = translation
    return languageDict

def insert_translations(path,language,translation):
    Insert translations to all language files for given string
    :param path: path to locale
    :param language: iso code for language
    :param translation: translation for string
    path = path + '/' + language + '/LC_MESSAGES/django.po'
    fo =, encoding='utf-8')
    lines = fo.readlines()
    for index,line in enumerate(lines):
        line = re.split('\n|\"|',line)[1]
        if line == repStr:
            lines[index+1] = 'msgstr \"' + translation +'\"\n'
            print "Processing translation for " + language
            if 'fuzzy' in lines[index-1]:
                print 'deleting fuzzy'
                del lines[index-1]
    fo = open('fxnet/locale/' + language + '/LC_MESSAGES/django.po', 'w')
    for line in lines:

class Command(BaseCommand):
    help = 'Replacing string in template file and keeps translations to that string'

    def add_arguments(self, parser):
       parser.add_argument('current_string', type=str)
       parser.add_argument('replacement_string', type=str)

    def handle(self, *args, **options):
           LOCALE_PATH = settings.LOCALE_PATHS[0]
           print "Locale path not found"
        global findStr, repStr, found
        findStr = options['current_string']
        repStr = options['replacement_string']
        os.path.walk(settings.BASE_DIR, filterFile, None)
        if not found:
            print "Can't find current_string in templates"
        languageDict = find_languages_folders(LOCALE_PATH)
        languageDict = collect_translations(LOCALE_PATH,languageDict)
        print languageDict
        call_command('makemessages', '--no-wrap')
        for language,translation in languageDict.iteritems():
            if translation:
                print "translation for " + language + " not found"

Example of use

(venv2) 192:example-project-com-website domin$ python replacestring "Old string" "Replacement string"
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/404.html
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/base.html
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/finisher.html
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/footer.html
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/header.html
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/index.html
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/main-menu-bottom.html
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/main-menu-top.html
file processed: /Users/domin/Projects/example-project-com-website/example-project/templates/scripts.html
processing locale el
processing locale fr
processing locale az
processing locale ru
processing locale hr
processing locale vi
processing locale de
processing locale zh_Hant
processing locale it
processing locale sk
processing locale fa
processing locale tl
processing locale zh_CN
processing locale es
processing locale cs
processing locale hu
processing locale ro
processing locale ar
processing locale pl
translation for hr not found
translation for vi not found
translation for de not found



Added by dominik

Date: Dec. 5, 2017, 11:36 p.m.