mirror of
https://github.com/boostorg/build.git
synced 2026-02-16 13:22:11 +00:00
222 lines
7.1 KiB
Plaintext
222 lines
7.1 KiB
Plaintext
# Copyright (C) Vladimir Prus 2003. Permission to copy, use, modify, sell and
|
|
# distribute this software is granted provided this copyright notice appears in
|
|
# all copies. This software is provided "as is" without express or implied
|
|
# warranty, and with no claim as to its suitability for any purpose.
|
|
|
|
# This module support GNU gettext internationalization utilities.
|
|
#
|
|
# It provides two main target rules: 'gettext.catalog', used for
|
|
# creating machine-readable catalogs from translations files, and
|
|
# 'gettext.update', used for update translation files from modified
|
|
# sources.
|
|
#
|
|
# To add i18n support to your application you should follow these
|
|
# steps.
|
|
#
|
|
# - Decide on a file name which will contain translations and
|
|
# what main target name will be used to update it. For example::
|
|
#
|
|
# gettext.update update-russian : russian.po a.cpp my_app ;
|
|
#
|
|
# - Create the initial translation file by running::
|
|
#
|
|
# bjam update-russian
|
|
#
|
|
# - Edit russian.po. For example, you might change fields like LastTranslator.
|
|
#
|
|
# - Create a main target for final message catalog::
|
|
#
|
|
# gettext.catalog russian : russian.po ;
|
|
#
|
|
# The machine-readable catalog will be updated whenever you update
|
|
# "russian.po". The "russian.po" file will be updated only on explicit
|
|
# request. When you're ready to update translations, you should
|
|
#
|
|
# - Run::
|
|
#
|
|
# bjam update-russian
|
|
#
|
|
# - Edit "russian.po" in appropriate editor.
|
|
#
|
|
# The next bjam run will convert "russian.po" into machine-readable form.
|
|
#
|
|
# By default, translations are marked by 'i18n' call. The 'gettext.keyword'
|
|
# feature can be used to alter this.
|
|
|
|
|
|
import targets ;
|
|
import property-set ;
|
|
import virtual-target ;
|
|
import "class" : new ;
|
|
import project ;
|
|
import type ;
|
|
import generators ;
|
|
import errors ;
|
|
import feature : feature ;
|
|
import toolset : flags ;
|
|
import regex ;
|
|
|
|
.path = "" ;
|
|
|
|
# Initializes the gettext module.
|
|
rule init ( path ? # Path where all tools are located. If not specified,
|
|
# they should be in PATH.
|
|
)
|
|
{
|
|
if $(.initialized) && $(.path) != $(path)
|
|
{
|
|
errors.error "Attempt to reconfigure with different path" ;
|
|
}
|
|
.initialized = true ;
|
|
if $(path)
|
|
{
|
|
.path = $(path)/ ;
|
|
}
|
|
}
|
|
|
|
# Creates a main target 'name', which, when updated, will cause
|
|
# file 'existing-translation' to be updated with translations
|
|
# extracted from 'sources'. It's possible to specify main target
|
|
# in sources --- it which case all target from dependency graph
|
|
# of those main targets will be scanned, provided they are of
|
|
# appropricate type. The 'gettext.types' feature can be used to
|
|
# control the types.
|
|
#
|
|
# The target will be updated only if explicitly requested on the
|
|
# command line.
|
|
rule update ( name : existing-translation sources + : requirements * )
|
|
{
|
|
local project = [ project.current ] ;
|
|
|
|
targets.main-target-alternative
|
|
[ new update-translations-class $(name) : $(project) :
|
|
$(existing-translation) $(sources)
|
|
: [ targets.main-target-requirements $(requirements) : $(project) ]
|
|
] ;
|
|
$(project).mark-target-as-explicit $(name) ;
|
|
}
|
|
|
|
|
|
# The human editable source, containing translation.
|
|
type.register gettext.PO : po ;
|
|
# The machine readable message catalog.
|
|
type.register gettext.catalog : mo : : main ;
|
|
# Intermediate type produce by extracting translations from
|
|
# sources.
|
|
type.register gettext.POT : pot ;
|
|
|
|
# Identifies the keyword that should be used when scanning sources.
|
|
# Default: i18n
|
|
feature gettext.keyword : : free ;
|
|
# Contains space-separated list of sources types which should be scanned.
|
|
# Default: "C CPP"
|
|
feature gettext.types : : free ;
|
|
|
|
generators.register-standard gettext.compile : gettext.PO : gettext.catalog ;
|
|
|
|
class update-translations-class : basic-target
|
|
{
|
|
import regex : split ;
|
|
|
|
rule __init__ ( name : project : sources * : requirements )
|
|
{
|
|
basic-target.__init__ $(name) : $(project) : $(sources) : $(requirements)
|
|
: $(default-build) ;
|
|
}
|
|
|
|
rule construct ( source-targets * : property-set )
|
|
{
|
|
local types = [ $(property-set).get <gettext.types> ] ;
|
|
types ?= "C CPP" ;
|
|
types = [ regex.split $(types) " " ] ;
|
|
property-set = [ property-set.empty ] ;
|
|
|
|
if ! $(.constructed)
|
|
{
|
|
# First deterime the list of sources that must be scanned to
|
|
# messages.
|
|
local all-sources ;
|
|
for local s in $(source-targets[2-])
|
|
{
|
|
all-sources += [ virtual-target.traverse $(s) : : include-sources ] ;
|
|
}
|
|
local right-sources ;
|
|
for local s in $(all-sources)
|
|
{
|
|
if [ $(s).type ] in $(types)
|
|
{
|
|
right-sources += $(s) ;
|
|
}
|
|
}
|
|
|
|
if $(right-sources)
|
|
{
|
|
local new-messages = [ new file-target $(self.name) : gettext.POT : $(self.project) ] ;
|
|
local extract =
|
|
[ new action $(new-messages) : $(right-sources) : gettext.extract ] ;
|
|
$(new-messages).action $(extract) ;
|
|
|
|
local r = [ new notfile-target $(self.name) : $(self.project) ] ;
|
|
local a = [ new action $(r) : $(source-targets[1]) $(new-messages)
|
|
: gettext.update-po-dispatch ] ;
|
|
$(r).action $(a) ;
|
|
.constructed = [ virtual-target.register $(r) ] ;
|
|
}
|
|
else
|
|
{
|
|
errors.error "No source could be scanned by gettext tools" ;
|
|
}
|
|
}
|
|
return $(.constructed) ;
|
|
}
|
|
}
|
|
|
|
flags gettext.extract KEYWORD <gettext.keyword> ;
|
|
actions extract
|
|
{
|
|
$(.path)xgettext -k$(KEYWORD:E=i18n) -o $(<) $(>)
|
|
}
|
|
|
|
# Does realy updating of po file. The tricky part is that
|
|
# we're actually updating one of the sources:
|
|
# $(<) is the NOTFILE target we're updating
|
|
# $(>[1]) is the PO file to be really updated.
|
|
# $(>[2]) is the PO file created from sources.
|
|
#
|
|
# When file to be updated does not exist (during the
|
|
# first run), we need to copy the file created from sources.
|
|
# In all other cases, we need to update the file.
|
|
rule update-po-dispatch
|
|
{
|
|
NOCARE $(>[1]) ;
|
|
gettext.create-po $(<) : $(>) ;
|
|
gettext.update-po $(<) : $(>) ;
|
|
_ on $(<) = " " ;
|
|
ok on $(<) = "" ;
|
|
EXISTING_PO on $(<) = $(>[1]) ;
|
|
}
|
|
|
|
# Due to fancy interaction of existing and updated, this rule
|
|
# can be called with with one source, in which case we copy
|
|
# the lonely source into EXISTING_PO, or with two sources,
|
|
# in which case the action body expands to nothing.
|
|
# I'd really like to have "missing" action modifier.
|
|
actions quietly existing updated create-po bind EXISTING_PO
|
|
{
|
|
cp$(_)"$(>[1])"$(_)"$(EXISTING_PO)"$($(>[2]:E=ok))
|
|
}
|
|
|
|
actions updated update-po bind EXISTING_PO
|
|
{
|
|
$(.path)msgmerge$(_)-U$(_)"$(EXISTING_PO)"$(_)"$(>[1])"
|
|
}
|
|
|
|
actions gettext.compile
|
|
{
|
|
$(.path)msgfmt -o $(<) $(>)
|
|
}
|
|
|
|
IMPORT $(__name__) : update : : gettext.update ;
|
|
|
|
|
|
|