• Stars
    star
    125
  • Rank 286,335 (Top 6 %)
  • Language
    Python
  • License
    BSD 2-Clause "Sim...
  • Created almost 15 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Convert Android string resources to gettext, and back.

android2po

Convert Android string resources to gettext .po files, and import them right back.

The goal is to remove as many syntax elements required by the Android string resource files when exporting, to present the text to translators in as easy a format as possible; and correctly writing everything back to Android on import while keeping the generated XML files easily readable as well (i.e. no unnecessary escaping).

Requirements

The following Python modules are required, and will mostly be auto-installed. See Installation below.

babel
http://babel.pocoo.org/
lxml
http://codespeak.net/lxml/
argparse
http://argparse.googlecode.com/

Since the .po files this script generates use contexts (msgctx), that's what you're gettext software will have to support as well.

Installation

To install the current release, you can simply do:

$ easy_install android2po

That's it!

If you want to install the current development version of android2po instead, get the source code, then run:

$ python setup.py install

setup.py should automatically install all the dependencies. Alternatively, you can also use pip if you prefer:

$ pip install -r requirements.pip

Usage

The basic idea is that:

  • values/strings.xml holds the reference strings in their original language (the gettext msgid fields).
  • The gettext .po files generated and updated by this script contain the reference version of the translations.
  • The values-XX/strings.xml files are fully generated based on your .po files, and should not be modified manually.

In addition to your authoritative strings.xml file, you will usually also want to keep your .po files in source control; The generated language-specific strings.xml files then contain no additional information, and do not need to be source controlled, though you are free to if you like.

The environment

To be able to run, the script necessarily needs to know about two filesystem locations: The directory where your Android resources are located, and the directory where the gettext .po files should be stored:

$ a2po COMMAND --android myproject/res --gettext myproject/locale

However, to simplify usage, the program will automatically try to detect the location of these folders, as follows:

  • It will search the directory hierarchy, starting with the your working directory, for a AndroidManifest.xml or .android2po file.
  • As soon as it finds either of those files, it will stop, and consider the it's location the project directory.
  • Unless explicitly overriden by you, it will place the .po files in a subdirectory ./locale of that project directory.
  • Only if a AndroidManifest.xml file is in the project directory will it assume that the Android resources are located in a subfolder named ./res.
  • If a .android2po file is in the project directory, it automatically will be loaded as a configuration file. See the section below on the format of the configuration file, and possible values.
  • The script automatically processes all the languages it can find. It will normally look at the existing .po files to determine the list of languages, with the exception of the init command, in which case the list of languages inside the Android resource directory will be used.

Initial setup

When switching to android2po, you will first want to create an initial export of your current translations.

$ a2po init

This will ignore any languages for which a .po file already exists.

For testing purposes, you may want to immediately import the generated files back in, to compare with what you originally had, and make sure the script was able to process your files correctly. At this point, make sure you have a backup, since your language-specific strings.xml files are going to be replaced (you are using source control, right?!):

$ a2po import
$ git diff --ignore-all-space res/values-XX/strings.xml

In the example above, git is used for source control. git provides a nice option to show a diff while ignoring whitespace changes, which will make it much easier to spot problems with the import. If you use a different tool, see if there is a comparable feature.

Hopefully, your translated XML files at this point hold the same information as before. The whitespace will probably have changed, comments will have been removed, and some strings may have changed visually (i.e. use different escaping). However, their meaning should not have changed. If it has, please report a bug.

Updating

After hacking on your code for a while, you have changed some strings (in your authoritative values/strings.xml file), and now you need to pass those on to your translators through your .po files.

Simply do:

$ a2po export

This will update your .po files with your changes.

Importing

Your translators have come back to you with their changes, and you want to include them in the next build. Simply do:

$ a2po import

This will fully regenerate your language-specific strings.xml based on the gettext .po files.

You can do this step manually, or add it to your build process.

Adding a new language

As noted above, android2po will automatically process all the languages it can find, based on the .po files that exist. To add a new language, simply run

$ a2po init {LANGUAGE CODES}

For example:

$ a2po init de fr

This will create both new .po and strings.xml files for German and French.

You are also free to simply create the appropriate strings.xml files yourself, and let

$ a2po init

initialize their proper .po counterparts (in case of the init command, the languages found in the Android resource directory will be processed).

Configuration file

A configuration file can be used to avoid manually specifying all the required options. The format of the file is simply a list of command line option, each specified on a line of it's own. For example:

--no-template
# Paths - don't specify --android, default location is used.
--gettext ../locale

As you can see, comments are supported by using #, and the mechanism to automatically try to detect the directories for .po files and Android strings.xml files is still in place if you don't specify locations explicitly.

The configuration file may be specified by using the --config option. Alternatively, if a .android2po file is found in the project directory, it will be used.

See --help for a list of possible configuration options. There's also an example configuration file in example.config that you can have a look at, or use as a template for your own.

Plurals support

<plurals> are supported, but merit some additional explanation.

Android's plural support is based on CLDR keywords like "one" and "many". The rules specifying which quantity n maps to which keyword are built into Android itself, by way of the CLDR database. It is important to understand that a keyword like "one" may be used for quantities other then 1.

In the gettext system, on the other hand, each catalog has the ability to define the plural rules it wants to use itself, via an expression like nplurals=2; plural=((n == 1) ? 0 : 1). The expression returns the index of the string to use for the quantity n.

android2po converts between those two system in the following way:

  • When writing .po files, it will generate a plural rule expression like above based on the CLDR data, custom-fit for the language in question. The result is a .po file that defines as many plural forms as required for the language, and your translation tool will ask for a different string for each plural form.
  • During import, it will generate a <plurals> tag with the correct quantity keywords based on it's knowledge (CLDR) about which such keywords the language supports.
  • The init command, having to convert existing <plurals> tags to gettext, will pick those quantity keywords the language supports, and ignore others (and display a warning in those cases).
  • The export command will ensure that the catalog uses the correct plural definition, but it otherwise does not have to deal with individual plural forms / quantities.

If this is confusing, consider the issue: Android lets you define a number of different quantity keywords for each <plurals> element, but ignores all keywords that are not supported by the language (see this erroneous bug report). gettext only allows you to define a fixed number of plural rules, as many as the language purports to require via the catalog's plural rule expression.

To cleanly convert between the two systems, we are forced to ignore keywords in an Android XML resource that are really not supported - but only if Android itself would also ignore them. So view this as essentially a validation feature.

A final note: plurals can be complex (and there are many languages) and the CLDR database is regularly updated. In French, whether 0 is treated as plural or singular possibly even depends on the dialect. As such, you may find that different plural rules for the same languages are in use in the wild. android2po uses the CLDR rules, but not necessarily the same version as Android does, and Android presumably will upgrade their CLDR version over time as well. I think the goal here would be to always make android2po use a reasonably recent version of the CLDR data, and accept that old Android versions with outdated plural information might not be able to correctly internationalize some plural strings into into those languages where the data is incorrect.

Further reading:

The CLDR plural system and rules
http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html http://cldr.unicode.org/index/cldr-spec/plural-rules
Plural information about various languages:
http://translate.sourceforge.net/wiki/l10n/pluralforms https://translations.launchpad.net/+languages https://developer.mozilla.org/en/Localization_and_Plurals

Understanding / Debugging the android2po

If something doesn't work as expected, it may be helpful to understand which files are processed how and when:

On init, android2po will take your language-neutral (English) values/strings.xml file and convert it to a .pot template.

Further on init, if there are existing values-{lang}/strings.xml files, it will take the strings from there, match them with the strings in the language-neutral values/strings.xml file, and generate .po files for these languages which already contain translations, in addition to the template. This is the only time that the values-{lang}/strings.xml files will be looked at and considered.

On export, android2po will take the language-neutral values/strings.xml file, generate a new .pot template, and then merge the new template into any existing .po catalogs, i.e. update the .po catalogs for each language with the changes. This is how gettext normally works (msgmerge). The values-{lang}/strings.xml files do not play a role here.

On 'import', android2po will only look at the .po catalogs for each language and generate values-{lang}/strings.xml files, without looking at anything else.

Notes

Initially based on:
http://code.google.com/p/openintents/source/browse/tools/Androidxml2po/androidxml2po.bash

Links of interest:

http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
GNU PO file format docs.
http://docs.oasis-open.org/xliff/v1.2/xliff-profile-po/xliff-profile-po-1.2.html
Explains the gettext format according to how xliff interprets it.
http://www.artfulbits.com/Android/aiLocalizer.aspx
App to localize Android xml string files directly. They seems to be involved with the Ukrainian translation of Android itself.
http://groups.google.com/group/android-platform/browse_thread/thread/a2626195205e8543

Notes that Google internally manages Android translations in their own system.

There is a converter from and to XLIFF in frameworks/base/tools/localize, which might be what they are using. It looks pretty decent too. Why isn't this promoted more?

https://launchpad.net/intltool
Converts to and from .po und "can be extended to support other types of XML" - sounds like something we could've used? It's Perl though, ugh.

More Repositories

1

webassets

Asset management for Python web development.
Python
917
star
2

flask-assets

Flask webassets integration.
Python
443
star
3

onkyo-eiscp

Control Onkyo A/V receivers over the network; usuable as a script, or as a Python library.
Python
442
star
4

k8s-snapshots

Automatic Volume Snapshots on Kubernetes.
Python
348
star
5

tarsnapper

tarsnap wrapper which expires backups using a gfs-scheme.
Python
220
star
6

android-autostarts

Tool to manage autostarts (broadcast receivers) on an Android device.
Java
195
star
7

python-glob2

Version of the glob module that supports recursion via **, and can capture patterns.
Python
123
star
8

django-assets

Django webassets integration.
Python
89
star
9

android-platform_sdk

To keep the deprecated apkbuilder tool alive should it break.
Java
64
star
10

gitolite-simple-mirror

post-receive hook to do make mirroring with gitolite easy.
Shell
54
star
11

ripple-python

Ripple-related routines in Python. Might become a proper client library later.
Python
49
star
12

py-androidbuild

Routines to build an Android app in Python and to get rid of Ant.
Python
46
star
13

sendtokindle

Grahical Send to Kindle Utility for Ubuntu
Python
45
star
14

dockerfiles

Some of my dockerfiles.
Dockerfile
43
star
15

ntfslink

A set of Windows Shell Extensions, providing extended functionality for creating and using hard links and junction points on NTFS file systems.
Pascal
42
star
16

linuxutils

Stuff I use on Linux.
Python
30
star
17

react-arrow

React component that renders a SVG arrow. Can point in any direction, different styles.
JavaScript
19
star
18

wasmbind

Nicer Python interface to Webassembly modules.
Python
17
star
19

elrc-maker

Tool to create Enhanced LRC files.
JavaScript
15
star
20

android-remote-stacktrace

Fork of android-remote-stacktrace to fit my personal needs.
Java
13
star
21

mfcobol-export

Exporter for Microfocus COBOL databases.
Python
13
star
22

python-closure

Closure compiler packaged for Python
Python
12
star
23

sonosweb

Import of purple.org/sonos
Perl
12
star
24

ripple-sepa-bridge

Python
12
star
25

emma

Import of "emma - extendable MySQL managing assistant"
Python
12
star
26

feedplatform

FeedPlatform implements the core functionality of a feed aggregator. It is supposed to be reusable and extremely flexible, mainly intended for integration with other applications.
Python
10
star
27

janos

Java-based Sonos Controller (SVN import from http://sourceforge.net/projects/janos/)
Java
10
star
28

django-tables

Deprecated in favor of django-tables2. This exists to keep old urls working.
Python
9
star
29

sorl-thumbnail

Python
9
star
30

xappy

Python
8
star
31

trio-asgi-server

Python
8
star
32

python-akismet

The voidspace.org.uk Akismet Python library with some fixes.
Python
8
star
33

python-multiprocessing

With patch for #18, to make it usable with celery.
7
star
34

synology-sipgate-sms

Send SMS notifications on Synology NAS via Sipgate.
Python
7
star
35

docker-gitolite

Shell
7
star
36

trio-protocol

Run asyncio protocols on top of trio
Python
7
star
37

jmap-python

A JMAP library in Python.
Python
6
star
38

influx-sansio

Python
6
star
39

ripple2go

Compiled version of the ripple client that runs on Github Pages. Fork the repository to get your own.
JavaScript
6
star
40

gevent-erlang-mode

Ad hoc, informally-specified, bug-ridden, slow implementations of some Erlang-style concepts in gevent.
Python
6
star
41

pysieved

The original branch seems to be broken with the git client in etch stable
Python
6
star
42

rsnapgraph

git import of rsnapgraph; Make it work with gnuplot 4.4
Perl
5
star
43

ripple-wcg-badges

HTML
5
star
44

openinghours.js

Query schema.org OpeningHoursSpecification in JavaScript.
TypeScript
5
star
45

allthekeeps

Explorer for the Keep and TBTC networks.
TypeScript
5
star
46

wifilock

Android App, ensures that the Wi-Fi radio will stay awake when the Phone goes to sleep.
Java
5
star
47

onkyo-eiscp-dotnet

Control Onkyo A/V receivers over the network; in C#, or on the command line. C# port of onkyo-eiscp for Python.
C#
4
star
48

python-smartinspect

A SmartInspect client library for Python (http://www.gurock.com/products/smartinspect/).
Python
4
star
49

ripple-federation-python

ripple/federation-php for Python.
Python
4
star
50

keepscore-android

Keep track of player scores during a card game.
Java
4
star
51

ripple-id

Webservice to identify ripple addresses
Python
4
star
52

ituneslp-tools

Tools to work with iTunes LP / iTunes Extras projects.
JavaScript
4
star
53

SynologyDownloadAssistant

Download directly to your synology diskstation
JavaScript
3
star
54

fretsonfire

Python
3
star
55

stgit

3
star
56

my-logcheck-db

My personal collection of custom logcheck rules, and a small script to apply them.
Python
3
star
57

reposync

Automate mirroring repositories, for example to github.
Python
3
star
58

php-languid

A statistical language guesser in PHP. Port of Maciej Ceglowski's Language::Guess.
PHP
3
star
59

corporeal

Clean, simple Windows Password Manager
Pascal
3
star
60

django-filebrowser

Fork of django-filebrowser that does not require django-grappelli
ActionScript
3
star
61

babel

Git import of python-babel
Python
3
star
62

jinja2utils

My personal collection of Jinja2 utilities.
Python
2
star
63

wsconfig

A tiny utility to automatize setting up a new workstation; linking config files and installing packages.
Python
2
star
64

protobuf

Google Protocol Buffers
C++
2
star
65

consul2vulcan

Go
2
star
66

islamic-patterns

TypeScript
2
star
67

track0

A web spider that makes sense (to me)
Python
2
star
68

gandi-python

Gandi CLI client.
Python
2
star
69

pyparsing

Another git import of pyparsing that won't be kept up to date.
Python
2
star
70

feedparser

Tracks feedparser SVN repository, plus some patches of mine.
Python
2
star
71

wormtail

Pascal
2
star
72

vandelay

A build tool.
Python
2
star
73

django-xappy

Bridges the Xappy Xapian interface with Django.
Python
2
star
74

jix

Port of the py.test fixture system to JavaScript
JavaScript
1
star
75

dvd-vr

Git import. Allow [label] to fallback to timestamp.
C
1
star
76

whatisripple.info

One-page explanation of the Ripple payment network, with images.
HTML
1
star
77

qdump

Very basic pastebin, Rails test app.
Ruby
1
star
78

import-all-ppa-keys

Copy of http://dev.firefly-it.de/repositories/show/lki
1
star
79

remember

remember, remember...
JavaScript
1
star
80

metadatad

Python
1
star
81

winutils

Stuff I use on Windows.
1
star
82

gajim-messaging-menu

Integrates Gajim with the Ubuntu Messaging Menu
Python
1
star
83

genericapi

Python
1
star
84

docker-deploy

Very much hacked together, and a work in progress for now.
Python
1
star
85

yyafl

Clone of git://git.stackfoundry.com/yyafl.git
Python
1
star
86

moneymoney-truelayer

TrueLayer extension for MoneyMoney.app
Lua
1
star
87

gwmap

Mapping Guild Wars with Google Maps.
JavaScript
1
star
88

textgrid-ui

TypeScript
1
star
89

descarty

A self-hostable Web History.
Python
1
star
90

confcollect

Configuration loader for 12factor Python apps, framework-agnostic.
Python
1
star
91

rippletxt

Python parser for ripple.txt
Python
1
star
92

py-snaptests

Python
1
star
93

worldofphoto-i18n

A World of Photo i18n files
Shell
1
star
94

mp3diags

SVN import of Mp3Diags trunk. Does not contain the full history, since /trunk did not always exist.
C++
1
star
95

localtodo

.gitignore local todo files, but sync them through Dropbox.
Python
1
star
96

react-navigation-views

Import of the npm package by the same name, which itself is an extract of the code from React-Native
JavaScript
1
star
97

hibiscus-cvsimport

There is a real git mirror now, see willuhn/hibiscus // git cvsimport for Hibiscus Jameica plugin from www.willuhn.de; to build, you still need a Jameica CVS checkout (see also http://blog.elsdoerfer.name/2011/07/14/building-hibiscus/).
Java
1
star