How to customize folder name when compilemessages in website insternationalization - django

For website Internationalization when run this command
django-admin compilemessages -l de
it produce the .po file under the locale folder like
locale/de/LC_MESSAGES/django.po
I want to rename LC_MESSAGES
How can I do this ???
Please help me

You should add a code snippet to rename the directory, this is the hard way but unfortunately, I don't know a better one.
import os
basedir = 'locale/de/' # Or you should add something like C:/locale/de
newname = 'Your script'
os.rename(os.path.join(basedir, newname)

Related

django-admin makemessages --no-obsolete doesn't seem to be working

First of all, I am expecting --no-obsolete would comment out msgid and msgstr if gettext is deleted, right?
How I am testing is:
I wrote gettext("some string here") in view
I ran makemessages command
It wrote a .po file as expected
Then I deleted gettext() line from view and saved file, verified runserver working.
I ran makemessages --no-obsolete and it has not made any changes to .po file.
.po file content extract .
#. Translators: This message is a test of wrap line
#: servers/views.py:31
msgid "Do let me know if it works."
msgstr ""
dev environment
Django = 1.11
OS = Mac/Ubuntu 14.04
settings.py
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
LOCALE = (
os.path.join(os.path.dirname(__file__), "locale"),
)
Now with the help of Julien and Tarun, I found following observations.
python manage.py makemessages -l <locale>
If there is no gettext in the file being processed, the above command won't write/update .po file. That means if the corresponding .po file earlier had entries for msgstr and msgid, then it won't remove those entries unless file being processed had at least one gettext.
Note: Above behavior is irrespective of --no-obsolete
Now to make the --no-obsolete work as expected we need to follow the steps below.
First thing run python manage.py makemessages -l <locale>, this would write .po file with msgid and msgstr.
Now set msgstr and run python manage.py compilemessages -l <locale>. This command writes .mo file in the same directory as .po file.
Now next time when you run makemessages again (without --no-obsolete), .po and .mo files are compared and missing/deleted gettext are commented in .po file.
And when you run makemessages --no-obsolete, commented entries are removed from the .po file.
E.g
if you have 3 gettext entries, and you run makemessages first time, it would write 3 msgid and 3 msgstr in .po file. Now if you remove all gettext entries, .po file won't be updated after you run makemessages again, but if your keep at least 1 gettext entry in same file and run makemessages again, it would delete all msgid and msgstr for deleted gettext entries.
But if you run compilemessages after makemessages, .mo file is created and then for subsequent makemessages commands .po and .mo files are compared and then msgid and msgstr is commented in .po file for deleted gettext entries.
Then finally when you run makemessages with --no-obsolete option the commented messages from .po files are deleted permanently.
What the --no-obsolete does is to run a command called msgattrib with the --no-obsolete option on the content the po file. A typical case would be you generate your po file with makemessages, you get this:
#: servers/views.py:31
msgid "Do let me know if it works."
msgstr ""
Then you translate:
#: servers/views.py:31
msgid "Do let me know if it works."
msgstr "translation"
Then you remove the gettext entry, it'll still by default keep the translation, but mark it as obsolete.
#: servers/views.py:31
#~msgid "Do let me know if it works."
#~msgstr "translation"
If you set --no-obsolete option, then once your po file is done, it'll run msgattr with no-obsolete option. This will remove lines tagged with #~. See https://linux.die.net/man/1/msgattrib
But, the way makemessages is built, is that this will be called once the po file is written. But if there are no gettext in the files being processed, then it won't write to the po file. It'll just stop before getting to this msgattrib command. The po file you see is the one generated by the previous makemessages command. So the no-obsolete won't do anything.
There's no real solution to this. the no-obsolete option doesn't deal with the cases where you don't have any gettext to process.
So I think #JulienGrégoire was right about the fact that if there is no translation processed then the --no-obsolete won't work. There needs to be at least one translation captured for --no-obsolete to work.
But the solution to this quite simple. You can update your settings.py to define LANGUAGES like below
from django.utils.translation import ugettext_lazy as _
LANGUAGES = (
('en', _('English')),
('fr', _('French')),
)
Now your settings will always generate a translation. So it will make sure that you get --no-obsolete working every time you use it

Django Static Files: Any Way to Get More Fine-Grained Control?

Django's static files feature allows you to specify certain directories to have "collected" in to a public-facing folder. That's great, but is there any way to get more fine-grained control than just having certain folders? For instance, is there anyway to specify ...
Including specific files
Excluding specific files
Excluding specific sub-directories
For instance, I'd like to say "collect all the files in this one folder except for this one file and this one directory". Alternatively, I could accomplish the same thing if I could pick specific files, and then pick all of the sub-directories of that one directory (except the one I don't want).
Is any of that possible?
I wrote a custom django-admin command to enable a COLLECT_STATIC_IGNORE setting.
First create the following stucture in any app folder:
appname/
management/
__init__.py
commands/
__init__.py
_private.py
collectstatic.py
In collectstatic.py put:
from django.contrib.staticfiles.management.commands.collectstatic import Command
from django.conf import settings
class Command(Command):
def set_options(self, **options):
"""
Set instance variables based on an options dict
"""
self.interactive = options['interactive']
self.verbosity = int(options.get('verbosity', 1))
self.symlink = options['link']
self.clear = options['clear']
self.dry_run = options['dry_run']
ignore_patterns = options['ignore_patterns']
if options['use_default_ignore_patterns']:
ignore_patterns += ['CVS', '.*', '*~']
ignore_patterns += settings.COLLECT_STATIC_IGNORE # Added.
self.ignore_patterns = list(set(ignore_patterns))
self.post_process = options['post_process']
Or, even better, like #CantucciHQ suggested, use super:
class Command(Command):
def set_options(self, **options):
super(Command, self).set_options(**options)
self.ignore_patterns += settings.COLLECT_STATIC_IGNORE
self.ignore_patterns = list(set(self.ignore_patterns))
This overrides the set_options function from de build-in collectstatic command.
In settings.py add COLLECT_STATIC_IGNORE.
This example ignores scss files and all files in admin folders.
COLLECT_STATIC_IGNORE = ['*.scss', 'admin', ... ]
Then:
python manage.py collectstatic
Flags work so after adding something to COLLECT_STATIC_IGNORE you might want to use --clear to clear the existing files before trying to copy or link the original file.
python manage.py collectstatic --clear

Django makemessages ignore switch doesn't work for me

I have problems localizing a django-nonrel project, which is deployed to GAE. Because of GAE I have to put everything into my project folder, so it looks like something like this
project
+ django
+ dbindexer
+ registration
+ myapp
...
+ locale
+ templates
I have strings to localize in templates directory, and in the myapp directory.
When I run python manage.py makemessages -l en --ignore django\* from the project dir it crawl through all the directories of the project, including django, so I get a quite big po file. My strings from the templates are there, along with all of the strings from django directory.
after --ignore ( or just -i ) I tried to pu django django/* , but nothing changed.
Any ideas?
./manage.py help makemessages
-i PATTERN, --ignore=PATTERN
Ignore files or directories matching this glob-style
pattern. Use multiple times to ignore more.
I have just tested it, and this command successfully ignored my application:
./manage.py makemessages -l da -i "django*"
But beware that before you test it, you should delete the old .po file, as I think it will not automatically remove the translation lines from your previous makemessages execution.
The problem is with the pattern - maybe the shell was expanding it for you.
In general - it is good to avoid path separators (whether / or \) in the pattern.
If you need to always pass specific options to the makemessages command, you could consider your own wrapper, like this one, which I use myself:
from django.conf import settings
from django.core.management.base import BaseCommand
from django.core.management import call_command
class Command(BaseCommand):
help = "Scan i18n messages without going into externals."
def handle(self, *args, **options):
call_command('makemessages',
all=True,
extensions=['html', 'inc'],
ignore_patterns=['externals*'])
This saves you typing, and gives a common entry point for scanning messages across the project (your translator colleague will not destroy translations by missing out some parameter).
Don't delete the old .po file, once you have cleared it from the totally unwanted (i.e. - those from 'django' directory) messages. This allows gettext to recycle old unused messages, once they are used again (or simmilar ones, which will be marked as #, fuzzy.
Edit - as mt4x noted - the wrapper above doesn't allow for passing the options to the wrapped command. This is easy to fix:
from django.core.management import call_command
from django.core.management.commands.makemessages import (
Command as MakeMessagesCommand
)
class Command(MakeMessagesCommand):
help = "Scan i18n messages without going into externals."
def handle(self, *args, **options):
options['all'] = True
options['extensions'] = ['html', 'inc']
if 'ignore_patterns' not in options:
options['ignore_patterns'] = []
options['ignore_patterns'] += ['externals*']
call_command('makemessages', **options)
Thus - you can fix what needs to be fixed, and flex the rest.
And this needs not be blind override like above, but also some conditional edit of the parameters passed to the command - appending something to a list or only adding it when it's missing.

Empty catalog when internationalizing JavaScript code

I'm trying to set up Internationalization of JavaScript code in my Django application.
My Django app has a locale subdirectory with a properly generated djangojs.po file. The package definition is as follows:
# urls.py
js_info_dict = {
'packages': ('my_project',),
}
./manage.py makemessages worked well as the .po file contains all the to-be-translated strings but no JavaScript string ever gets translated on the website and the catalog is always empty.
I also had some problems with. This is how it works for me:
Add this to yr root urls.py:
js_info_dict = { 'domain': 'djangojs',
'packages': ('YOUR_PROJECT_NAME',), }
urlpatterns = patterns('',
#enable using translation strings in javascript
#source: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#module-django.views.i18n
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)
In JS files use:
var somevar = gettext('Text to translate');
To compile django translation files: In a shell/terminal run from the project root (where 'apps', 'settings', etc lie):
#for "normal django files" (.py, .html):
django-admin.py makemessages --locale=de
#for javascript files. source: http://stackoverflow.com/a/3571954/268125
django-admin.py makemessages -a -d djangojs --locale=de
#to compile the translation files to machine code
django-admin.py compilemessages --locale=de
i added my_project to INSTALLED APPS in settings.py and that seemed to do the trick

Load Multiple Fixtures at Once

Is there anyway to load one fixture and have it load multiple fixtures?
I'd ideally like to type:
python manage.py loaddata all_fixtures
And have that load all of the data instead of having to type everything. Is this possible?
Using $ python manage.py loaddata myfixtures/*.json would work as Bash will substitute the wildcard to a list of matching filenames.
I have multiple apps on the project directory and have each app with its 'fixtures' directory. So using some bash I can do:
python3 manage.py loaddata */fixtures/*.json
And that expands all of the json files inside of the fixtures directory on each app in my project. You can test it by simply doing:
ls */fixtures/*.json
Why not create a Makefile that pulls in all your fixtures? eg something like:
load_all_fixtures:
./manage.py loaddata path/to/fixtures/foo.json
./manage.py loaddata path/to/fixtures/bar.json
./manage.py loaddata path/to/fixtures/baz.json
And then at the shell prompt, run
make load_all_fixtures
(This kind of approach is also good for executing unit tests for certain apps only and ignoring others, if need be)
This thread shows up among the first results with a Google search "load data from all fixtures" and doesn't mention what IMO is the correct solution for this, ie the solution that allows you to load any fixtures you want without any wildcard tricks nor a single modification of the settings.py file (I also used to do it this way)
Just make your apps' fixtures directories flat (and not the usual Django scheme that e.g. goes app_name/templates/app_name/mytemplate.html), ie app_name/fixtures/myfixture.[json, yaml, xml]
Here's what the django doc says :
For example:
django-admin loaddata foo/bar/mydata.json
would search /fixtures/foo/bar/mydata.json for each installed application, /foo/bar/mydata.json for each directory in FIXTURE_DIRS, and the literal path foo/bar/mydata.json.
What that means is that if you have a fixtures/myfixture.json in all your app directories, you just have to run
./manage.py loaddata myfixture
to load all the fixtures that are located there within your project ... And that's it ! You can even restrict what apps you load fixtures from by using --app or --exclude arguments.
I'll mention that I use my fixtures only to populate my database while doing some development so I don't mind having a flat structure in my 'fixtures' directories ... But even if you use your fixtures for tests it seems like having a flat structure is the Django-esque way to go, and as
that answer suggests, you would reference the fixture from a specific app by just writing something like :
class MyTestCase(TestCase):
fixtures = ['app_name/fixtures/myfixture.json']
My command is this, simple. (django 1.6)
python manage.py loaddata a.json b.json c.json
If you want to have this work on linux and windows you simply could use this for loading all your json-Fixtures:
import os
files = os.listdir('path/to/my/fixtures')
def loaddata(file):
if os.path.splitext(file)[1] == '.json' and file != 'initial_data.json':
print file
os.system("python manage.py loaddata %s" % file)
map(loaddata, files)
Works for me with Django-admin version 3.1.4
python manage.py loaddata json_file_1 json_file_2
My folder structure is like this -
app_name_1
├──fixtures
├────json_file_1.json
├────json_file_2.json
app_name_2
├──fixtures
├────json_file_3.json
Manage.py loaddata will look automatically in certain places, so if you name your fixtures the same in each app, or put all your fixtures in the same folder it can be easy to load them all. If you have many different fixtures, and need a more complex naming schema, you can easily load all your fixtures using find with -exec
find . -name "*.json" -exec manage.py loaddata {} \;
As I state in this [question][2], I also have this in a fabfile. EDIT: use python manage.py if manage.py is not in your VE path.
If your fixtures are located into the same folder, you can simply ls and xargs: ls myfolder | xargs django-admin loaddata.
Example with this structure:
$ tree fixtures/
root_dir/fixtures/
├── 1_users.json
├── 2_articles.json
└── 3_addresses.json
$ ls -d fixtures/* | xargs django-admin loaddata
would do the same as:
$ django-admin loaddata 1_users.json
$ django-admin loaddata 2_articles.json
$ django-admin loaddata 3_addresses.json
After doing a bit of searching, I ended up writing this script. It searches through all directories named "fixtures" for .json files and runs a "python manage.py loaddata {fixture_name}.json". Sometimes ordering matters for foreign key constraints, so it leaves a fixture in the queue if the constraint cannot be resolved.
(Note: It requires the pip package simple_terminal that I wrote. And I set it up to be run by 'python manage.py runscript ', which requires django-extensions.)
# load_fixture.py
#
# A script that searches for all .json files in fixtures directories
# and loads them into the working database. This is meant to be run after
# dropping and recreating a database then running migrations.
#
# Usage: python manage.py runscript load_fixtures
from simple_terminal import Terminal
from django.core.management import call_command
from django.db.utils import IntegrityError
def load_fixture(fixture_location):
# runs command: python manage.py loaddata <fixture_location>
call_command('loaddata', fixture_location)
def run():
with Terminal() as t:
# get all .json files in a fixtures directory
fixture_locations = t.command(
'find . -name *.json | grep fixtures | grep -v env')
while fixture_locations:
# check that every iteration imports are occuring
errors = []
length_before = len(fixture_locations)
for fl in fixture_locations:
try:
# try to load fixture and if loaded remove it from the array
load_fixture(fl)
print("LOADED: {}".format(fl))
fixture_locations.remove(fl)
except IntegrityError as e:
errors.append(str(e))
# if import did not occur this iteration raise exception due to
# missing foreign key reference
length_after = len(fixture_locations)
if length_before == length_after:
raise IntegrityError(' '.join(errors))
This works well for me; it finds all files located in fixtures directories within the the src directory:
python manage.py loaddata \
$(ls -1 src/**/fixtures/* | tr '\n' '\0' | xargs -0 -n 1 basename | tr '\n' ' ')
python manage.py loaddata ./*/fixtures/*.json
This command will look for the folder fixture in all the directory and then it will pick up all the files with json extension and will install the fixtures.
This way you won't have to have just one folder for fixtures instead you can have fixtures on app level and in multiple apps.
It will work with the ideal folder structure like this -
app_name_1
├──fixtures
├────json_file_1.json
├────json_file_2.json
app_name_2
├──fixtures
├────json_file_3.json