<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://techbase.kde.org/skins/common/feed.css?0.2"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://techbase.kde.org/api.php?action=feedcontributions&amp;user=Ilic&amp;feedformat=atom</id>
		<title>KDE TechBase - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://techbase.kde.org/api.php?action=feedcontributions&amp;user=Ilic&amp;feedformat=atom"/>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Special:Contributions/Ilic"/>
		<updated>2013-05-25T21:54:42Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.20.2</generator>

	<entry>
		<id>http://techbase.kde.org/Localization/Tools/Lbundle_Check</id>
		<title>Localization/Tools/Lbundle Check</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Tools/Lbundle_Check"/>
				<updated>2013-02-02T16:05:04Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Removed extra empty lines.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Localization/Tools/Lbundle_Check --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
&lt;br /&gt;
section=[[Localization#Tools|Tools]]|&lt;br /&gt;
&lt;br /&gt;
name=Lbundle Checker|&lt;br /&gt;
&lt;br /&gt;
prereqs=[[Localization/Tools/Subversion|Subversion Ops]], [[Localization/Concepts/Non_Text_Resources|Localizing Non-Text Resources]]|&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== About ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; script checks and records the state of localized non-text resources organized in lbundles, allowing translators to track their relation to original resources. Its latest version can be found in &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; directory in the KDE repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; is in no way tied to KDE Translation Project, but can be used in any other environment. Only the instructions in this article are specifically about using &amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; in context of KDE TP.&lt;br /&gt;
&lt;br /&gt;
== Checking Out and Updating Sources ==&lt;br /&gt;
&lt;br /&gt;
To be able to track lbundle states, the translator (one of the coordinators) needs to have all the sources to which localized resources correspond. This is done by checking out once from the KDE repositories, and then regularly updating local checkouts. This is hard to do and maintain manually for selected sources only.&lt;br /&gt;
&lt;br /&gt;
Instead, the easiest is to check out and update all localization-relevant KDE sources, using a single command. This command is &amp;lt;tt&amp;gt;populate_source.sh&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;trunk/l10n-kde4/scripts/&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;branches/stable/l10n-kde4/scripts/&amp;lt;/tt&amp;gt; directories; each knows how to check out and update sources corresponding to the given translation branch (trunk or stable). It is run simply like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4&lt;br /&gt;
$ scripts/populate_source.sh&lt;br /&gt;
$ cd $KDEREPO/branches/stable/l10n-kde4&lt;br /&gt;
$ scripts/populate_source.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Running &amp;lt;tt&amp;gt;populate_source.sh&amp;lt;/tt&amp;gt; which will take quite some time for the first run, but subsequent runs will be much faster. After the run is complete, in current working directory there will be the &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; directory, with all the checkouts in it. The local directory tree should then look like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            source/&lt;br /&gt;
            ...&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                source/&lt;br /&gt;
                ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
At the moment of this writing, the &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; in trunk occupies ~10 GiB of disk space, and in stable ~6 GiB. While this is not little space, it should not be a significant problem given contemporary typical disk sizes.&lt;br /&gt;
&lt;br /&gt;
To quickly check out or update only one or few modules, their names can be given as arguments to &amp;lt;tt&amp;gt;populate_source.sh&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ scripts/populate_source.sh extragear-network_konversation kdegames_konquest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Module names for use as arguments can be found in &amp;lt;tt&amp;gt;source/modules&amp;lt;/tt&amp;gt; file. This file is generated anew whenever &amp;lt;tt&amp;gt;populate_source.sh&amp;lt;/tt&amp;gt; is run without arguments, i.e. to update everything.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; directory contains the &amp;lt;tt&amp;gt;repo/&amp;lt;/tt&amp;gt; subdirectory with actual local checkouts, and the &amp;lt;tt&amp;gt;link/&amp;lt;/tt&amp;gt; subdirectory, with links to checkout directories suitable for later operations. If the imaginary KDingus application is part of kdeutils top module, and is kept in a Git repository, it will be located like this in &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; in trunk:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
source/&lt;br /&gt;
    repo/&lt;br /&gt;
        git-unstable/&lt;br /&gt;
            kdeutils_kdingus&lt;br /&gt;
    link/&lt;br /&gt;
        kdeutils/&lt;br /&gt;
            kdingus --&amp;gt; ../../repo/kdeutils_kdingus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And if KDingus were in the Subversion repository:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
source/&lt;br /&gt;
    repo/&lt;br /&gt;
        trunk/&lt;br /&gt;
            KDE/&lt;br /&gt;
                kdeutils/&lt;br /&gt;
                    kdingus&lt;br /&gt;
    link/&lt;br /&gt;
        kdeutils/&lt;br /&gt;
            kdingus --&amp;gt; ../../repo/trunk/KDE/kdeutils/kdingus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that in both cases the link location stays the same, &amp;lt;tt&amp;gt;source/link/kdeutils/kdingus&amp;lt;/tt&amp;gt;. It will also stay the same in &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; of stable branch, where &amp;lt;tt&amp;gt;repo/&amp;lt;/tt&amp;gt; will instead contain &amp;lt;tt&amp;gt;git-stable/&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;branches/KDE/4.x/&amp;lt;/tt&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
There is a special case when a top module name represents Git repository of its own, such as &amp;lt;tt&amp;gt;kde-baseapps&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;kdepim&amp;lt;/tt&amp;gt;. The link then has to repeat the module name:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
source/&lt;br /&gt;
    link/&lt;br /&gt;
        kde-baseapps/&lt;br /&gt;
            kde-baseapps --&amp;gt; ../../repo/git-unstable/kde-baseapps&lt;br /&gt;
        kdepim/&lt;br /&gt;
            kdepim --&amp;gt; ../../repo/git-unstable/kdepim&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; is capable of gracefully handling this case as well.&lt;br /&gt;
&lt;br /&gt;
== Setup ==&lt;br /&gt;
&lt;br /&gt;
Before going through the setup examples, refresh the examples on organization of [[Localization/Concepts/Non_Text_Resources#Inside The Repository|lbundles in the repository]], which dealt with localizing the splash screen of the imaginary KDingus application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; can be used to track both out-of-source and in-source lbundles, but the setup needed for these two modes is somewhat different. The setup is explained for both modes, followed by the details of operation.&lt;br /&gt;
&lt;br /&gt;
=== Out-of-Source Lbundles ===&lt;br /&gt;
&lt;br /&gt;
When it was assumed that KDingus was part of kdeutils top module, its out-of-source lbundle for the language &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; was organized like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/trunk/l10n-kde4/aa/data/kdeutils/&lt;br /&gt;
    CMakeLists.txt&lt;br /&gt;
    kdingus/&lt;br /&gt;
        CMakeLists.txt&lt;br /&gt;
        pics/&lt;br /&gt;
            CMakeLists.txt&lt;br /&gt;
            l10n-spec&lt;br /&gt;
            l10n/&lt;br /&gt;
                aa/&lt;br /&gt;
                    kdingus-splash.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
except that this listing includes one new file, the &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt;. This is the setup file for tracking the lbundle, or rather, all lbundles on its level and beneath. The files outside of &amp;lt;tt&amp;gt;l10n/&amp;lt;/tt&amp;gt; subdirs are going to be called ''unbundled'', as they are not considered a part of the lbundle proper.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; files are composed of &amp;lt;tt&amp;gt;key = value&amp;lt;/tt&amp;gt; fields per line. For the example above the content of &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; would be:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# l10n-spec for KDingus' out-of-source bundle.&lt;br /&gt;
source-root = aa/data:source/link;^1&lt;br /&gt;
source-vcs = auto&lt;br /&gt;
bundle-vcs = auto&lt;br /&gt;
languages = aa&lt;br /&gt;
track-unbundled = CMakeLists.txt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields used in the example are:&lt;br /&gt;
&lt;br /&gt;
; source-root: the path to the root directory of the KDingus' sources. Every path-valued field can specify the path in several ways, which will be explained shortly. In this example, &amp;lt;tt&amp;gt;aa/data:source/link&amp;lt;/tt&amp;gt; means to construct the path to original file corresponding to localized file by replacing &amp;lt;tt&amp;gt;aa/data&amp;lt;/tt&amp;gt; in the absolute localized path with &amp;lt;tt&amp;gt;source/link&amp;lt;/tt&amp;gt;; if sources were [[#Checking Out and Updating Sources|checked out as explained earlier]], this will do exactly the right thing. Then there is the second path specification element separated by semi-colon, &amp;lt;tt&amp;gt;^1&amp;lt;/tt&amp;gt;, which means to assume that the original file may have one extra parent directory inserted somewhere in its path; this is used to cover the special case of top module name being equal to submodule name (e.g. &amp;lt;tt&amp;gt;source/link/kdepim/kdepim&amp;lt;/tt&amp;gt;). Note that this path specification nowhere refers to KDingus in particular: it should be applicable to all out-of-source bundles.&lt;br /&gt;
&lt;br /&gt;
; source-vcs, bundle-vcs: the version control systems used by the source code and the lbundle, respectively. These fields are needed so that &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; knows how to perform VCS operations when necessary, as well as to avoid trying to track version control bookkeeping files in the lbundle (e.g. &amp;lt;tt&amp;gt;.svn&amp;lt;/tt&amp;gt; subdirs for Subversiong). Currently the two known VCS are &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;git&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;auto&amp;lt;/tt&amp;gt; can be set to let &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; which one it is.&lt;br /&gt;
&lt;br /&gt;
; languages: space-delimited list of languages expected in &amp;lt;tt&amp;gt;l10n&amp;lt;/tt&amp;gt; subdirs. This is an optional field, which serves to check for naming errors with language subdirs. It may be left out, preventing such checks, but there is no reason to do so (especially for in-source bundles described below).&lt;br /&gt;
&lt;br /&gt;
; track-unbundled: space-delimited list of relative file paths, or pairs of file paths, of unbundled files which should be tracked nevertheless. In this example, &amp;lt;tt&amp;gt;CMakeLists.txt&amp;lt;/tt&amp;gt; should be tracked because the installation instructions for the lbundle may need to change when instructions for the original resources change. A pair of file paths, as two space-separated paths within parenthesis (e.g. &amp;lt;tt&amp;gt;(foo.txt bar.txt)&amp;lt;/tt&amp;gt;), can be given instead of a single file path when the local relative path needs to be different from that of the tracked original. A shell glob can be specified instead of a particular path (e.g. &amp;lt;tt&amp;gt;*.txt&amp;lt;/tt&amp;gt;), but only for single paths, not in pairs. Backslash serves as escape character, e.g. when the file name contains a space.&lt;br /&gt;
&lt;br /&gt;
Several other fields, not used in this example, are available:&lt;br /&gt;
&lt;br /&gt;
; ignore-unbundled: space-delimited list of relative file paths which are to be completely ignored by &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;. For an out-of-source bundle, a file which is unbundled should be either tracked too (using &amp;lt;tt&amp;gt;track-unbundled&amp;lt;/tt&amp;gt;) or ignored using this field, otherwise &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will complain about it. Shell globs also possible.&lt;br /&gt;
&lt;br /&gt;
; strict-state: a boolean value stating whether the tracking state is to be strictly imposed. Non-strict means that out-of-sync states between localized and original resources are recorded only in the track file, whereas strict state means that the localized files names will be changed too to reflect the out-of-sync state. More details in section on [[#Operation|operation]].&lt;br /&gt;
&lt;br /&gt;
; ignore-substr: space-delimited list of substrings to ignore in names of bundled files when determining their original counterparts. This is never needed in KDE, but in other environments some localized files may be handled differently than a plain substitute for the original file, based on a substring in their name (e.g. a localized image may be overlayed over the original, rather than replacing it).&lt;br /&gt;
&lt;br /&gt;
; track-by-subdir: by default there is only one tracking file per &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file (see [[#Operation|operation]] for tracking files); when this option is enabled (a boolean), there will be instead one tracking file per subdirectory (excluding &amp;lt;tt&amp;gt;l10n/&amp;lt;/tt&amp;gt; directories) starting from the level of &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file and below. Usefull when frequent moving of subdirectories within the repository is expected, and there are a lot of localized resources to track.&lt;br /&gt;
&lt;br /&gt;
Paths in path-valued fields (such as &amp;lt;tt&amp;gt;source-root&amp;lt;/tt&amp;gt;) can be specified in several modes. When it makes sense, to make up one path field value two or more modes can be chained, separated with semi-colon (&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt;). Each subsequent mode refers to the path established up to that point. Path specification modes are as follows:&lt;br /&gt;
&lt;br /&gt;
* Relative to a top root directory. This is represented by ordinary relative path. When running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;, the top root directory will have to be given through &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
* Relative to the directory of current lbundle (i.e. to the parent directory of &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file). This is done by prefixing a relative path with exclamation mark (&amp;lt;tt&amp;gt;!&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
* By replacing a part of the absolute path of the current lbundle directory. The replacement specification is of the form &amp;lt;tt&amp;gt;findstr:replstr&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* With allowed insertion of one or more consecutive parent directories when trying to find the path. This is given by &amp;lt;tt&amp;gt;^N&amp;lt;/tt&amp;gt;, where N is the maximum number of inserted parents. This mode cannot be the first in mode chain.&lt;br /&gt;
&lt;br /&gt;
The usual #-comments are allowed in &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; files, as well as line continuation by trailing backslashes (e.g. when several file paths are needed in &amp;lt;tt&amp;gt;track-unbundled&amp;lt;/tt&amp;gt; field).&lt;br /&gt;
&lt;br /&gt;
=== In-Source Lbundles ===&lt;br /&gt;
&lt;br /&gt;
If KDingus is an extragear application, its directory structure with the in-source lbundle having &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;bb&amp;lt;/tt&amp;gt; languages, and an &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file, would be this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/source/link/&lt;br /&gt;
    kdingus/&lt;br /&gt;
        CMakeLists.txt&lt;br /&gt;
        pics/&lt;br /&gt;
            CMakeLists.txt&lt;br /&gt;
            kdingus-splash.png&lt;br /&gt;
            l10n-spec&lt;br /&gt;
            l10n/&lt;br /&gt;
                aa/&lt;br /&gt;
                    kdingus-splash.png&lt;br /&gt;
                bb/&lt;br /&gt;
                    kdingus-splash.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The contents of &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; is simpler than that of out-of-source lbundles:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# l10n-spec for KDingus' in-source bundle.&lt;br /&gt;
source-vcs = auto&lt;br /&gt;
languages = aa bb&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the lbundle is kept together with the application, sharing same root directory and version control system, there is no need for the &amp;lt;tt&amp;gt;source-root&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;bundle-vcs&amp;lt;/tt&amp;gt; fields. In fact, the presence or lack of the &amp;lt;tt&amp;gt;source-root&amp;lt;/tt&amp;gt; field identifies the lbundle as out-of-source or in-source.&lt;br /&gt;
&lt;br /&gt;
Field &amp;lt;tt&amp;gt;track-unbundled&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;ignore-unbundled&amp;lt;/tt&amp;gt;) are not present either. All files which are unbundled are silently ignored. It is assumed that the KDingus' maintainer will modify and test installation instructions such as not to break installation of localized resources.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;languages&amp;lt;/tt&amp;gt; field could be omitted here as well, but for in-source lbundles it is even more important to keep tight check of wrongly named language subdirs.&lt;br /&gt;
&lt;br /&gt;
=== Greedy Bundling ===&lt;br /&gt;
&lt;br /&gt;
The default assumption behind lbundles is that only a small part of all resources need to be localized. It is upon the translator to spot the resources which need localization, make their localized versions, and add them to an lbundle where they will get tracked.&lt;br /&gt;
&lt;br /&gt;
When instead it would be better to track all of the original resources, lbundle tracking can be set to ''greedy'' mode: any original resource that does not have a localized counterpart yet will be tracked as missing. When a new original resource gets added, the translator will be notified of that by &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Fields in &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; used in greedy mode are as follows:&lt;br /&gt;
&lt;br /&gt;
; greedy-bundling: the option to engage greedy mode (a boolean value, set to true). Other fields controlling greedy bundling have no effect if this option is not set.&lt;br /&gt;
&lt;br /&gt;
; greedy-monolingual: states whether the lbundle is monolingual (boolean). This should make sense only for out-of-source bundles, where there may be one per language. Greedy mode needs this piece of information in order to know how to report and track missing localized files, as bundled (multilingual lbundle) or unbundled (monolingual).&lt;br /&gt;
&lt;br /&gt;
; greedy-from-level: if the lbundle covers a tree of original subdirectories, this field can be used to limit the greedy collection and reporting of missing files only to subdirectories at this level and below. 0 is the level of the &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file itself, 1 is one level below, etc.&lt;br /&gt;
&lt;br /&gt;
; greedy-only-started: normally all original resources missing in localization are reported as such (except the ignored ones), no matter where they reside in the original subdirectory tree covered by the lbundle. This field (a boolean) is used to limit greedy bundling only to those subdirectories already existing in the lbundle. Useful in several scenarios, e.g. when starting the resource localization to avoid being engulfed in listings of missing localized resources. Automatically enabled when &amp;lt;tt&amp;gt;track-by-subdir&amp;lt;/tt&amp;gt; is in effect.&lt;br /&gt;
&lt;br /&gt;
== Operation ==&lt;br /&gt;
&lt;br /&gt;
To check all lbundles for the language &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; in trunk, &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; can be run like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4/&lt;br /&gt;
$ lbundle-check.py aa/ # check all out-of-source&lt;br /&gt;
$ lbundle-check.py source/link/ -l aa # check all in-source&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If &amp;lt;tt&amp;gt;-l aa&amp;lt;/tt&amp;gt; option weren't specified in the second invocation, &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; would check ''all'' languages in &amp;lt;tt&amp;gt;source/link/&amp;lt;/tt&amp;gt; instead of only &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt;. In the first invocation &amp;lt;tt&amp;gt;-l aa&amp;lt;/tt&amp;gt; was omitted because out-of-source bundles contain only their own language, but it wouldn't cause any problem if it were present. Only particular lbundles can be checked by giving their subdirectories as arguments.&lt;br /&gt;
&lt;br /&gt;
So, what does &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; actually do, and what does it report? For brevity, let's limit to the out-of-source bundle for the KDingus as kdeutils application. After setting up the &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; for that case (as shown [[#Out-of-Source Lbundles|earlier]]), running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; for the first time will output:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4&lt;br /&gt;
$ lbundle-check.py aa/data/&lt;br /&gt;
!  aa/data/kdeutils/kdingus/pics/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
Added to tracking: 2&lt;br /&gt;
  aa/data/kdeutils/kdingus/pics/CMakeLists.txt&lt;br /&gt;
  aa/data/kdeutils/kdingus/pics/l10n/aa/kdingus-splash.png&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The file &amp;lt;tt&amp;gt;aa/data/kdeutils/kdingus/pics/l10n-track&amp;lt;/tt&amp;gt; will be created, with the following contents:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Do not edit manually, except to remove complete lines.&lt;br /&gt;
&lt;br /&gt;
# -&lt;br /&gt;
ok        ¦CMakeLists.txt¦  865f7...e926d  755260&lt;br /&gt;
&lt;br /&gt;
# aa&lt;br /&gt;
ok        ¦l10n/aa/kdingus-splash.png¦  37c4a7...8fe3a  755647&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For each &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file encountered, &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will create one of these &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; files. &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; file, in each non-comment, non-empty line, contains four fields, in order: the state of the localized resource against the original, the relative path to the bundled resource, the checksum of the ''original'' resource, and the VCS revision string of the original file which has this checksum.&lt;br /&gt;
&lt;br /&gt;
At this point, when &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file has been manually written, and &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; created by running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;, both should be added and committed to version control.&lt;br /&gt;
&lt;br /&gt;
So long as the original resource does not change, rerunning &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; in the same way will do nothing, as everything is in sync. Obviously, the original resources should be updated to the latest repository version prior to checking, and &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; can do that itself if started with &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ lbundle-check.py -u aa/data/&lt;br /&gt;
svn up .../kdeutils/kdingus/pics/CMakeLists.txt&lt;br /&gt;
At revision 762512.&lt;br /&gt;
svn up .../kdeutils/kdingus/pics/kdingus-splash.png&lt;br /&gt;
At revision 762512.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the original resource is modified, e.g. KDingus' splash screen is tweaked up, &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will report the following:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ lbundle-check.py aa/data/&lt;br /&gt;
!  aa/data/kdeutils/kdingus/pics/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
Newly fuzzied: 1&lt;br /&gt;
  aa/data/kdeutils/kdingus/pics/l10n/aa/kdingus-splash.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and its entry in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; will state:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
fuzzy     ¦l10n/aa/kdingus-splash.png¦  37c4a7...8fe3a  755647&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
i.e. only the status will have changed from &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt;. Now the translator has the information needed to compare what has changed in the original splash image: this entry still states the revision of the previous original file on which the localized file was based.&lt;br /&gt;
&lt;br /&gt;
If the original resource is renamed, moved, or deleted, the report will be slightly different:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ lbundle-check.py aa/data/&lt;br /&gt;
!  aa/data/kdeutils/kdingus/pics/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
Newly obsoleted: 1&lt;br /&gt;
  aa/data/kdeutils/kdingus/pics/l10n/aa/kdingus-splash.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and the entry in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
obsolete  ¦l10n/aa/kdingus-splash.png¦  37c4a7...8fe3a  755647&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now the translator must find out, using the old revision string, what exactly happened to the original resource, and do the same for the localized resource.&lt;br /&gt;
&lt;br /&gt;
When the fuzzy or obsolete state has been resolved, localized resource updated to reflect changes in the original, it should be recorded as such. To do this, the entry for the resource is first manually deleted from &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; file (the whole line is removed), and then &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; is rerun. This will recreate the entry with a fresh &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;strict-state&amp;lt;/tt&amp;gt; field has been set to true in &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt;, then not only the state of the entry in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; is changed, but the tracked file itself is renamed to contain &amp;lt;tt&amp;gt;~fuzzy&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;~obsolete&amp;lt;/tt&amp;gt; marker just before the extension. This mode is called strict because unless the out-of-sync state is corrected, the file is &amp;quot;misnamed&amp;quot; from the point of view of the runtime system, and will not be used instead of the original (it may even not get installed, depending on the exact installation instructions).&lt;br /&gt;
&lt;br /&gt;
To resolve the fuzzy or obsolete state in strict mode, it is not necessary to manually remove the entry from &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt;. Instead, it is enough to put an updated version of the file (without the state maker in its name) next to the out-of-sync version, and rerun &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;. It will remove the old version and update the entry in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt;. (The renaming/removal are version control aware, i.e. proper version control commands will be used for these operations if &amp;lt;tt&amp;gt;*-vcs&amp;lt;/tt&amp;gt; fields have been set in the spec file.)&lt;br /&gt;
&lt;br /&gt;
When [[#Greedy Bundling|greedy bundling]] is engaged, each original file which doesn't have a localized counterpart will be reported in the track file (either as bundled or unbundled, depending on &amp;lt;tt&amp;gt;greedy-monolingual&amp;lt;/tt&amp;gt; option), with it's state set to &amp;lt;tt&amp;gt;missing&amp;lt;/tt&amp;gt; (except for the ignored files, given by the &amp;lt;tt&amp;gt;ignore-unbundled&amp;lt;/tt&amp;gt; option). When the localized file is placed at the appropriate location, next run of &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will change the state to &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Special Case: Tracking KDE Documentation Resources ==&lt;br /&gt;
&lt;br /&gt;
{{note|This section should be mostly self-contained, providing all the information needed for resource tracking in documentation, for two reasons. Firstly, it can be reasonably assumed that many more KDE translation teams will want to track localized documentation resources, rather than some other, special resources. Secondly, structure of documentation resources is significantly different from that of normal lbundles, so having separate examples helps.}}&lt;br /&gt;
&lt;br /&gt;
KDE documentation consists of two types of resources: the text, which is provided through Docbook files, and other data, mostly screenshots from applications. The text from original Docbook files is extracted into PO templates, translated through PO files, and localized Docbook files created out of them. Thus, when the original text changes, translators are automatically made aware of that through new and fuzzy entries in PO files. This is not so for screenshots. When an original screenshot changes, gets removed or added, translators get no notice of it. However, the tracking mechanism provided by &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; can be used to help rectify this.&lt;br /&gt;
&lt;br /&gt;
Localized resources of KDE documentation are not really organized into lbundles; their organization far precedes the lbundling system. Still, every language's documentation directory (&amp;lt;tt&amp;gt;aa/docs/&amp;lt;/tt&amp;gt;) can be understood as one ''greedy monolingual'' lbundle composed solely of ''unbundled'' resources, and as such tracked by the &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;. Docbook files are excluded from tracking, as they are kept up-to-date through Docbook-PO-Docbook roundtrip. At the moment, tracking is set up and operated by the coordinator of each language team that wants to have it.&lt;br /&gt;
&lt;br /&gt;
To set up tracking, the coordinator of the language &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; should maintain the local checkout of several modules, with same structure as KDE repository, as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            templates/&lt;br /&gt;
            documentation/&lt;br /&gt;
            aa/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            scripts/&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                templates/&lt;br /&gt;
                documentation/&lt;br /&gt;
                aa/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In fact, it is a good idea anyway for a language coordinator to maintain such a checkout (the total space requirement is between 500 MB and 1 GB).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;documentation/&amp;lt;/tt&amp;gt; subdirectory is not actually found in the Subversion repository; it is created and periodically updated by running the &amp;lt;tt&amp;gt;scripts/populate_documentation.sh&amp;lt;/tt&amp;gt; script, in stable and trunk:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4&lt;br /&gt;
$ scripts/populate_documentation.sh&lt;br /&gt;
$ cd $KDEREPO/branches/stable/l10n-kde4&lt;br /&gt;
$ scripts/populate_documentation.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;populate_documentation.sh&amp;lt;/tt&amp;gt; from trunk will get exactly the documentation modules' branches translated as trunk, and &amp;lt;tt&amp;gt;populate_documentation.sh&amp;lt;/tt&amp;gt; from stable those translated as stable.&lt;br /&gt;
&lt;br /&gt;
After this file structure is established, create the files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/trunk/l10n-kde4/aa/docs/l10n-spec&lt;br /&gt;
$KDEREPO/branches/stable/l10n-kde4/aa/docs/l10n-spec&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
both with the following, branch-independent content:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
source-root = aa/docs:documentation&lt;br /&gt;
source-vcs = file&lt;br /&gt;
bundle-vcs = auto&lt;br /&gt;
track-by-subdir = yes&lt;br /&gt;
&lt;br /&gt;
greedy-bundling = yes&lt;br /&gt;
greedy-monolingual = yes&lt;br /&gt;
greedy-from-level = 2&lt;br /&gt;
&lt;br /&gt;
ignore-unbundled = \&lt;br /&gt;
    CMakeLists.txt */CMakeLists.txt */*/CMakeLists.txt */*/*/CMakeLists.txt \&lt;br /&gt;
    */*/*.docbook */*/*/*.docbook \&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the language code &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;aa/docs:...&amp;lt;/tt&amp;gt; at the top, and modify it accordingly.&lt;br /&gt;
&lt;br /&gt;
Finally, run the &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; on the documentation directories of your language, e.g. for the trunk:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ lbundle-check.py $KDEREPO/trunk/l10n-kde4/aa/docs/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
After some time, depending on how many localized screenshots you have made already, a whole lot of output may appear -- listing of files having been added to tracking. More importantly, each subdirectory in &amp;lt;tt&amp;gt;aa/docs/&amp;lt;/tt&amp;gt; which has (or could have) at least one localized screenshot, will get a ''tracking file'', named &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt;. Tracking files will be automatically added to version control as well, so you can commit &amp;lt;tt&amp;gt;aa/docs/&amp;lt;/tt&amp;gt; right away.&lt;br /&gt;
&lt;br /&gt;
What does a tracking file look like? For example, the original documentation for KRuler contains these files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
documentation/kdegraphics/kruler/&lt;br /&gt;
    CMakeLists.txt&lt;br /&gt;
    index.docbook&lt;br /&gt;
    kruler.png&lt;br /&gt;
    kruler-settings.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Assume that your language's localized documentation contains:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
aa/docs/kdegraphics/kruler/&lt;br /&gt;
    CMakeLists.txt&lt;br /&gt;
    index.docbook&lt;br /&gt;
    kruler.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
that is, the localized variant of &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt; is missing. Then, the &amp;lt;tt&amp;gt;aa/docs/kdegraphics/kruler/l10n-track&amp;lt;/tt&amp;gt; that got created will have this contents:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Do not edit manually, except to remove complete lines.&lt;br /&gt;
&lt;br /&gt;
ok        ¦kruler.png¦  58ba...872a  58ba...872a&lt;br /&gt;
missing   ¦kruler-settings.png¦  4dd2...5ebf  4dd2...5ebf&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Each line contains four pieces of data: the sync state and the name of the localized file, and the twice repeated checksum of the ''original'' file. (Instead of the second checksum normally there would be the repository revision of the original file, but &amp;lt;tt&amp;gt;populate_documentation.sh&amp;lt;/tt&amp;gt; does not make proper repository checkouts). Since this is the first run of &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;, it assumed that the present localized &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; is up-to-date (more later on this assumption), and so its state is set to &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;. For &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt;, which is not there in the localized directory, the state is set as &amp;lt;tt&amp;gt;missing&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The day-to-day operation constitutes running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; from time to time, in the same way as the first time. When a new original screenshot is added, the appropriate &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; file will get a new &amp;lt;tt&amp;gt;missing&amp;lt;/tt&amp;gt; entry. When a localized screenshot is produced and put into correct place, the &amp;lt;tt&amp;gt;missing&amp;lt;/tt&amp;gt; state will change into &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4/&lt;br /&gt;
$ (...put localized kruler-settings.png into aa/docs/...)&lt;br /&gt;
$ lbundle-check.py aa/docs/&lt;br /&gt;
A  (bin)  aa/docs/kdegraphics/kruler/kruler-settings.png&lt;br /&gt;
M      aa/docs/kdegraphics/kruler/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
New 'ok': 1&lt;br /&gt;
  aa/docs/kdegraphics/kruler/kruler-settings.png (...)&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that version control operations are done automatically too.&lt;br /&gt;
&lt;br /&gt;
Assume now that, in the above example, after some time the original &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; is modified, and the original &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt; is removed. Then, running the tracker produces:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4/&lt;br /&gt;
$ lbundle-check.py aa/docs/&lt;br /&gt;
M      aa/docs/kdegraphics/kruler/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
New 'fuzzy': 1&lt;br /&gt;
  aa/docs/kdegraphics/kruler/kruler.png (...)&lt;br /&gt;
New 'obsolete': 1&lt;br /&gt;
  aa/docs/kdegraphics/kruler/kruler-settings.png (...)&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and the content of tracking file becomes:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Do not edit manually, except to remove complete lines.&lt;br /&gt;
&lt;br /&gt;
fuzzy     ¦kruler.png¦  58ba...872a  3d94...2c6f&lt;br /&gt;
obsolete  ¦kruler-settings.png¦  4dd2...5ebf  ae31...b561&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now the translator should remove the obsoleted localized &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt;, and check the new original &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; to see what to do with the localized &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt;. When the fuzzy state of localized &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; is resolved -- by making a new localized screenshot, or deciding that the existing screenshot is still fine -- the translator edits &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; to remove its line. After rerunning &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;, new localized &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; will be picked up with the default &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt; state, and the line for &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt; will be automatically removed.&lt;br /&gt;
&lt;br /&gt;
{{warning|As the top comment in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; files states, never manually edit these files except to unfuzzy entries by removing their complete lines. E.g. do not change the state manually, which would leave the original checksum and revision wrong.}}&lt;br /&gt;
&lt;br /&gt;
Instead of running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; on the whole &amp;lt;tt&amp;gt;aa/docs/&amp;lt;/tt&amp;gt; tree, it can also be run on any given subdirectory of it. It will then check only the files in that subdirectory and below.&lt;br /&gt;
&lt;br /&gt;
=== Many Localized Screenshots at Start ===&lt;br /&gt;
&lt;br /&gt;
There is a small issue with the fact that &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will set state of new files to &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;. If the documentation directory already has a lot of screenshots with unknown state compared to the original, it is not appropriate to consider them &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;, but &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt;. To have this, after the ''first'' run of &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; simply postprocess all &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ find aa/docs/ -iname l10n-track | xargs perl -pi -e 's/^ok   /fuzzy/'&lt;br /&gt;
$ find aa/docs/ -iname l10n-track | xargs perl -pi -e 's/[0-9a-z]{32}/0/'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
(The second command replaces the original checksums with all zeros, as otherwise the files would be again recognized as up-to-date on the next run.) Afterwards, in due time, existing screenshots can be inspected one by one, and their fuzzy state removed as explained previously.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Tools/Lbundle_Check</id>
		<title>Localization/Tools/Lbundle Check</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Tools/Lbundle_Check"/>
				<updated>2013-02-02T16:04:05Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Updated to new Git/Subversion state of affairs.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Localization/Tools/Lbundle_Check --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
&lt;br /&gt;
section=[[Localization#Tools|Tools]]|&lt;br /&gt;
&lt;br /&gt;
name=Lbundle Checker|&lt;br /&gt;
&lt;br /&gt;
prereqs=[[Localization/Tools/Subversion|Subversion Ops]], [[Localization/Concepts/Non_Text_Resources|Localizing Non-Text Resources]]|&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== About ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; script checks and records the state of localized non-text resources organized in lbundles, allowing translators to track their relation to original resources. Its latest version can be found in &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; directory in the KDE repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; is in no way tied to KDE Translation Project, but can be used in any other environment. Only the instructions in this article are specifically about using &amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; in context of KDE TP.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Checking Out and Updating Sources ==&lt;br /&gt;
&lt;br /&gt;
To be able to track lbundle states, the translator (one of the coordinators) needs to have all the sources to which localized resources correspond. This is done by checking out once from the KDE repositories, and then regularly updating local checkouts. This is hard to do and maintain manually for selected sources only.&lt;br /&gt;
&lt;br /&gt;
Instead, the easiest is to check out and update all localization-relevant KDE sources, using a single command. This command is &amp;lt;tt&amp;gt;populate_source.sh&amp;lt;/tt&amp;gt;, found in &amp;lt;tt&amp;gt;trunk/l10n-kde4/scripts/&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;branches/stable/l10n-kde4/scripts/&amp;lt;/tt&amp;gt; directories; each knows how to check out and update sources corresponding to the given translation branch (trunk or stable). It is run simply like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4&lt;br /&gt;
$ scripts/populate_source.sh&lt;br /&gt;
$ cd $KDEREPO/branches/stable/l10n-kde4&lt;br /&gt;
$ scripts/populate_source.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Running &amp;lt;tt&amp;gt;populate_source.sh&amp;lt;/tt&amp;gt; which will take quite some time for the first run, but subsequent runs will be much faster. After the run is complete, in current working directory there will be the &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; directory, with all the checkouts in it. The local directory tree should then look like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            source/&lt;br /&gt;
            ...&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                source/&lt;br /&gt;
                ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
At the moment of this writing, the &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; in trunk occupies ~10 GiB of disk space, and in stable ~6 GiB. While this is not little space, it should not be a significant problem given contemporary typical disk sizes.&lt;br /&gt;
&lt;br /&gt;
To quickly check out or update only one or few modules, their names can be given as arguments to &amp;lt;tt&amp;gt;populate_source.sh&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ scripts/populate_source.sh extragear-network_konversation kdegames_konquest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Module names for use as arguments can be found in &amp;lt;tt&amp;gt;source/modules&amp;lt;/tt&amp;gt; file. This file is generated anew whenever &amp;lt;tt&amp;gt;populate_source.sh&amp;lt;/tt&amp;gt; is run without arguments, i.e. to update everything.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; directory contains the &amp;lt;tt&amp;gt;repo/&amp;lt;/tt&amp;gt; subdirectory with actual local checkouts, and the &amp;lt;tt&amp;gt;link/&amp;lt;/tt&amp;gt; subdirectory, with links to checkout directories suitable for later operations. If the imaginary KDingus application is part of kdeutils top module, and is kept in a Git repository, it will be located like this in &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; in trunk:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
source/&lt;br /&gt;
    repo/&lt;br /&gt;
        git-unstable/&lt;br /&gt;
            kdeutils_kdingus&lt;br /&gt;
    link/&lt;br /&gt;
        kdeutils/&lt;br /&gt;
            kdingus --&amp;gt; ../../repo/kdeutils_kdingus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And if KDingus were in the Subversion repository:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
source/&lt;br /&gt;
    repo/&lt;br /&gt;
        trunk/&lt;br /&gt;
            KDE/&lt;br /&gt;
                kdeutils/&lt;br /&gt;
                    kdingus&lt;br /&gt;
    link/&lt;br /&gt;
        kdeutils/&lt;br /&gt;
            kdingus --&amp;gt; ../../repo/trunk/KDE/kdeutils/kdingus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that in both cases the link location stays the same, &amp;lt;tt&amp;gt;source/link/kdeutils/kdingus&amp;lt;/tt&amp;gt;. It will also stay the same in &amp;lt;tt&amp;gt;source/&amp;lt;/tt&amp;gt; of stable branch, where &amp;lt;tt&amp;gt;repo/&amp;lt;/tt&amp;gt; will instead contain &amp;lt;tt&amp;gt;git-stable/&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;branches/KDE/4.x/&amp;lt;/tt&amp;gt;, etc.&lt;br /&gt;
&lt;br /&gt;
There is a special case when a top module name represents Git repository of its own, such as &amp;lt;tt&amp;gt;kde-baseapps&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;kdepim&amp;lt;/tt&amp;gt;. The link then has to repeat the module name:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
source/&lt;br /&gt;
    link/&lt;br /&gt;
        kde-baseapps/&lt;br /&gt;
            kde-baseapps --&amp;gt; ../../repo/git-unstable/kde-baseapps&lt;br /&gt;
        kdepim/&lt;br /&gt;
            kdepim --&amp;gt; ../../repo/git-unstable/kdepim&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; is capable of gracefully handling this case as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Setup ==&lt;br /&gt;
&lt;br /&gt;
Before going through the setup examples, refresh the examples on organization of [[Localization/Concepts/Non_Text_Resources#Inside The Repository|lbundles in the repository]], which dealt with localizing the splash screen of the imaginary KDingus application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;lbundle_check.py&amp;lt;/tt&amp;gt; can be used to track both out-of-source and in-source lbundles, but the setup needed for these two modes is somewhat different. The setup is explained for both modes, followed by the details of operation.&lt;br /&gt;
&lt;br /&gt;
=== Out-of-Source Lbundles ===&lt;br /&gt;
&lt;br /&gt;
When it was assumed that KDingus was part of kdeutils top module, its out-of-source lbundle for the language &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; was organized like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/trunk/l10n-kde4/aa/data/kdeutils/&lt;br /&gt;
    CMakeLists.txt&lt;br /&gt;
    kdingus/&lt;br /&gt;
        CMakeLists.txt&lt;br /&gt;
        pics/&lt;br /&gt;
            CMakeLists.txt&lt;br /&gt;
            l10n-spec&lt;br /&gt;
            l10n/&lt;br /&gt;
                aa/&lt;br /&gt;
                    kdingus-splash.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
except that this listing includes one new file, the &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt;. This is the setup file for tracking the lbundle, or rather, all lbundles on its level and beneath. The files outside of &amp;lt;tt&amp;gt;l10n/&amp;lt;/tt&amp;gt; subdirs are going to be called ''unbundled'', as they are not considered a part of the lbundle proper.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; files are composed of &amp;lt;tt&amp;gt;key = value&amp;lt;/tt&amp;gt; fields per line. For the example above the content of &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; would be:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# l10n-spec for KDingus' out-of-source bundle.&lt;br /&gt;
source-root = aa/data:source/link;^1&lt;br /&gt;
source-vcs = auto&lt;br /&gt;
bundle-vcs = auto&lt;br /&gt;
languages = aa&lt;br /&gt;
track-unbundled = CMakeLists.txt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields used in the example are:&lt;br /&gt;
&lt;br /&gt;
; source-root: the path to the root directory of the KDingus' sources. Every path-valued field can specify the path in several ways, which will be explained shortly. In this example, &amp;lt;tt&amp;gt;aa/data:source/link&amp;lt;/tt&amp;gt; means to construct the path to original file corresponding to localized file by replacing &amp;lt;tt&amp;gt;aa/data&amp;lt;/tt&amp;gt; in the absolute localized path with &amp;lt;tt&amp;gt;source/link&amp;lt;/tt&amp;gt;; if sources were [[#Checking Out and Updating Sources|checked out as explained earlier]], this will do exactly the right thing. Then there is the second path specification element separated by semi-colon, &amp;lt;tt&amp;gt;^1&amp;lt;/tt&amp;gt;, which means to assume that the original file may have one extra parent directory inserted somewhere in its path; this is used to cover the special case of top module name being equal to submodule name (e.g. &amp;lt;tt&amp;gt;source/link/kdepim/kdepim&amp;lt;/tt&amp;gt;). Note that this path specification nowhere refers to KDingus in particular: it should be applicable to all out-of-source bundles.&lt;br /&gt;
&lt;br /&gt;
; source-vcs, bundle-vcs: the version control systems used by the source code and the lbundle, respectively. These fields are needed so that &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; knows how to perform VCS operations when necessary, as well as to avoid trying to track version control bookkeeping files in the lbundle (e.g. &amp;lt;tt&amp;gt;.svn&amp;lt;/tt&amp;gt; subdirs for Subversiong). Currently the two known VCS are &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;git&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;auto&amp;lt;/tt&amp;gt; can be set to let &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; which one it is.&lt;br /&gt;
&lt;br /&gt;
; languages: space-delimited list of languages expected in &amp;lt;tt&amp;gt;l10n&amp;lt;/tt&amp;gt; subdirs. This is an optional field, which serves to check for naming errors with language subdirs. It may be left out, preventing such checks, but there is no reason to do so (especially for in-source bundles described below).&lt;br /&gt;
&lt;br /&gt;
; track-unbundled: space-delimited list of relative file paths, or pairs of file paths, of unbundled files which should be tracked nevertheless. In this example, &amp;lt;tt&amp;gt;CMakeLists.txt&amp;lt;/tt&amp;gt; should be tracked because the installation instructions for the lbundle may need to change when instructions for the original resources change. A pair of file paths, as two space-separated paths within parenthesis (e.g. &amp;lt;tt&amp;gt;(foo.txt bar.txt)&amp;lt;/tt&amp;gt;), can be given instead of a single file path when the local relative path needs to be different from that of the tracked original. A shell glob can be specified instead of a particular path (e.g. &amp;lt;tt&amp;gt;*.txt&amp;lt;/tt&amp;gt;), but only for single paths, not in pairs. Backslash serves as escape character, e.g. when the file name contains a space.&lt;br /&gt;
&lt;br /&gt;
Several other fields, not used in this example, are available:&lt;br /&gt;
&lt;br /&gt;
; ignore-unbundled: space-delimited list of relative file paths which are to be completely ignored by &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;. For an out-of-source bundle, a file which is unbundled should be either tracked too (using &amp;lt;tt&amp;gt;track-unbundled&amp;lt;/tt&amp;gt;) or ignored using this field, otherwise &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will complain about it. Shell globs also possible.&lt;br /&gt;
&lt;br /&gt;
; strict-state: a boolean value stating whether the tracking state is to be strictly imposed. Non-strict means that out-of-sync states between localized and original resources are recorded only in the track file, whereas strict state means that the localized files names will be changed too to reflect the out-of-sync state. More details in section on [[#Operation|operation]].&lt;br /&gt;
&lt;br /&gt;
; ignore-substr: space-delimited list of substrings to ignore in names of bundled files when determining their original counterparts. This is never needed in KDE, but in other environments some localized files may be handled differently than a plain substitute for the original file, based on a substring in their name (e.g. a localized image may be overlayed over the original, rather than replacing it).&lt;br /&gt;
&lt;br /&gt;
; track-by-subdir: by default there is only one tracking file per &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file (see [[#Operation|operation]] for tracking files); when this option is enabled (a boolean), there will be instead one tracking file per subdirectory (excluding &amp;lt;tt&amp;gt;l10n/&amp;lt;/tt&amp;gt; directories) starting from the level of &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file and below. Usefull when frequent moving of subdirectories within the repository is expected, and there are a lot of localized resources to track.&lt;br /&gt;
&lt;br /&gt;
Paths in path-valued fields (such as &amp;lt;tt&amp;gt;source-root&amp;lt;/tt&amp;gt;) can be specified in several modes. When it makes sense, to make up one path field value two or more modes can be chained, separated with semi-colon (&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt;). Each subsequent mode refers to the path established up to that point. Path specification modes are as follows:&lt;br /&gt;
&lt;br /&gt;
* Relative to a top root directory. This is represented by ordinary relative path. When running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;, the top root directory will have to be given through &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
* Relative to the directory of current lbundle (i.e. to the parent directory of &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file). This is done by prefixing a relative path with exclamation mark (&amp;lt;tt&amp;gt;!&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
* By replacing a part of the absolute path of the current lbundle directory. The replacement specification is of the form &amp;lt;tt&amp;gt;findstr:replstr&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* With allowed insertion of one or more consecutive parent directories when trying to find the path. This is given by &amp;lt;tt&amp;gt;^N&amp;lt;/tt&amp;gt;, where N is the maximum number of inserted parents. This mode cannot be the first in mode chain.&lt;br /&gt;
&lt;br /&gt;
The usual #-comments are allowed in &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; files, as well as line continuation by trailing backslashes (e.g. when several file paths are needed in &amp;lt;tt&amp;gt;track-unbundled&amp;lt;/tt&amp;gt; field).&lt;br /&gt;
&lt;br /&gt;
=== In-Source Lbundles ===&lt;br /&gt;
&lt;br /&gt;
If KDingus is an extragear application, its directory structure with the in-source lbundle having &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;bb&amp;lt;/tt&amp;gt; languages, and an &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file, would be this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/source/link/&lt;br /&gt;
    kdingus/&lt;br /&gt;
        CMakeLists.txt&lt;br /&gt;
        pics/&lt;br /&gt;
            CMakeLists.txt&lt;br /&gt;
            kdingus-splash.png&lt;br /&gt;
            l10n-spec&lt;br /&gt;
            l10n/&lt;br /&gt;
                aa/&lt;br /&gt;
                    kdingus-splash.png&lt;br /&gt;
                bb/&lt;br /&gt;
                    kdingus-splash.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The contents of &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; is simpler than that of out-of-source lbundles:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# l10n-spec for KDingus' in-source bundle.&lt;br /&gt;
source-vcs = auto&lt;br /&gt;
languages = aa bb&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the lbundle is kept together with the application, sharing same root directory and version control system, there is no need for the &amp;lt;tt&amp;gt;source-root&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;bundle-vcs&amp;lt;/tt&amp;gt; fields. In fact, the presence or lack of the &amp;lt;tt&amp;gt;source-root&amp;lt;/tt&amp;gt; field identifies the lbundle as out-of-source or in-source.&lt;br /&gt;
&lt;br /&gt;
Field &amp;lt;tt&amp;gt;track-unbundled&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;ignore-unbundled&amp;lt;/tt&amp;gt;) are not present either. All files which are unbundled are silently ignored. It is assumed that the KDingus' maintainer will modify and test installation instructions such as not to break installation of localized resources.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;languages&amp;lt;/tt&amp;gt; field could be omitted here as well, but for in-source lbundles it is even more important to keep tight check of wrongly named language subdirs.&lt;br /&gt;
&lt;br /&gt;
=== Greedy Bundling ===&lt;br /&gt;
&lt;br /&gt;
The default assumption behind lbundles is that only a small part of all resources need to be localized. It is upon the translator to spot the resources which need localization, make their localized versions, and add them to an lbundle where they will get tracked.&lt;br /&gt;
&lt;br /&gt;
When instead it would be better to track all of the original resources, lbundle tracking can be set to ''greedy'' mode: any original resource that does not have a localized counterpart yet will be tracked as missing. When a new original resource gets added, the translator will be notified of that by &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Fields in &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; used in greedy mode are as follows:&lt;br /&gt;
&lt;br /&gt;
; greedy-bundling: the option to engage greedy mode (a boolean value, set to true). Other fields controlling greedy bundling have no effect if this option is not set.&lt;br /&gt;
&lt;br /&gt;
; greedy-monolingual: states whether the lbundle is monolingual (boolean). This should make sense only for out-of-source bundles, where there may be one per language. Greedy mode needs this piece of information in order to know how to report and track missing localized files, as bundled (multilingual lbundle) or unbundled (monolingual).&lt;br /&gt;
&lt;br /&gt;
; greedy-from-level: if the lbundle covers a tree of original subdirectories, this field can be used to limit the greedy collection and reporting of missing files only to subdirectories at this level and below. 0 is the level of the &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file itself, 1 is one level below, etc.&lt;br /&gt;
&lt;br /&gt;
; greedy-only-started: normally all original resources missing in localization are reported as such (except the ignored ones), no matter where they reside in the original subdirectory tree covered by the lbundle. This field (a boolean) is used to limit greedy bundling only to those subdirectories already existing in the lbundle. Useful in several scenarios, e.g. when starting the resource localization to avoid being engulfed in listings of missing localized resources. Automatically enabled when &amp;lt;tt&amp;gt;track-by-subdir&amp;lt;/tt&amp;gt; is in effect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operation ==&lt;br /&gt;
&lt;br /&gt;
To check all lbundles for the language &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; in trunk, &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; can be run like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4/&lt;br /&gt;
$ lbundle-check.py aa/ # check all out-of-source&lt;br /&gt;
$ lbundle-check.py source/link/ -l aa # check all in-source&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If &amp;lt;tt&amp;gt;-l aa&amp;lt;/tt&amp;gt; option weren't specified in the second invocation, &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; would check ''all'' languages in &amp;lt;tt&amp;gt;source/link/&amp;lt;/tt&amp;gt; instead of only &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt;. In the first invocation &amp;lt;tt&amp;gt;-l aa&amp;lt;/tt&amp;gt; was omitted because out-of-source bundles contain only their own language, but it wouldn't cause any problem if it were present. Only particular lbundles can be checked by giving their subdirectories as arguments.&lt;br /&gt;
&lt;br /&gt;
So, what does &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; actually do, and what does it report? For brevity, let's limit to the out-of-source bundle for the KDingus as kdeutils application. After setting up the &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; for that case (as shown [[#Out-of-Source Lbundles|earlier]]), running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; for the first time will output:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4&lt;br /&gt;
$ lbundle-check.py aa/data/&lt;br /&gt;
!  aa/data/kdeutils/kdingus/pics/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
Added to tracking: 2&lt;br /&gt;
  aa/data/kdeutils/kdingus/pics/CMakeLists.txt&lt;br /&gt;
  aa/data/kdeutils/kdingus/pics/l10n/aa/kdingus-splash.png&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The file &amp;lt;tt&amp;gt;aa/data/kdeutils/kdingus/pics/l10n-track&amp;lt;/tt&amp;gt; will be created, with the following contents:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Do not edit manually, except to remove complete lines.&lt;br /&gt;
&lt;br /&gt;
# -&lt;br /&gt;
ok        ¦CMakeLists.txt¦  865f7...e926d  755260&lt;br /&gt;
&lt;br /&gt;
# aa&lt;br /&gt;
ok        ¦l10n/aa/kdingus-splash.png¦  37c4a7...8fe3a  755647&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For each &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file encountered, &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will create one of these &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; files. &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; file, in each non-comment, non-empty line, contains four fields, in order: the state of the localized resource against the original, the relative path to the bundled resource, the checksum of the ''original'' resource, and the VCS revision string of the original file which has this checksum.&lt;br /&gt;
&lt;br /&gt;
At this point, when &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt; file has been manually written, and &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; created by running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;, both should be added and committed to version control.&lt;br /&gt;
&lt;br /&gt;
So long as the original resource does not change, rerunning &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; in the same way will do nothing, as everything is in sync. Obviously, the original resources should be updated to the latest repository version prior to checking, and &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; can do that itself if started with &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ lbundle-check.py -u aa/data/&lt;br /&gt;
svn up .../kdeutils/kdingus/pics/CMakeLists.txt&lt;br /&gt;
At revision 762512.&lt;br /&gt;
svn up .../kdeutils/kdingus/pics/kdingus-splash.png&lt;br /&gt;
At revision 762512.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the original resource is modified, e.g. KDingus' splash screen is tweaked up, &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will report the following:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ lbundle-check.py aa/data/&lt;br /&gt;
!  aa/data/kdeutils/kdingus/pics/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
Newly fuzzied: 1&lt;br /&gt;
  aa/data/kdeutils/kdingus/pics/l10n/aa/kdingus-splash.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and its entry in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; will state:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
fuzzy     ¦l10n/aa/kdingus-splash.png¦  37c4a7...8fe3a  755647&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
i.e. only the status will have changed from &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt;. Now the translator has the information needed to compare what has changed in the original splash image: this entry still states the revision of the previous original file on which the localized file was based.&lt;br /&gt;
&lt;br /&gt;
If the original resource is renamed, moved, or deleted, the report will be slightly different:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ lbundle-check.py aa/data/&lt;br /&gt;
!  aa/data/kdeutils/kdingus/pics/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
Newly obsoleted: 1&lt;br /&gt;
  aa/data/kdeutils/kdingus/pics/l10n/aa/kdingus-splash.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and the entry in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
obsolete  ¦l10n/aa/kdingus-splash.png¦  37c4a7...8fe3a  755647&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now the translator must find out, using the old revision string, what exactly happened to the original resource, and do the same for the localized resource.&lt;br /&gt;
&lt;br /&gt;
When the fuzzy or obsolete state has been resolved, localized resource updated to reflect changes in the original, it should be recorded as such. To do this, the entry for the resource is first manually deleted from &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; file (the whole line is removed), and then &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; is rerun. This will recreate the entry with a fresh &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;strict-state&amp;lt;/tt&amp;gt; field has been set to true in &amp;lt;tt&amp;gt;l10n-spec&amp;lt;/tt&amp;gt;, then not only the state of the entry in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; is changed, but the tracked file itself is renamed to contain &amp;lt;tt&amp;gt;~fuzzy&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;~obsolete&amp;lt;/tt&amp;gt; marker just before the extension. This mode is called strict because unless the out-of-sync state is corrected, the file is &amp;quot;misnamed&amp;quot; from the point of view of the runtime system, and will not be used instead of the original (it may even not get installed, depending on the exact installation instructions).&lt;br /&gt;
&lt;br /&gt;
To resolve the fuzzy or obsolete state in strict mode, it is not necessary to manually remove the entry from &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt;. Instead, it is enough to put an updated version of the file (without the state maker in its name) next to the out-of-sync version, and rerun &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;. It will remove the old version and update the entry in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt;. (The renaming/removal are version control aware, i.e. proper version control commands will be used for these operations if &amp;lt;tt&amp;gt;*-vcs&amp;lt;/tt&amp;gt; fields have been set in the spec file.)&lt;br /&gt;
&lt;br /&gt;
When [[#Greedy Bundling|greedy bundling]] is engaged, each original file which doesn't have a localized counterpart will be reported in the track file (either as bundled or unbundled, depending on &amp;lt;tt&amp;gt;greedy-monolingual&amp;lt;/tt&amp;gt; option), with it's state set to &amp;lt;tt&amp;gt;missing&amp;lt;/tt&amp;gt; (except for the ignored files, given by the &amp;lt;tt&amp;gt;ignore-unbundled&amp;lt;/tt&amp;gt; option). When the localized file is placed at the appropriate location, next run of &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will change the state to &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Special Case: Tracking KDE Documentation Resources ==&lt;br /&gt;
&lt;br /&gt;
{{note|This section should be mostly self-contained, providing all the information needed for resource tracking in documentation, for two reasons. Firstly, it can be reasonably assumed that many more KDE translation teams will want to track localized documentation resources, rather than some other, special resources. Secondly, structure of documentation resources is significantly different from that of normal lbundles, so having separate examples helps.}}&lt;br /&gt;
&lt;br /&gt;
KDE documentation consists of two types of resources: the text, which is provided through Docbook files, and other data, mostly screenshots from applications. The text from original Docbook files is extracted into PO templates, translated through PO files, and localized Docbook files created out of them. Thus, when the original text changes, translators are automatically made aware of that through new and fuzzy entries in PO files. This is not so for screenshots. When an original screenshot changes, gets removed or added, translators get no notice of it. However, the tracking mechanism provided by &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; can be used to help rectify this.&lt;br /&gt;
&lt;br /&gt;
Localized resources of KDE documentation are not really organized into lbundles; their organization far precedes the lbundling system. Still, every language's documentation directory (&amp;lt;tt&amp;gt;aa/docs/&amp;lt;/tt&amp;gt;) can be understood as one ''greedy monolingual'' lbundle composed solely of ''unbundled'' resources, and as such tracked by the &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;. Docbook files are excluded from tracking, as they are kept up-to-date through Docbook-PO-Docbook roundtrip. At the moment, tracking is set up and operated by the coordinator of each language team that wants to have it.&lt;br /&gt;
&lt;br /&gt;
To set up tracking, the coordinator of the language &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; should maintain the local checkout of several modules, with same structure as KDE repository, as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            templates/&lt;br /&gt;
            documentation/&lt;br /&gt;
            aa/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            scripts/&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                templates/&lt;br /&gt;
                documentation/&lt;br /&gt;
                aa/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In fact, it is a good idea anyway for a language coordinator to maintain such a checkout (the total space requirement is between 500 MB and 1 GB).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;documentation/&amp;lt;/tt&amp;gt; subdirectory is not actually found in the Subversion repository; it is created and periodically updated by running the &amp;lt;tt&amp;gt;scripts/populate_documentation.sh&amp;lt;/tt&amp;gt; script, in stable and trunk:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4&lt;br /&gt;
$ scripts/populate_documentation.sh&lt;br /&gt;
$ cd $KDEREPO/branches/stable/l10n-kde4&lt;br /&gt;
$ scripts/populate_documentation.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;populate_documentation.sh&amp;lt;/tt&amp;gt; from trunk will get exactly the documentation modules' branches translated as trunk, and &amp;lt;tt&amp;gt;populate_documentation.sh&amp;lt;/tt&amp;gt; from stable those translated as stable.&lt;br /&gt;
&lt;br /&gt;
After this file structure is established, create the files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/trunk/l10n-kde4/aa/docs/l10n-spec&lt;br /&gt;
$KDEREPO/branches/stable/l10n-kde4/aa/docs/l10n-spec&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
both with the following, branch-independent content:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
source-root = aa/docs:documentation&lt;br /&gt;
source-vcs = file&lt;br /&gt;
bundle-vcs = auto&lt;br /&gt;
track-by-subdir = yes&lt;br /&gt;
&lt;br /&gt;
greedy-bundling = yes&lt;br /&gt;
greedy-monolingual = yes&lt;br /&gt;
greedy-from-level = 2&lt;br /&gt;
&lt;br /&gt;
ignore-unbundled = \&lt;br /&gt;
    CMakeLists.txt */CMakeLists.txt */*/CMakeLists.txt */*/*/CMakeLists.txt \&lt;br /&gt;
    */*/*.docbook */*/*/*.docbook \&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the language code &amp;lt;tt&amp;gt;aa&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;aa/docs:...&amp;lt;/tt&amp;gt; at the top, and modify it accordingly.&lt;br /&gt;
&lt;br /&gt;
Finally, run the &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; on the documentation directories of your language, e.g. for the trunk:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ lbundle-check.py $KDEREPO/trunk/l10n-kde4/aa/docs/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
After some time, depending on how many localized screenshots you have made already, a whole lot of output may appear -- listing of files having been added to tracking. More importantly, each subdirectory in &amp;lt;tt&amp;gt;aa/docs/&amp;lt;/tt&amp;gt; which has (or could have) at least one localized screenshot, will get a ''tracking file'', named &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt;. Tracking files will be automatically added to version control as well, so you can commit &amp;lt;tt&amp;gt;aa/docs/&amp;lt;/tt&amp;gt; right away.&lt;br /&gt;
&lt;br /&gt;
What does a tracking file look like? For example, the original documentation for KRuler contains these files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
documentation/kdegraphics/kruler/&lt;br /&gt;
    CMakeLists.txt&lt;br /&gt;
    index.docbook&lt;br /&gt;
    kruler.png&lt;br /&gt;
    kruler-settings.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Assume that your language's localized documentation contains:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
aa/docs/kdegraphics/kruler/&lt;br /&gt;
    CMakeLists.txt&lt;br /&gt;
    index.docbook&lt;br /&gt;
    kruler.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
that is, the localized variant of &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt; is missing. Then, the &amp;lt;tt&amp;gt;aa/docs/kdegraphics/kruler/l10n-track&amp;lt;/tt&amp;gt; that got created will have this contents:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Do not edit manually, except to remove complete lines.&lt;br /&gt;
&lt;br /&gt;
ok        ¦kruler.png¦  58ba...872a  58ba...872a&lt;br /&gt;
missing   ¦kruler-settings.png¦  4dd2...5ebf  4dd2...5ebf&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Each line contains four pieces of data: the sync state and the name of the localized file, and the twice repeated checksum of the ''original'' file. (Instead of the second checksum normally there would be the repository revision of the original file, but &amp;lt;tt&amp;gt;populate_documentation.sh&amp;lt;/tt&amp;gt; does not make proper repository checkouts). Since this is the first run of &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;, it assumed that the present localized &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; is up-to-date (more later on this assumption), and so its state is set to &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;. For &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt;, which is not there in the localized directory, the state is set as &amp;lt;tt&amp;gt;missing&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The day-to-day operation constitutes running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; from time to time, in the same way as the first time. When a new original screenshot is added, the appropriate &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; file will get a new &amp;lt;tt&amp;gt;missing&amp;lt;/tt&amp;gt; entry. When a localized screenshot is produced and put into correct place, the &amp;lt;tt&amp;gt;missing&amp;lt;/tt&amp;gt; state will change into &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4/&lt;br /&gt;
$ (...put localized kruler-settings.png into aa/docs/...)&lt;br /&gt;
$ lbundle-check.py aa/docs/&lt;br /&gt;
A  (bin)  aa/docs/kdegraphics/kruler/kruler-settings.png&lt;br /&gt;
M      aa/docs/kdegraphics/kruler/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
New 'ok': 1&lt;br /&gt;
  aa/docs/kdegraphics/kruler/kruler-settings.png (...)&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that version control operations are done automatically too.&lt;br /&gt;
&lt;br /&gt;
Assume now that, in the above example, after some time the original &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; is modified, and the original &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt; is removed. Then, running the tracker produces:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-kde4/&lt;br /&gt;
$ lbundle-check.py aa/docs/&lt;br /&gt;
M      aa/docs/kdegraphics/kruler/l10n-track&lt;br /&gt;
--------------------&lt;br /&gt;
New 'fuzzy': 1&lt;br /&gt;
  aa/docs/kdegraphics/kruler/kruler.png (...)&lt;br /&gt;
New 'obsolete': 1&lt;br /&gt;
  aa/docs/kdegraphics/kruler/kruler-settings.png (...)&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and the content of tracking file becomes:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Do not edit manually, except to remove complete lines.&lt;br /&gt;
&lt;br /&gt;
fuzzy     ¦kruler.png¦  58ba...872a  3d94...2c6f&lt;br /&gt;
obsolete  ¦kruler-settings.png¦  4dd2...5ebf  ae31...b561&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now the translator should remove the obsoleted localized &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt;, and check the new original &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; to see what to do with the localized &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt;. When the fuzzy state of localized &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; is resolved -- by making a new localized screenshot, or deciding that the existing screenshot is still fine -- the translator edits &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; to remove its line. After rerunning &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt;, new localized &amp;lt;tt&amp;gt;kruler.png&amp;lt;/tt&amp;gt; will be picked up with the default &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt; state, and the line for &amp;lt;tt&amp;gt;kruler-settings.png&amp;lt;/tt&amp;gt; will be automatically removed.&lt;br /&gt;
&lt;br /&gt;
{{warning|As the top comment in &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; files states, never manually edit these files except to unfuzzy entries by removing their complete lines. E.g. do not change the state manually, which would leave the original checksum and revision wrong.}}&lt;br /&gt;
&lt;br /&gt;
Instead of running &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; on the whole &amp;lt;tt&amp;gt;aa/docs/&amp;lt;/tt&amp;gt; tree, it can also be run on any given subdirectory of it. It will then check only the files in that subdirectory and below.&lt;br /&gt;
&lt;br /&gt;
=== Many Localized Screenshots at Start ===&lt;br /&gt;
&lt;br /&gt;
There is a small issue with the fact that &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; will set state of new files to &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;. If the documentation directory already has a lot of screenshots with unknown state compared to the original, it is not appropriate to consider them &amp;lt;tt&amp;gt;ok&amp;lt;/tt&amp;gt;, but &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt;. To have this, after the ''first'' run of &amp;lt;tt&amp;gt;lbundle-check.py&amp;lt;/tt&amp;gt; simply postprocess all &amp;lt;tt&amp;gt;l10n-track&amp;lt;/tt&amp;gt; files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ find aa/docs/ -iname l10n-track | xargs perl -pi -e 's/^ok   /fuzzy/'&lt;br /&gt;
$ find aa/docs/ -iname l10n-track | xargs perl -pi -e 's/[0-9a-z]{32}/0/'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
(The second command replaces the original checksums with all zeros, as otherwise the files would be again recognized as up-to-date on the next run.) Afterwards, in due time, existing screenshots can be inspected one by one, and their fuzzy state removed as explained previously.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Summit</id>
		<title>Localization/Workflows/PO Summit</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Summit"/>
				<updated>2013-01-31T00:13:24Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Put back placeholder language.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Translating in Summit|&lt;br /&gt;
prereqs=[[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Software Branches and Translation ==&lt;br /&gt;
&lt;br /&gt;
The obvious approach to releasing software is for developers to focus on one central body of code, a single &amp;quot;branch&amp;quot;, fixing bugs and adding new features to it, and from time to time taking a &amp;quot;snapshot&amp;quot; of the branch and packing it as next release. One approach to make the release process more robust, is for development to proceed in two parallel branches. From the &amp;quot;stable&amp;quot; branch the actual releases are made, mostly with bugs fixed and only very important features added. The other, &amp;quot;unstable&amp;quot; branch, is used to develop new and redesign existing features, and at some point will become the next stable branch. Depending on the project, releases may be made from the unstable branch as well, in parallel with stable releases, in order for eager users to help testing the novelties.&lt;br /&gt;
&lt;br /&gt;
In KDE, all three release models may be present at any given moment. Core KDE modules, which are together labeled as &amp;quot;the KDE&amp;quot; and released in unison, follow the two branch model, with stable and trunk branch, and releases from stable branch only. KDE extragear applications may do the same, but they are not required to; they may instead make releases from the trunk branch only, or also use stable and trunk branch, but make releases from both. This presents translators with the workflow as on the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_branches.png|center|Classic translation by branches]]&lt;br /&gt;
&lt;br /&gt;
The KDE [[Localization/Workflows/Repository_Automation|repository automation]] (aka &amp;quot;Scripty&amp;quot;) is preparing template POs and merging them with language POs. From the point of view of language teams, real people who perform global actions (e.g. moving around POs for all languages when an application moves from module to another) can also be grouped here. However, the translation team is still presented with two branches of POs to translate.&lt;br /&gt;
&lt;br /&gt;
In general, this means that, just like programmers, at times translators have to work on both branches, and propagate fixes from one branch to another (&amp;quot;backport&amp;quot; from trunk to stable, or &amp;quot;forwardport&amp;quot; from stable to trunk). This may be prone to coordinatorial confusion, and demand extra effort and attention when updating translations. Keeping up with two branches is easier in core KDE modules, as they are released from stable branch only and with singular schedule, but could be more taxing with extragear applications.&lt;br /&gt;
&lt;br /&gt;
The exact amount of effort spent due to parallel translation, porting of fixes, and coordination, depends on the translation team. For example, a well-manned and well-coordinated team, with established style and terminology guides, custom automation to support these, may be able to keep all POs in both branches fully translated at all times with ease. Or, a team may have worked out well-defined schedules, such that any given member of the team at one point switches from translating one branch to another, without looking back, thus effectively having everyone always working on one branch (even if not the same one).&lt;br /&gt;
&lt;br /&gt;
If, however, you as the team coordinator have said and thought &amp;quot;Should do that in trunk too, bugger&amp;quot;, &amp;quot;Didn't we fix that already?&amp;quot;, &amp;quot;No, you should take it from stable&amp;quot;, &amp;quot;It was released from WHAT branch?&amp;quot;, more often than you would have liked, the following presents one possibility for sidestepping such issues.&lt;br /&gt;
&lt;br /&gt;
== Translating in Summit ==&lt;br /&gt;
&lt;br /&gt;
For a PO catalog which exists in both stable and trunk branch, a new same-named catalog can be made by ''gathering'' all the unique messages from branch PO files, i.e. the ''summit'' of branch POs. Assuming that branch POs were not all that different, since they are two versions of the same catalog, the summit PO shouldn't have much more messages than either. Translators at all times work on the summit PO, from which the messages are periodically ''scattered'' back to original branch POs. Thus, translators can always work on summit POs, not having to do any parallel translation, branch switching or porting of fixes. The summit workflow is presented by the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_summit.png|center|Translation in summit]]&lt;br /&gt;
&lt;br /&gt;
In the summit mode, repository automation gathers summit PO templates from branch templates, and stores them separately from real branches, at {{path|trunk/l10n-support/templates/summit/}}. The language team also has a collection summit POs, at {{path|trunk/l10n-support/LANG/summit/}}, which is the sole location where translation happens. As before, repository automation handles merging of templates in branches, but merging of summit POs is done by the team coordinator; team coordinator can opt to manually merge branch POs as well (more on why-and-how of this later). From time to time, the team coordinator fills out branch POs by scattering from summit. Not to worry, each of these special actions upon the team coordinator is done with a single command.&lt;br /&gt;
&lt;br /&gt;
While it is in principle obvious that two branch POs can be made into one summit PO with the union of their messages, there are some important details that should be handled the right way by the summitting system:&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes modules in one branch, so that it no longer belongs to the same module in both branches (e.g. application is moved from one to another module in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes its name in one branch, but not in the other (e.g. application is renamed in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO in one branch is split into two POs in another (e.g. extracting a library out of monolithic application in trunk)?&lt;br /&gt;
&lt;br /&gt;
* Where to place messages unique to one branch in the summit PO? The original file context of a message, which messages precede it and which follow it, should be kept as much as possible.&lt;br /&gt;
&lt;br /&gt;
* If source references are used to achieve good ordering of messages in summit PO, what to do if some source file paths change in one branch (e.g. application gets restructured in trunk)?&lt;br /&gt;
&lt;br /&gt;
* How to handle messages with different plurality across branches (since messages are identified only by their &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, an not &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt;)?&lt;br /&gt;
&lt;br /&gt;
And handle these details it does, the present summitting system. This also means that teams working in the summit need not take care of the first three issues above, which are affecting manual branch handling too.&lt;br /&gt;
&lt;br /&gt;
Summit POs are normal, fully valid POs in their own right. A message in a summit PO is different from branch PO only by being equipped with another comment, &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt;, showing in which branches the message exists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgctxt &amp;quot;The destination url of a job&amp;quot;&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:517&lt;br /&gt;
msgid &amp;quot;&amp;amp;Keep this window open after transfer is complete&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first message above thus exists in trunk only, the second in stable only, and the third in both branches. The source reference always points to the source file in the first listed branch. Any extracted comments (&amp;lt;tt&amp;gt;#.&amp;lt;/tt&amp;gt;) other than the branch list are also taken from the first listed branch.&lt;br /&gt;
&lt;br /&gt;
Note that the two messages above are different only by context; the context was added in trunk, but not in stable, in order not to break message freeze. However, due to careful ordering of messages in summit POs, these two messages appear together, allowing translator to immediately make correction in stable branch too if the new context in trunk shows it to be necessary.&lt;br /&gt;
&lt;br /&gt;
=== Setting Up and Daily Operation ===&lt;br /&gt;
&lt;br /&gt;
Before initializing language summit, the team coordinator has to have all the necessary paths checked out from the KDE repository, and structured on the local machine exactly as in the repository. If the path to the root of KDE repository on the local machine is &amp;lt;tt&amp;gt;$KDEREPO&amp;lt;/tt&amp;gt;, and the language code &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt;, then the structure should be as follows, with leaf directories checked out in full:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            scripts/&lt;br /&gt;
            pology/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                templates/&lt;br /&gt;
                LANG/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that this structure is fully under version control (rather than e.g. top directories being manually created), so if that is not the case, the following commands will fetch everything anew in proper order:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd $KDEREPO&lt;br /&gt;
svn co --depth=empty svn+ssh://svn.kde.org/home/kde .&lt;br /&gt;
svn up --depth=empty branches branches/stable branches/stable/l10n-kde4&lt;br /&gt;
svn up --depth=empty trunk trunk/l10n-support trunk/l10n-kde4&lt;br /&gt;
svn up branches/stable/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the trailing dot in the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command, and do not miss to substitute LANG for the real language code in the last three commands. &amp;lt;tt&amp;gt;--depth=empty&amp;lt;/tt&amp;gt; option prevents recursive fetching, so that e.g. the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command does not fetch the complete repository tree. Later you can regularly update this tree with single command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
svn up $KDEREPO/{trunk,branches/stable}/l10n-kde4/{scripts,templates,LANG} \&lt;br /&gt;
       $KDEREPO/trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Summit operations are performed using the &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; command, which is part of [[Localization/Tools/Pology|Pology]], residing in {{path|trunk/l10n-support/pology/}}. Therefore the first thing to do is to setup Pology, which amounts only to setting the proper path:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ export PATH=$KDEREPO/trunk/l10n-support/pology/bin:$PATH&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To initialize the summit, by gathering from existing translation in branches, the team coordinator executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Depending on the amount of translation, after some minutes the initial gathering will have been completed, and language summit located under {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages/}}. This is the only time when the coordinator performs the gather operation on language POs; it is daily done only on templates by repository automation. Then, the created language summit should be merged with current summit templates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Merging the summit is something that the coordinator does periodically, with frequency of own desire. For example, it can be done daily, or with increasing frequency as the last day for translation for the next release approaches.&lt;br /&gt;
&lt;br /&gt;
After the first merging, language summit is ready for active translation. The coordinator should now commit {{path|$KDEREPO/trunk/l10n-support/LANG/}}, and, importantly, notify team members to stop working on branch POs and focus exclusively on summit POs.&lt;br /&gt;
&lt;br /&gt;
To scatter the summit, i.e. fill out POs in stable and trunk branch from the summit POs, the coordinator periodically executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As with merging, there is no fixed schedule when scattering should be done. Of course, it must necessarily be done before the next release is tagged, and in between it is useful to scatter for runtime testing, or to have translation statistics by branches on l10n.kde.org up to date.&lt;br /&gt;
&lt;br /&gt;
Periodic scattering and merging of the complete summit are basically all that a language team coordinator needs to do specifically to operate the summit. Also, since {{path|l10n-support/scripts/}} and {{path|l10n-support/pology/}} contain scripts and settings critical for proper functioning of summit operations, and may be tweaked at any time, they should always be updated from the repository together with PO files and templates (in fact, it is best to always update at once the whole tree as outlined above).&lt;br /&gt;
&lt;br /&gt;
{{note|For documentation POs, summit setup and operation is the same, only replacing every &amp;lt;tt&amp;gt;messages&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;docmessages&amp;lt;/tt&amp;gt; in the command lines above. The user interface and documentation summits are fully independent, so for a trial period it is reasonable to work with the interface summit only, and engage documentation summit once the trial has been deemed successfull.}}&lt;br /&gt;
&lt;br /&gt;
=== Operation Targets ===&lt;br /&gt;
&lt;br /&gt;
Sometimes it is advantageous to merge or scatter just a single catalog, a single module, a single branch, or any combination thereof. To this end, scatter and merge operations accept any number of ''operation targets'' after the operation keyword, specified as one of &amp;lt;tt&amp;gt;''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''MODULE''/&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''MODULE''/&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;''BRANCH'':&amp;lt;/tt&amp;gt;. For example, to scatter just to Dolphin's PO in stable branch, in order to test translation at runtime, one would execute:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(note no &amp;lt;tt&amp;gt;.po&amp;lt;/tt&amp;gt; ending on catalog name). Or, to scatter to every PO in &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; module in stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:kdeplasma-addons/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the trailing slash is mandatory, or else &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; would think that &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; is a catalog name). Finally, to scatter to all catalogs in the stable branch (with the trailing colon for the same reason as earlier):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command line arguments of &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; operations are intentionally arranged such that all the arguments fixed for one language are placed first. If operation targets are used frequently, then it is convenient to place the immutable part of the command line under a shell alias, with absolute path to the summit setup file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ alias posummit-kde-LANG=&amp;quot;posummit $KDEREPO/trunk/l10n-support/scripts/messages.summit LANG&amp;quot;&lt;br /&gt;
$ cd ANYWHERE&lt;br /&gt;
$ posummit-kde-LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Externally Injected Branch Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Once the summit is in operation, normally the only way for a catalog to appear in branches (trunk or stable) is through scattering from the summit. However, sometimes an application which had seen considerable development outside of the infrastructure of KDE project gets moved in, drawing in any of its existing translations into branches. Such externally injected branch catalogs cause warnings to be issued on summit scattering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/foobar.po  # dummy injection&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/libfoobar.po  # dummy injection&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
posummit: [warning] Some branch catalogs have no associated summit catalog (expected summit path given):&lt;br /&gt;
... ../l10n-kde4/LANG/messages/kdetoys/foobar.po --&amp;gt; LANG/summit/messages/kdetoys/foobar.po&lt;br /&gt;
... ../l10n-kde4/LANG/messages/kdetoys/libfoobar.po --&amp;gt; LANG/summit/messages/kdetoys/libfoobar.po&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When this happens, the injected catalogs need to be gathered into the summit. This is done just like the initial gathering, only giving injected catalogs' names as operation targets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force foobar libfoobar&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Summit Customization ===&lt;br /&gt;
&lt;br /&gt;
File {{path|scripts/messages.summit}} (i.e. {{path|$KDEREPO/trunk/l10n-support/scripts/messages.summit}}), given as first argument to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, contains the general summit setup for all languages. This file is set to include customization file per language, if it exists at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages.extras.summit}}, which contains additions and overrides to the general setup as desired by the language team. Same as the general setup file, the customization file is a Python source. It uses an external object named &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; to define summit settings, and can, of course, contain any helper Python code (the file is executed only once, at the beginning of a &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; run). It has the following general layout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# -*- coding: UTF-8 -*-&lt;br /&gt;
# kate: syntax Python;&lt;br /&gt;
# This file is included by scripts/messages.summit&lt;br /&gt;
# for language-specific additions/overrides.&lt;br /&gt;
#&lt;br /&gt;
# ...&lt;br /&gt;
# ... operations with object S and other Python code ...&lt;br /&gt;
# ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Object &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; provides both data attributes and methods to configure different aspects of summit operation. For example, while the general setup specifies that text fields in summit catalogs should not be wrapped on column but should be wrapped on logical breaks (like some markup tags), this can be overriden using &amp;lt;tt&amp;gt;summit_wrap&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;summit_fine_wrap&amp;lt;/tt&amp;gt; attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
S.summit_wrap = True&lt;br /&gt;
S.summit_fine_wrap = False&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, to get the path to a file relative to the summit customization file itself (rather than to current working directory, where &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; was executed), method &amp;lt;tt&amp;gt;resolve_path_rooted&amp;lt;/tt&amp;gt; can be used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
relpath = S.resolve_path_rooted(&amp;quot;../whatever.txt&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following sections will present some typical customization possibilities.&lt;br /&gt;
&lt;br /&gt;
=== Fully Local Merging ===&lt;br /&gt;
&lt;br /&gt;
When scattering from the summit, sometimes there will be reports of &amp;quot;messages missing in the summit&amp;quot;. This happens because of time rift created by the Scripty merging branch POs, gathering summit templates, and a team coordinator merging the language summit, thus making some messages in branch POs not always present in the summit. This condition is benign, as such warnings will start to disappear with the message freeze approaching, but can be annoying. For this reason, team coordinator can stop Scripty from merging branch POs, and have the &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; command alone merge not only summit POs, but stable and trunk POs as well, such that summit and branches are always in perfect sync.&lt;br /&gt;
&lt;br /&gt;
First, to stop Scripty from merging branch POs, a file named &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; (with arbitrary content) should be committed to the roots of respective trees, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$ touch $KDEREPO/trunk/l10n-kde4/messages/LANG/no-auto-merge&lt;br /&gt;
$ touch $KDEREPO/branches/stable/l10n-kde4/LANG/messages/no-auto-merge&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, to make summit &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; merge everything, the following lines should be added into the summit customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Set local merging for all branches.&lt;br /&gt;
for branch in S.branches:&lt;br /&gt;
    branch[&amp;quot;merge_locally&amp;quot;] = True&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once local merging of all branches is set, the coordinator can also use operation targets for selective merging, e.g. to merge only stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge stable:&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Merging with Compendium ===&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; takes into account only the catalog itself to fill out near-match translations to new messages introduced by merging. i.e. to produce fuzzy messages. However, an arbitrary PO file can be given to &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; as another possible source of earlier translations, through the &amp;lt;tt&amp;gt;--compendium&amp;lt;/tt&amp;gt; option. For maximum effect, this PO file is usually constructed as the collection of messages from all PO files project-wide, and hence called the ''compendium''.&lt;br /&gt;
&lt;br /&gt;
Compendium can be used in summit merge operations simply by setting &amp;lt;tt&amp;gt;compendium_on_merge&amp;lt;/tt&amp;gt; attribute in summit customization file. If the compendium is located at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages-compendium.po}}, then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Compendium to use when merging summit catalogs.&lt;br /&gt;
S.compendium_on_merge = S.resolve_path_rooted(&amp;quot;messages-compendium.po&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that if not located as above, compendium should not be placed within {{path|.../LANG/summit/messages/}}, as then it would be considered a summit catalog itself. In case fully local merging is engaged, only summit POs will be merged with compendium; it makes no sense for branch POs, since they are not being directly translated.&lt;br /&gt;
&lt;br /&gt;
See [http://www.gnu.org/software/automake/manual/gettext/Creating-Compendia.html &amp;quot;Creating Compendia&amp;quot;] section of Gettext manual for details on how to create a compendium out of current body of summit translations. Once you establish the precise commands to create the compendium (whether to collect fuzzies too, whether to include old compendium as one of sources for the new, etc.), you would periodically refresh and commit the updated compendium.&lt;br /&gt;
&lt;br /&gt;
=== Vivifying Summit Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Translation of a summit catalog normally starts the same way as it did for branch catalogs, by copying it over from template and initializing the header. This can be done manually, but it can also be quite automatic when using project manager as sometimes provided by dedicated PO editors. However, relying on the editor's project manager can be disadvantageous at times. For example, aside from the PO editor, other, frequently command line tools may be used to process the body of translation, and these tools might need to consider non-started templates as if they were empty POs (e.g. statistics). Team members who do not have full local checkout, or no project set up in the editor, may need to jump between language and template directories when looking for files to translate.&lt;br /&gt;
&lt;br /&gt;
Therefore, summit setup can be customized to automatically create (&amp;quot;vivify&amp;quot;) summit catalogs for every new summit template, so that there is never the need (for a tool or human) to specifically treat templates as empty catalogs. This is done by adding the following lines into customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Create empty summit catalog for every new summit template.&lt;br /&gt;
S.vivify_on_merge = True&lt;br /&gt;
S.vivify_w_translator = &amp;quot;Noone Noonian &amp;lt;noone.noonian@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_langteam = &amp;quot;Neverneese &amp;lt;neverteam@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_plurals = &amp;quot;nplurals=2; plural=n != 1;&amp;quot;&lt;br /&gt;
# Minimum translation state to create branch catalog on scatter.&lt;br /&gt;
S.scatter_min_completeness = 0.9&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;vivify_w_*&amp;lt;/tt&amp;gt; attributes set the necessary data to initialize headers of newly created summit catalogs. Aside from those listed above, there is also the &amp;lt;tt&amp;gt;vivify_w_charset&amp;lt;/tt&amp;gt; attribute, which is by default &amp;lt;tt&amp;gt;&amp;quot;UTF-8&amp;quot;&amp;lt;/tt&amp;gt;, and very probably should not be changed.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; attribute does not refer to vivification of summit catalogs, but should invariably be set in this context. When scattering from summit, normally the branch catalog is automatically created if there is the corresponding summit catalog. When vivification is engaged, this would result in creation of empty branch catalogs too, which is not desired for two reasons. Firstly, empty branch catalogs would become part of the released language pack, for which there is no practical reason. Secondly, KDE's i18n system regards an application with installed catalog as translated, so messages coming from basic system catalogs (e.g. &amp;lt;tt&amp;gt;kdelibs4&amp;lt;/tt&amp;gt;) would show through, resulting in mostly untranslated user interface with specks of translation -- many users consider this rather ungainly. Therefore, &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; sets how complete the translation of currently non-existing branch catalog should be after scatter (0.0 empty, 1.0 fully complete), for the branch catalog to actually be created. If the &amp;lt;tt&amp;gt;--force&amp;lt;/tt&amp;gt; option is given to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, the branch catalog will be created regardless of its translation state, which may be handy in combination with [[#Operation Targets|operation target]] when wanting to check work in progress in running application.&lt;br /&gt;
&lt;br /&gt;
If [[#Merging with Compendium|the compendium has been set]] for merging, every vivified summit catalog will also be merged against the compendium, to fill out as many of messages with approximate translations.&lt;br /&gt;
&lt;br /&gt;
=== Scatter Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Checks, modifications...))&lt;br /&gt;
&lt;br /&gt;
=== Merge Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Special header fields...))&lt;br /&gt;
&lt;br /&gt;
== Disadvantages to Summit and Remedies ==&lt;br /&gt;
&lt;br /&gt;
Although hopefully shadowed by the advantages, working in summit is not without its disadvantages. These should be weighed when deciding of whether to try out the summit workflow.&lt;br /&gt;
&lt;br /&gt;
Obviously, while summit operations are made to be quite automatic, some extra aptitude is asked of the team coordinator. Reasonable shell handling, understanding of version control operations, feeling the pulse of repository automation, are all prerequisites, and some scripting ability advantageous.&lt;br /&gt;
&lt;br /&gt;
After the summit is put in operation, any changes made manually in branch POs will not propagate to summit, and will be soon lost to scattering -- summit translations override everything in branches. This means that the whole team must work in the summit, it is not possible for some members to use the summit, and some not.&lt;br /&gt;
&lt;br /&gt;
A summit PO file will necessarily have more messages than either of the branch files. For example, in the KDE 4.0/4.1 and 4.1/4.2 cycle, summit POs of core KDE modules had on average less than 5% more words than their stable counterparts. However, the said percent is the top, never approached limit of wasted workload due to trunk messages coming and going, given that as the next feature KDE release approaches, more and more trunk messages will find their way into it.&lt;br /&gt;
&lt;br /&gt;
Another, more pressing issue with increased size of summit POs is the following scenario: a stable release is around the corner, and the team has no time to update summit POs fully, but could update only stable messages in them. E.g. there are 1000 untranslated and fuzzy messages, out of which only 100 are from the stable branch. A clever dedicated PO editor could allow jumping only through untranslated and fuzzy messages which also satisfy a general search criteria, which in this case would be that a comment matches &amp;lt;tt&amp;gt;#\.\+&amp;gt;.*stable&amp;lt;/tt&amp;gt; regular expression. On the other hand, with some external help, it is enough if the PO editor can merely search through comments. Then, the &amp;lt;tt&amp;gt;posieve&amp;lt;/tt&amp;gt; command (ready to use next to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;) can equip untranslated and fuzzy stable messages with &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag (producing &amp;lt;tt&amp;gt;#, ..., untranslated&amp;lt;/tt&amp;gt; comment), and this flag can be searched for in the PO editor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ posieve tag-untranslated -sbranch:stable -swfuzzy PATHS_TO_PO_FILES_OR_DIRS&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag does not need to be manually removed when the message is updated. It will automatically disappear on the next merge, as it is not among flags known to Gettext.&lt;br /&gt;
&lt;br /&gt;
If an automatic source lookup mechanism (to check the message context by following its source references) was available for branches, it may not entirely work for summit. Already the branch POs in KDE are kept separate from the code, which means that paths given by source references cannot be followed directly, but appropriate root paths have to be added in some way (a dedicated PO editor may provide a way to do this); this should continue to work with summit for those messages which exist both in trunk and stable branch, since their source references correspond to trunk code. But for messages found only in stable branch, whose source references correspond to stable code, existing source lookup mechanism will likely assume trunk roots again, and try to fetch wrong sources. To fix this, the source lookup mechanism should be flexible enough to select roots based on branch keywords given in summit messages' &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt; comment.&lt;br /&gt;
&lt;br /&gt;
There is also the organizational issue with starting to use the summit, and, if it does not help as expected, stopping to use it. Team members have to be reminded to not send in branch POs at start, and then to be sent back to branch POs if summit is disbanded. On the plus side, disbanding summit is technically simple: just remove from the repository {{path|l10n-supprot/LANG/summit}}, possibly also &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; files if [[#Fully Local Merging|fully local merging]] was set up, and that is it.&lt;br /&gt;
&lt;br /&gt;
== Another Way to Improve Branch Handling ==&lt;br /&gt;
&lt;br /&gt;
If summit seems a lot to digest, or is simply an overkill for team's needs, but still some improvement to manual handling of branches would be welcomed, KDE's dedicated PO editor [[Localization/Tools/Lokalize|Lokalize]] offers a ''branch sync'' mode. It works as follows.&lt;br /&gt;
&lt;br /&gt;
In Lokalize project definition, the local paths of trunk and stable PO roots are set in ''Translation directory:'' and ''Branch directory:'' fields. Then, when a trunk PO file is opened, if it has a stable counterpart with same name and location as in the trunk, this stable PO is also going to be opened. For each trunk message in the main editing pane, if such a message exists in stable PO too, the stable message will be shown in the ''Secondary Sync'' pane; changes in the translation of trunk message will reflect to the stable message, and stable PO file will also be saved when the trunk is saved.&lt;br /&gt;
&lt;br /&gt;
Furthermore, any team member can personally choose to work like this, there is no need to change the workflow of the language team as whole. When sending modifications to the coordinator, team members who rely on this feature of Lokalize simply send both trunk and stable POs that got modified.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Summit</id>
		<title>Localization/Workflows/PO Summit</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Summit"/>
				<updated>2013-01-31T00:11:23Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Updated to warning instead of error behavior on externally injected branch catalogs.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Translating in Summit|&lt;br /&gt;
prereqs=[[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Software Branches and Translation ==&lt;br /&gt;
&lt;br /&gt;
The obvious approach to releasing software is for developers to focus on one central body of code, a single &amp;quot;branch&amp;quot;, fixing bugs and adding new features to it, and from time to time taking a &amp;quot;snapshot&amp;quot; of the branch and packing it as next release. One approach to make the release process more robust, is for development to proceed in two parallel branches. From the &amp;quot;stable&amp;quot; branch the actual releases are made, mostly with bugs fixed and only very important features added. The other, &amp;quot;unstable&amp;quot; branch, is used to develop new and redesign existing features, and at some point will become the next stable branch. Depending on the project, releases may be made from the unstable branch as well, in parallel with stable releases, in order for eager users to help testing the novelties.&lt;br /&gt;
&lt;br /&gt;
In KDE, all three release models may be present at any given moment. Core KDE modules, which are together labeled as &amp;quot;the KDE&amp;quot; and released in unison, follow the two branch model, with stable and trunk branch, and releases from stable branch only. KDE extragear applications may do the same, but they are not required to; they may instead make releases from the trunk branch only, or also use stable and trunk branch, but make releases from both. This presents translators with the workflow as on the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_branches.png|center|Classic translation by branches]]&lt;br /&gt;
&lt;br /&gt;
The KDE [[Localization/Workflows/Repository_Automation|repository automation]] (aka &amp;quot;Scripty&amp;quot;) is preparing template POs and merging them with language POs. From the point of view of language teams, real people who perform global actions (e.g. moving around POs for all languages when an application moves from module to another) can also be grouped here. However, the translation team is still presented with two branches of POs to translate.&lt;br /&gt;
&lt;br /&gt;
In general, this means that, just like programmers, at times translators have to work on both branches, and propagate fixes from one branch to another (&amp;quot;backport&amp;quot; from trunk to stable, or &amp;quot;forwardport&amp;quot; from stable to trunk). This may be prone to coordinatorial confusion, and demand extra effort and attention when updating translations. Keeping up with two branches is easier in core KDE modules, as they are released from stable branch only and with singular schedule, but could be more taxing with extragear applications.&lt;br /&gt;
&lt;br /&gt;
The exact amount of effort spent due to parallel translation, porting of fixes, and coordination, depends on the translation team. For example, a well-manned and well-coordinated team, with established style and terminology guides, custom automation to support these, may be able to keep all POs in both branches fully translated at all times with ease. Or, a team may have worked out well-defined schedules, such that any given member of the team at one point switches from translating one branch to another, without looking back, thus effectively having everyone always working on one branch (even if not the same one).&lt;br /&gt;
&lt;br /&gt;
If, however, you as the team coordinator have said and thought &amp;quot;Should do that in trunk too, bugger&amp;quot;, &amp;quot;Didn't we fix that already?&amp;quot;, &amp;quot;No, you should take it from stable&amp;quot;, &amp;quot;It was released from WHAT branch?&amp;quot;, more often than you would have liked, the following presents one possibility for sidestepping such issues.&lt;br /&gt;
&lt;br /&gt;
== Translating in Summit ==&lt;br /&gt;
&lt;br /&gt;
For a PO catalog which exists in both stable and trunk branch, a new same-named catalog can be made by ''gathering'' all the unique messages from branch PO files, i.e. the ''summit'' of branch POs. Assuming that branch POs were not all that different, since they are two versions of the same catalog, the summit PO shouldn't have much more messages than either. Translators at all times work on the summit PO, from which the messages are periodically ''scattered'' back to original branch POs. Thus, translators can always work on summit POs, not having to do any parallel translation, branch switching or porting of fixes. The summit workflow is presented by the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_summit.png|center|Translation in summit]]&lt;br /&gt;
&lt;br /&gt;
In the summit mode, repository automation gathers summit PO templates from branch templates, and stores them separately from real branches, at {{path|trunk/l10n-support/templates/summit/}}. The language team also has a collection summit POs, at {{path|trunk/l10n-support/LANG/summit/}}, which is the sole location where translation happens. As before, repository automation handles merging of templates in branches, but merging of summit POs is done by the team coordinator; team coordinator can opt to manually merge branch POs as well (more on why-and-how of this later). From time to time, the team coordinator fills out branch POs by scattering from summit. Not to worry, each of these special actions upon the team coordinator is done with a single command.&lt;br /&gt;
&lt;br /&gt;
While it is in principle obvious that two branch POs can be made into one summit PO with the union of their messages, there are some important details that should be handled the right way by the summitting system:&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes modules in one branch, so that it no longer belongs to the same module in both branches (e.g. application is moved from one to another module in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes its name in one branch, but not in the other (e.g. application is renamed in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO in one branch is split into two POs in another (e.g. extracting a library out of monolithic application in trunk)?&lt;br /&gt;
&lt;br /&gt;
* Where to place messages unique to one branch in the summit PO? The original file context of a message, which messages precede it and which follow it, should be kept as much as possible.&lt;br /&gt;
&lt;br /&gt;
* If source references are used to achieve good ordering of messages in summit PO, what to do if some source file paths change in one branch (e.g. application gets restructured in trunk)?&lt;br /&gt;
&lt;br /&gt;
* How to handle messages with different plurality across branches (since messages are identified only by their &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, an not &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt;)?&lt;br /&gt;
&lt;br /&gt;
And handle these details it does, the present summitting system. This also means that teams working in the summit need not take care of the first three issues above, which are affecting manual branch handling too.&lt;br /&gt;
&lt;br /&gt;
Summit POs are normal, fully valid POs in their own right. A message in a summit PO is different from branch PO only by being equipped with another comment, &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt;, showing in which branches the message exists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgctxt &amp;quot;The destination url of a job&amp;quot;&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:517&lt;br /&gt;
msgid &amp;quot;&amp;amp;Keep this window open after transfer is complete&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first message above thus exists in trunk only, the second in stable only, and the third in both branches. The source reference always points to the source file in the first listed branch. Any extracted comments (&amp;lt;tt&amp;gt;#.&amp;lt;/tt&amp;gt;) other than the branch list are also taken from the first listed branch.&lt;br /&gt;
&lt;br /&gt;
Note that the two messages above are different only by context; the context was added in trunk, but not in stable, in order not to break message freeze. However, due to careful ordering of messages in summit POs, these two messages appear together, allowing translator to immediately make correction in stable branch too if the new context in trunk shows it to be necessary.&lt;br /&gt;
&lt;br /&gt;
=== Setting Up and Daily Operation ===&lt;br /&gt;
&lt;br /&gt;
Before initializing language summit, the team coordinator has to have all the necessary paths checked out from the KDE repository, and structured on the local machine exactly as in the repository. If the path to the root of KDE repository on the local machine is &amp;lt;tt&amp;gt;$KDEREPO&amp;lt;/tt&amp;gt;, and the language code &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt;, then the structure should be as follows, with leaf directories checked out in full:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            scripts/&lt;br /&gt;
            pology/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                templates/&lt;br /&gt;
                LANG/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that this structure is fully under version control (rather than e.g. top directories being manually created), so if that is not the case, the following commands will fetch everything anew in proper order:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd $KDEREPO&lt;br /&gt;
svn co --depth=empty svn+ssh://svn.kde.org/home/kde .&lt;br /&gt;
svn up --depth=empty branches branches/stable branches/stable/l10n-kde4&lt;br /&gt;
svn up --depth=empty trunk trunk/l10n-support trunk/l10n-kde4&lt;br /&gt;
svn up branches/stable/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the trailing dot in the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command, and do not miss to substitute LANG for the real language code in the last three commands. &amp;lt;tt&amp;gt;--depth=empty&amp;lt;/tt&amp;gt; option prevents recursive fetching, so that e.g. the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command does not fetch the complete repository tree. Later you can regularly update this tree with single command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
svn up $KDEREPO/{trunk,branches/stable}/l10n-kde4/{scripts,templates,LANG} \&lt;br /&gt;
       $KDEREPO/trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Summit operations are performed using the &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; command, which is part of [[Localization/Tools/Pology|Pology]], residing in {{path|trunk/l10n-support/pology/}}. Therefore the first thing to do is to setup Pology, which amounts only to setting the proper path:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ export PATH=$KDEREPO/trunk/l10n-support/pology/bin:$PATH&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To initialize the summit, by gathering from existing translation in branches, the team coordinator executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Depending on the amount of translation, after some minutes the initial gathering will have been completed, and language summit located under {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages/}}. This is the only time when the coordinator performs the gather operation on language POs; it is daily done only on templates by repository automation. Then, the created language summit should be merged with current summit templates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Merging the summit is something that the coordinator does periodically, with frequency of own desire. For example, it can be done daily, or with increasing frequency as the last day for translation for the next release approaches.&lt;br /&gt;
&lt;br /&gt;
After the first merging, language summit is ready for active translation. The coordinator should now commit {{path|$KDEREPO/trunk/l10n-support/LANG/}}, and, importantly, notify team members to stop working on branch POs and focus exclusively on summit POs.&lt;br /&gt;
&lt;br /&gt;
To scatter the summit, i.e. fill out POs in stable and trunk branch from the summit POs, the coordinator periodically executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As with merging, there is no fixed schedule when scattering should be done. Of course, it must necessarily be done before the next release is tagged, and in between it is useful to scatter for runtime testing, or to have translation statistics by branches on l10n.kde.org up to date.&lt;br /&gt;
&lt;br /&gt;
Periodic scattering and merging of the complete summit are basically all that a language team coordinator needs to do specifically to operate the summit. Also, since {{path|l10n-support/scripts/}} and {{path|l10n-support/pology/}} contain scripts and settings critical for proper functioning of summit operations, and may be tweaked at any time, they should always be updated from the repository together with PO files and templates (in fact, it is best to always update at once the whole tree as outlined above).&lt;br /&gt;
&lt;br /&gt;
{{note|For documentation POs, summit setup and operation is the same, only replacing every &amp;lt;tt&amp;gt;messages&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;docmessages&amp;lt;/tt&amp;gt; in the command lines above. The user interface and documentation summits are fully independent, so for a trial period it is reasonable to work with the interface summit only, and engage documentation summit once the trial has been deemed successfull.}}&lt;br /&gt;
&lt;br /&gt;
=== Operation Targets ===&lt;br /&gt;
&lt;br /&gt;
Sometimes it is advantageous to merge or scatter just a single catalog, a single module, a single branch, or any combination thereof. To this end, scatter and merge operations accept any number of ''operation targets'' after the operation keyword, specified as one of &amp;lt;tt&amp;gt;''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''MODULE''/&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''MODULE''/&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;''BRANCH'':&amp;lt;/tt&amp;gt;. For example, to scatter just to Dolphin's PO in stable branch, in order to test translation at runtime, one would execute:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(note no &amp;lt;tt&amp;gt;.po&amp;lt;/tt&amp;gt; ending on catalog name). Or, to scatter to every PO in &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; module in stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:kdeplasma-addons/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the trailing slash is mandatory, or else &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; would think that &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; is a catalog name). Finally, to scatter to all catalogs in the stable branch (with the trailing colon for the same reason as earlier):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command line arguments of &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; operations are intentionally arranged such that all the arguments fixed for one language are placed first. If operation targets are used frequently, then it is convenient to place the immutable part of the command line under a shell alias, with absolute path to the summit setup file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ alias posummit-kde-LANG=&amp;quot;posummit $KDEREPO/trunk/l10n-support/scripts/messages.summit LANG&amp;quot;&lt;br /&gt;
$ cd ANYWHERE&lt;br /&gt;
$ posummit-kde-LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Externally Injected Branch Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Once the summit is in operation, normally the only way for a catalog to appear in branches (trunk or stable) is through scattering from the summit. However, sometimes an application which had seen considerable development outside of the infrastructure of KDE project gets moved in, drawing in any of its existing translations into branches. Such externally injected branch catalogs cause warnings to be issued on summit scattering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/foobar.po  # dummy injection&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/libfoobar.po  # dummy injection&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
posummit: [warning] Some branch catalogs have no associated summit catalog (expected summit path given):&lt;br /&gt;
... ../l10n-kde4/sr/messages/kdetoys/foobar.po --&amp;gt; sr/summit/messages/kdetoys/foobar.po&lt;br /&gt;
... ../l10n-kde4/sr/messages/kdetoys/libfoobar.po --&amp;gt; sr/summit/messages/kdetoys/libfoobar.po&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When this happens, the injected catalogs need to be gathered into the summit. This is done just like the initial gathering, only giving injected catalogs' names as operation targets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force foobar libfoobar&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Summit Customization ===&lt;br /&gt;
&lt;br /&gt;
File {{path|scripts/messages.summit}} (i.e. {{path|$KDEREPO/trunk/l10n-support/scripts/messages.summit}}), given as first argument to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, contains the general summit setup for all languages. This file is set to include customization file per language, if it exists at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages.extras.summit}}, which contains additions and overrides to the general setup as desired by the language team. Same as the general setup file, the customization file is a Python source. It uses an external object named &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; to define summit settings, and can, of course, contain any helper Python code (the file is executed only once, at the beginning of a &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; run). It has the following general layout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# -*- coding: UTF-8 -*-&lt;br /&gt;
# kate: syntax Python;&lt;br /&gt;
# This file is included by scripts/messages.summit&lt;br /&gt;
# for language-specific additions/overrides.&lt;br /&gt;
#&lt;br /&gt;
# ...&lt;br /&gt;
# ... operations with object S and other Python code ...&lt;br /&gt;
# ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Object &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; provides both data attributes and methods to configure different aspects of summit operation. For example, while the general setup specifies that text fields in summit catalogs should not be wrapped on column but should be wrapped on logical breaks (like some markup tags), this can be overriden using &amp;lt;tt&amp;gt;summit_wrap&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;summit_fine_wrap&amp;lt;/tt&amp;gt; attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
S.summit_wrap = True&lt;br /&gt;
S.summit_fine_wrap = False&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, to get the path to a file relative to the summit customization file itself (rather than to current working directory, where &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; was executed), method &amp;lt;tt&amp;gt;resolve_path_rooted&amp;lt;/tt&amp;gt; can be used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
relpath = S.resolve_path_rooted(&amp;quot;../whatever.txt&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following sections will present some typical customization possibilities.&lt;br /&gt;
&lt;br /&gt;
=== Fully Local Merging ===&lt;br /&gt;
&lt;br /&gt;
When scattering from the summit, sometimes there will be reports of &amp;quot;messages missing in the summit&amp;quot;. This happens because of time rift created by the Scripty merging branch POs, gathering summit templates, and a team coordinator merging the language summit, thus making some messages in branch POs not always present in the summit. This condition is benign, as such warnings will start to disappear with the message freeze approaching, but can be annoying. For this reason, team coordinator can stop Scripty from merging branch POs, and have the &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; command alone merge not only summit POs, but stable and trunk POs as well, such that summit and branches are always in perfect sync.&lt;br /&gt;
&lt;br /&gt;
First, to stop Scripty from merging branch POs, a file named &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; (with arbitrary content) should be committed to the roots of respective trees, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$ touch $KDEREPO/trunk/l10n-kde4/messages/LANG/no-auto-merge&lt;br /&gt;
$ touch $KDEREPO/branches/stable/l10n-kde4/LANG/messages/no-auto-merge&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, to make summit &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; merge everything, the following lines should be added into the summit customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Set local merging for all branches.&lt;br /&gt;
for branch in S.branches:&lt;br /&gt;
    branch[&amp;quot;merge_locally&amp;quot;] = True&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once local merging of all branches is set, the coordinator can also use operation targets for selective merging, e.g. to merge only stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge stable:&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Merging with Compendium ===&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; takes into account only the catalog itself to fill out near-match translations to new messages introduced by merging. i.e. to produce fuzzy messages. However, an arbitrary PO file can be given to &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; as another possible source of earlier translations, through the &amp;lt;tt&amp;gt;--compendium&amp;lt;/tt&amp;gt; option. For maximum effect, this PO file is usually constructed as the collection of messages from all PO files project-wide, and hence called the ''compendium''.&lt;br /&gt;
&lt;br /&gt;
Compendium can be used in summit merge operations simply by setting &amp;lt;tt&amp;gt;compendium_on_merge&amp;lt;/tt&amp;gt; attribute in summit customization file. If the compendium is located at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages-compendium.po}}, then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Compendium to use when merging summit catalogs.&lt;br /&gt;
S.compendium_on_merge = S.resolve_path_rooted(&amp;quot;messages-compendium.po&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that if not located as above, compendium should not be placed within {{path|.../LANG/summit/messages/}}, as then it would be considered a summit catalog itself. In case fully local merging is engaged, only summit POs will be merged with compendium; it makes no sense for branch POs, since they are not being directly translated.&lt;br /&gt;
&lt;br /&gt;
See [http://www.gnu.org/software/automake/manual/gettext/Creating-Compendia.html &amp;quot;Creating Compendia&amp;quot;] section of Gettext manual for details on how to create a compendium out of current body of summit translations. Once you establish the precise commands to create the compendium (whether to collect fuzzies too, whether to include old compendium as one of sources for the new, etc.), you would periodically refresh and commit the updated compendium.&lt;br /&gt;
&lt;br /&gt;
=== Vivifying Summit Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Translation of a summit catalog normally starts the same way as it did for branch catalogs, by copying it over from template and initializing the header. This can be done manually, but it can also be quite automatic when using project manager as sometimes provided by dedicated PO editors. However, relying on the editor's project manager can be disadvantageous at times. For example, aside from the PO editor, other, frequently command line tools may be used to process the body of translation, and these tools might need to consider non-started templates as if they were empty POs (e.g. statistics). Team members who do not have full local checkout, or no project set up in the editor, may need to jump between language and template directories when looking for files to translate.&lt;br /&gt;
&lt;br /&gt;
Therefore, summit setup can be customized to automatically create (&amp;quot;vivify&amp;quot;) summit catalogs for every new summit template, so that there is never the need (for a tool or human) to specifically treat templates as empty catalogs. This is done by adding the following lines into customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Create empty summit catalog for every new summit template.&lt;br /&gt;
S.vivify_on_merge = True&lt;br /&gt;
S.vivify_w_translator = &amp;quot;Noone Noonian &amp;lt;noone.noonian@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_langteam = &amp;quot;Neverneese &amp;lt;neverteam@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_plurals = &amp;quot;nplurals=2; plural=n != 1;&amp;quot;&lt;br /&gt;
# Minimum translation state to create branch catalog on scatter.&lt;br /&gt;
S.scatter_min_completeness = 0.9&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;vivify_w_*&amp;lt;/tt&amp;gt; attributes set the necessary data to initialize headers of newly created summit catalogs. Aside from those listed above, there is also the &amp;lt;tt&amp;gt;vivify_w_charset&amp;lt;/tt&amp;gt; attribute, which is by default &amp;lt;tt&amp;gt;&amp;quot;UTF-8&amp;quot;&amp;lt;/tt&amp;gt;, and very probably should not be changed.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; attribute does not refer to vivification of summit catalogs, but should invariably be set in this context. When scattering from summit, normally the branch catalog is automatically created if there is the corresponding summit catalog. When vivification is engaged, this would result in creation of empty branch catalogs too, which is not desired for two reasons. Firstly, empty branch catalogs would become part of the released language pack, for which there is no practical reason. Secondly, KDE's i18n system regards an application with installed catalog as translated, so messages coming from basic system catalogs (e.g. &amp;lt;tt&amp;gt;kdelibs4&amp;lt;/tt&amp;gt;) would show through, resulting in mostly untranslated user interface with specks of translation -- many users consider this rather ungainly. Therefore, &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; sets how complete the translation of currently non-existing branch catalog should be after scatter (0.0 empty, 1.0 fully complete), for the branch catalog to actually be created. If the &amp;lt;tt&amp;gt;--force&amp;lt;/tt&amp;gt; option is given to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, the branch catalog will be created regardless of its translation state, which may be handy in combination with [[#Operation Targets|operation target]] when wanting to check work in progress in running application.&lt;br /&gt;
&lt;br /&gt;
If [[#Merging with Compendium|the compendium has been set]] for merging, every vivified summit catalog will also be merged against the compendium, to fill out as many of messages with approximate translations.&lt;br /&gt;
&lt;br /&gt;
=== Scatter Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Checks, modifications...))&lt;br /&gt;
&lt;br /&gt;
=== Merge Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Special header fields...))&lt;br /&gt;
&lt;br /&gt;
== Disadvantages to Summit and Remedies ==&lt;br /&gt;
&lt;br /&gt;
Although hopefully shadowed by the advantages, working in summit is not without its disadvantages. These should be weighed when deciding of whether to try out the summit workflow.&lt;br /&gt;
&lt;br /&gt;
Obviously, while summit operations are made to be quite automatic, some extra aptitude is asked of the team coordinator. Reasonable shell handling, understanding of version control operations, feeling the pulse of repository automation, are all prerequisites, and some scripting ability advantageous.&lt;br /&gt;
&lt;br /&gt;
After the summit is put in operation, any changes made manually in branch POs will not propagate to summit, and will be soon lost to scattering -- summit translations override everything in branches. This means that the whole team must work in the summit, it is not possible for some members to use the summit, and some not.&lt;br /&gt;
&lt;br /&gt;
A summit PO file will necessarily have more messages than either of the branch files. For example, in the KDE 4.0/4.1 and 4.1/4.2 cycle, summit POs of core KDE modules had on average less than 5% more words than their stable counterparts. However, the said percent is the top, never approached limit of wasted workload due to trunk messages coming and going, given that as the next feature KDE release approaches, more and more trunk messages will find their way into it.&lt;br /&gt;
&lt;br /&gt;
Another, more pressing issue with increased size of summit POs is the following scenario: a stable release is around the corner, and the team has no time to update summit POs fully, but could update only stable messages in them. E.g. there are 1000 untranslated and fuzzy messages, out of which only 100 are from the stable branch. A clever dedicated PO editor could allow jumping only through untranslated and fuzzy messages which also satisfy a general search criteria, which in this case would be that a comment matches &amp;lt;tt&amp;gt;#\.\+&amp;gt;.*stable&amp;lt;/tt&amp;gt; regular expression. On the other hand, with some external help, it is enough if the PO editor can merely search through comments. Then, the &amp;lt;tt&amp;gt;posieve&amp;lt;/tt&amp;gt; command (ready to use next to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;) can equip untranslated and fuzzy stable messages with &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag (producing &amp;lt;tt&amp;gt;#, ..., untranslated&amp;lt;/tt&amp;gt; comment), and this flag can be searched for in the PO editor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ posieve tag-untranslated -sbranch:stable -swfuzzy PATHS_TO_PO_FILES_OR_DIRS&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag does not need to be manually removed when the message is updated. It will automatically disappear on the next merge, as it is not among flags known to Gettext.&lt;br /&gt;
&lt;br /&gt;
If an automatic source lookup mechanism (to check the message context by following its source references) was available for branches, it may not entirely work for summit. Already the branch POs in KDE are kept separate from the code, which means that paths given by source references cannot be followed directly, but appropriate root paths have to be added in some way (a dedicated PO editor may provide a way to do this); this should continue to work with summit for those messages which exist both in trunk and stable branch, since their source references correspond to trunk code. But for messages found only in stable branch, whose source references correspond to stable code, existing source lookup mechanism will likely assume trunk roots again, and try to fetch wrong sources. To fix this, the source lookup mechanism should be flexible enough to select roots based on branch keywords given in summit messages' &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt; comment.&lt;br /&gt;
&lt;br /&gt;
There is also the organizational issue with starting to use the summit, and, if it does not help as expected, stopping to use it. Team members have to be reminded to not send in branch POs at start, and then to be sent back to branch POs if summit is disbanded. On the plus side, disbanding summit is technically simple: just remove from the repository {{path|l10n-supprot/LANG/summit}}, possibly also &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; files if [[#Fully Local Merging|fully local merging]] was set up, and that is it.&lt;br /&gt;
&lt;br /&gt;
== Another Way to Improve Branch Handling ==&lt;br /&gt;
&lt;br /&gt;
If summit seems a lot to digest, or is simply an overkill for team's needs, but still some improvement to manual handling of branches would be welcomed, KDE's dedicated PO editor [[Localization/Tools/Lokalize|Lokalize]] offers a ''branch sync'' mode. It works as follows.&lt;br /&gt;
&lt;br /&gt;
In Lokalize project definition, the local paths of trunk and stable PO roots are set in ''Translation directory:'' and ''Branch directory:'' fields. Then, when a trunk PO file is opened, if it has a stable counterpart with same name and location as in the trunk, this stable PO is also going to be opened. For each trunk message in the main editing pane, if such a message exists in stable PO too, the stable message will be shown in the ''Secondary Sync'' pane; changes in the translation of trunk message will reflect to the stable message, and stable PO file will also be saved when the trunk is saved.&lt;br /&gt;
&lt;br /&gt;
Furthermore, any team member can personally choose to work like this, there is no need to change the workflow of the language team as whole. When sending modifications to the coordinator, team members who rely on this feature of Lokalize simply send both trunk and stable POs that got modified.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization</id>
		<title>Localization</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization"/>
				<updated>2011-11-26T12:35:57Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Modified description of Pology.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization}}&lt;br /&gt;
&lt;br /&gt;
''Welcome, adventurer, to the universe of KDE localization! Brought along a generous reserve of breathing air?''&lt;br /&gt;
&lt;br /&gt;
{{warning|This assembly of articles is intended to become the central source on localization of KDE, but is far from being there yet. In the meantime, the authoritative body of documentation (albeit in parts outdated) is the [http://l10n.kde.org/docs/translation-howto KDE Translation Howto].}}&lt;br /&gt;
&lt;br /&gt;
== The Milky Way ==&lt;br /&gt;
&lt;br /&gt;
This page is the hub of articles on all things concerning localization of KDE. The topics covered are intended to detail facts, issue advice and satisfy curiosity about KDE localization ways. And to do so for &amp;quot;all audiences&amp;quot;: from newly interested in free software localization, over those more experienced seeking to get involved into KDE localization, to veteran KDE translators curious about new developments.&lt;br /&gt;
&lt;br /&gt;
To achieve this aim, the topics are by necessity not structured linearly. When you read a textbook, in the introduction you can frequently find authors' instructions on how to &amp;quot;follow&amp;quot; the book: possible coherent chains of chapters, which chapter is a prerequisite for another, and which optional. So is with the topics presented here, taken to the extreme, with many entry and exit points depending on individual interests.&lt;br /&gt;
&lt;br /&gt;
The hub currently connects three spiralling arms of topics:&lt;br /&gt;
&lt;br /&gt;
; [[#Concepts|Concepts]] : Expositions of widespread concepts in free software localization in general and KDE localization in particular. General mechanics and formats, advanced technical possibilities, organization and communication processes.&lt;br /&gt;
&lt;br /&gt;
; [[#Tools|Tools]] : Descriptions of tools which may benefit the localization process, from command line scripts to full-featured GUI applications. Their possible roles in support of localization concepts.&lt;br /&gt;
&lt;br /&gt;
; [[#Workflows|Workflows]] : Instructions and procedures on how to contribute to KDE localization, on various levels of engagement. What are the need-to-know concepts in different scenarios, and which tools are appropriate to carry them through.&lt;br /&gt;
&lt;br /&gt;
{{tip|If you are fresh in the trade, do not feel intimidated by the expanse. Not even crack KDE translators are supposed to be intimately acquainted with, or need all this stuff. Instead, if you are eager to start churning out results, head to the [[Localization/Workflows/Rookie|rookie workflow]] and follow the leads therein.}}&lt;br /&gt;
&lt;br /&gt;
=== Note to Editors ===&lt;br /&gt;
&lt;br /&gt;
It is important to correctly place certain bits of information in the localization universe. The reader should be made aware of what is a local KDE convention, what a special feature of the tool they use, and what a general concept and its embodiment in specific KDE context.&lt;br /&gt;
&lt;br /&gt;
While this is obviously a KDE-focused resource, it is nevertheless useful to provide examples of how some elements are handled outside of KDE. Through contrast and comparison, the reader may better understand the whys and hows of presented material. Likewise, it may help those already familiar with other localization environments.&lt;br /&gt;
&lt;br /&gt;
== Concepts ==&lt;br /&gt;
&lt;br /&gt;
For better or for worse, there is no lack of frameworks, formats, procedures and other vague notions that a KDE translator may stumble upon along the way. They may be a burden of sorts -- many things to keep in mind -- but also a source of fun, challenge, and deep satisfaction when creatively combined towards great efficiency of everyday work and mirror-perfect polish of the final output. Thus, expect the articles here not to withold much.&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Encodings|Text Encoding]]&lt;br /&gt;
: ''Text is the most basic object of localization. However, to handle it at low level -- to encode text -- such that languages of the world are smoothly supported, was historically not trivial. Read about the current standards, proper setups and errors due to text encoding which may pop up.''&lt;br /&gt;
&amp;lt;!-- write about: use UTF-8, set locale, visible errors --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/PO_Odyssey|The PO Format]]&lt;br /&gt;
: ''The PO format is the mainstay of free software translation. Ragardless of the actual workflows and tools used, translators should maintain a good measure of familiarity with the underlying PO format. This article thoroughly describes the elements of the PO format and various uses of PO catalog files which embody it.''&lt;br /&gt;
&amp;lt;!-- write about: dynamic, static, detailed story --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/XML_Markup|XML Markup]]&lt;br /&gt;
: ''Parts of text are sometimes presented to the user in special way: bold or italic, title sized, etc. XML-like text markup is a popular way of specifying such presentation, and translators will frequently find it embedded in the source texts. This article deals with XML markup from translators' viewpoint.''&lt;br /&gt;
&amp;lt;!-- write about: xml-markup: well-formedness, visual vs. semantic, types (HTML, KUIT, Docbook), phony --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Version_Control|Version Control]]&lt;br /&gt;
: ''KDE evolves by integrating a lot of work contributed by a lot of people scattered around the planet, and that along parallel lines of development. To prevent information collapse into the gravity well of unhindered creativity, programmers employ version control systems -- and so do the translators.''&lt;br /&gt;
&amp;lt;!-- write about: concept, terminology, branches, freezes, anon, account --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Communication|Rings of Communication]]&lt;br /&gt;
: ''Translators have many communication outlets at their disposal. Beyond the circle of one's own language team, translators from other teams and programmers are orbiting close at reach. Find out which issues are best dealt with at which level, for the time spent in constructive discussion to achieve most positive impact.''&lt;br /&gt;
&amp;lt;!-- write about: team-internal, bad i18n, needed contexts; kde-i18n-doc, irc, bug reps --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Auto_Assists|Automatic Translation Assists]]&lt;br /&gt;
: ''Automatic assists help translators to speed up the work, avoid common errors, and achieve consistency in style and terminology. They may be provided as standalone tools, or as features of specialized translation tools. These assists include spell checkers, glossaries, translation memories, etc.''&lt;br /&gt;
&amp;lt;!-- write about: spell/gram check, glossary, translation memory, online corpuses; examples of apps/sites which provide them --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Statistics|Collecting and Using Statistics]]&lt;br /&gt;
: ''Statistics provide overall indicators of the past localization progress, and means to extrapolate for the future. However, as always with statistics, for meaningful conclusions they should be used with care. Read about the sources of statistics, things to count, and effort estimates.''&lt;br /&gt;
&amp;lt;!-- write about: what and how to count, online (l10n.kde.org), workload assesment, branches --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Doc_Translation|Translating Documentation]]&lt;br /&gt;
: ''Compared to localizing application interfaces, translating their documentation both throws new elements into the fray, and casts others in a different light. The need to keep the interfaces and documentation in sync, demands another layer of attention. This article covers those peculiarities.''&lt;br /&gt;
&amp;lt;!-- write about: DocBook, XML-POT-PO roundtrip, building translated XML, custom entities, consistence with UI --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Non_Latin_Alpha_LTR|Writing Systems Distinctions]]&lt;br /&gt;
: ''User interfaces have been historically centered and developed around alphabetic writing system, using Latin alphabet, and written from left to right. Drastic changes to any of these assumptions, such as right to left writing or using ideographs instead of alphabet, requires some consideration.''&lt;br /&gt;
&amp;lt;!-- write about: non-Latin, RTL, CJK; accelerators, input --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Locales|Language/Country Specific Formats]]&lt;br /&gt;
: ''Applications frequently process and display pieces of information which, while universal in concept, are presented differently accros cultures: time and dates, numbers, calendars, and so on. KDE apps gracefully handle such differences, relying on the language/country-based specifications in the KDE core.''&lt;br /&gt;
&amp;lt;!-- write about: libc locales, KDE locales (editing l10n/runtime/ctry/...), KLocale::format* placeholders --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/KDE_Special_Messages|Special Entries in Translation Catalogs]]&lt;br /&gt;
: ''Most messages in translation catalogs are ordinary text intended for the user, but some are not. Programmers may use messages which let translators choose behavior for their language, add language-specific data, or state translation credits. Such special entries typically found in KDE catalogs are described here.''&lt;br /&gt;
&amp;lt;!-- write about: &amp;quot;...TRANSLATOR...&amp;quot;, behavior questions, stuff in kdelibs4.po (RTL, brown fox, KUIT patterns, kb.keys), filters --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Transcript|Translation Scripting with Transcript]]&lt;br /&gt;
: ''Traditional UI translation frameworks are based on English as the pivotal language. This frequently leads to technical problems in target languages, where translators may be forced to choose between bad and worse. To alleviate such issues, KDE provides a way to act on translation at runtime -- the Transcript engine.''&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Concepts/Non_Text_Resources|Localizing Non-Text Resources]]&lt;br /&gt;
: ''While the first thought of localization is that of text translation, text is not the sole resource for localization. Any content presented to the user -- an icon, image, sound -- may require localization in certain cultural contexts. Learn how to localize non-text resources in KDE as the need arises.''&lt;br /&gt;
&amp;lt;!-- write about: lbundles, ll/data/... structure, out-of-source, in-source --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
&lt;br /&gt;
Great many tools exist to support the localization process. Some may be quite general, and other tightly coupled with KDE localization process. Tools are thus presented in different ways. More general tools typically have referent documentation of their own, and here it is explained how they relate to concepts and workflows used in KDE. Custom, KDE-specific tools are explained in greater detail, sometimes to the point of these articles being their referent documentation.&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Tools/Gettext_Tools|Gettext Tools]]&lt;br /&gt;
: ''GNU Gettext is the de-facto referent implementation of the PO format. It is used to extract templates from the code and update PO catalogs, and has many tools for processing PO files. Its compiler of PO format into binary format for application use, is the final arbiter of validity of a PO file.''&lt;br /&gt;
&lt;br /&gt;
; [http://userbase.kde.org/Lokalize Lokalize]&lt;br /&gt;
: ''[http://userbase.kde.org/Lokalize Lokalize] is a computer-aided translation (CAT) tool, a full-featured GUI application for translators, written from scratch using KDE4 framework. Aside from basic editing of PO files with nifty auxiliary details, it integrates support for glossary, translation memory, diff-modes for QA, project managing, etc.''&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Tools/Emacs_and_Vim|Emacs &amp;amp; Vim]]&lt;br /&gt;
: ''Emacs and Vim are ubiquitous Unix text editors, in continuous use and development from times immemorial. Both very different from today's typical editors, as well as between each other, powerfull and extendable, they have been pressed into many roles. One is power-assisted editing of PO files.''&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Tools/Translate_Toolkit|Translate Toolkit]]&lt;br /&gt;
: ''Translate Toolkit is a host of command-line utilities, written mostly in Python, that expands and extends on Gettext's tools. They provide advanced search, selection and merging of PO files, and environment-specific validity checks. Also included are converters between various non-PO formats.''&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Tools/Subversion|Subversion]]&lt;br /&gt;
: ''Subversion, SVN for short, is the version control system currently used by the KDE project as whole. Same as the code, KDE localization data are stored in the central SVN repository. This article describes the use cases of Subversion for translators, as well as repository organization of localized data.''&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Tools/Pology|Pology]]&lt;br /&gt;
: ''Pology is a Python library and a set of command-line tools for processing PO files. The tools perform various specialized operations on PO files, some of which have explicit support for PO files within the KDE Translation Project. The library is geared towards quick and robust assembly of &amp;quot;field&amp;quot; scripts for processing PO files, in a version-controlled environment.''&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Tools/Lbundle_Check|Lbundle Checker]]&lt;br /&gt;
: ''For text resources translated through PO files there are well-established means of tracking changes as the underling code evolves. This is the script to provide a degree of such support for localized non-text resources, when organized as localization bundles.''&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Tools/Misc_Scripts|Miscellaneous Scripts]]&lt;br /&gt;
: ''KDE repository contains many standalone scripts to check and process localized data, of various degrees of specificity -- many even tied to the exact repository organization. Collected here are the descriptions of such scripts which may be generally useful to translators.''&lt;br /&gt;
&lt;br /&gt;
== Workflows ==&lt;br /&gt;
&lt;br /&gt;
There is no single way to participate in KDE localization. Contributors will differ by the amount and direction of effort they put in, and the workflow articles are here to provide guidance for the frequently observed roles. Also presented are the technical and organizational details which have tidal influence on everyday translator's workflow.&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Workflows/Rookie|Rookie Translator]]&lt;br /&gt;
: ''This is your first forray into localization and you're looking for the sign saying &amp;quot;Don't Panic&amp;quot;, in large friendly letters? Find about the essential prerequisites to start translating early, but productively.''&lt;br /&gt;
&amp;lt;!-- write about: what to read, which tools, contacting coordinators, where to ask questions, netiquette --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Workflows/Translator|Seasoned Translator]]&lt;br /&gt;
: ''Translators that have surmounted the difficulties and acquired the concepts and tools for the work to become daily routine, may start looking into new directions. How to better coordinate effort, cooperate with other language teams, test the localization quality in live environment, etc.''&lt;br /&gt;
&amp;lt;!-- write about: communication (errors, contexts), coordination, inst. KDE from sources, testing translation --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Workflows/Coordinator|Language Coordinator]]&lt;br /&gt;
: ''Each language team in KDE needs one or few persons tasked additionally to their basic work on localization. They take care that the team effort progresses smoothly, and voice their teams in global matters. Language coordinators have write-access to KDE repository, and the responsibility to boot.''&lt;br /&gt;
&amp;lt;!-- write about: VCS account, mailing list, working on which branch, monitoring commits, building docs, QA --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Workflows/Overlord|Global Coordinator]]&lt;br /&gt;
: ''While the cooperation can and does take place between translators from different language teams, more focused attention is needed to handle some global issues. To that end, some translators engage in maintenance tasks on wider scale, and one of them is appointed the KDE Localization Coordinator.''&lt;br /&gt;
&amp;lt;!-- write about: catalog moves, freezes, log monitoring, announcements --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Workflows/New_Language|Introducing a New Language]]&lt;br /&gt;
: ''Great many languages are already being localized into within KDE project. Sometimes, however, a new language is to be introduced, which requires coordination between its translators and core KDE team. Also, to ship a language as part of official KDE release, some essentials must be satisfied.''&lt;br /&gt;
&amp;lt;!-- write about: essentials, add to stats, to KCM locale --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Workflows/Repository_Automation|Repository Automation]]&lt;br /&gt;
: ''Daily in the KDE repository, the lumbering machinery scrutinizes code, updates translations to reflect changes, performs checks, serving the results to translators. Learn to follow its hum, and know where to grease when the gears clog.''&lt;br /&gt;
&amp;lt;!-- write about: Scripty the Beast from start to end, script by script; template extraction, desktop files, doc -&amp;gt; POT, logs, i18n code checks --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Workflows/PO_Summit|Translating in Summit]]&lt;br /&gt;
: ''Handling two branches for translation, stable and trunk, can be tedious. Porting fixes from one to another branch, making sure team members work on correct branch, etc. Especially so when non-core modules are considered, like extragear. Read about one possibility to curb this overhead.''&lt;br /&gt;
&lt;br /&gt;
; [[Localization/Workflows/PO_Ascription|Reviewing by Ascriptions]]&lt;br /&gt;
: ''It is essential for quality that translations are reviewed: for context, terminology, grammar, style, etc. Given text is normally reviewed by persons other than its translator, which prompts the question of how to coordinate and track reviewing. This article presents the ascription system of reviews, building on the summit workflow.''&lt;br /&gt;
&lt;br /&gt;
[[Category:Localization]]&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Tools/Pology</id>
		<title>Localization/Tools/Pology</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Tools/Pology"/>
				<updated>2011-11-26T12:31:26Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Links to other Pology-related articles.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Tools/Pology}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Tools|Tools]]|&lt;br /&gt;
name=Pology|&lt;br /&gt;
prereqs=[[Localization/Tools/Gettext_Tools|Gettext Tools]]|&lt;br /&gt;
related=[[Localization/Tools/Pology/PO_Embedded_Diffing|PO Diffing]], [[Localization/Workflows/PO_Summit|Summiting Translation Branches]], [[Localization/Workflows/PO_Ascription|Review by Ascription]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== About ==&lt;br /&gt;
&lt;br /&gt;
Pology is a Python library and a set of command-line tools for processing PO files. The library aims to enable easy, fast and robust creation of scripts for tackling problems encountered in the &amp;quot;field&amp;quot;, in everyday translation work. The tools perform various specialized operations, beyond that of other PO-handling software. Some of the tools are designed to (or have provisions to) treat a collection of PO files as an entity unto itself.&lt;br /&gt;
&lt;br /&gt;
In Pology, no attempt is made to handle any other translation file format but PO. All of the end-user tools and library programming interfaces are geared towards the technical aspects, conventions and workflows around the PO format. For example, some tools explicitly take into account that PO files are frequently kept under version control, providing the functionality to support that workflow.&lt;br /&gt;
&lt;br /&gt;
Language- and project-specific support is present throughout Pology, and it is designed to be easily expanded in the future. In the context of KDE, for example, there is a tool for validating PO files within the KDE Translation Project: it will recognize the &amp;quot;role&amp;quot; of the particular PO file (e.g. a native KDE code PO file, a .desktop PO file, Docbook PO file...) and then apply checks appropriate for that role. (This tool is run weekly on KDE servers, on PO files of all languages, and results announced to &amp;lt;tt&amp;gt;kde-i18n-doc&amp;lt;/tt&amp;gt; mailing list.)&lt;br /&gt;
&lt;br /&gt;
Pology source distribution can be fetched from its home page at:&lt;br /&gt;
&lt;br /&gt;
 http://pology.nedohodnik.net&lt;br /&gt;
&lt;br /&gt;
The home page also links to on-line documentation (user manual and library API), and provides instructions for browsing or fetching the current development code.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Tools/Pology</id>
		<title>Localization/Tools/Pology</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Tools/Pology"/>
				<updated>2011-11-26T12:24:23Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: The content of this page is no longer actual. Instead, brief overview is given and links to Pology home page.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Tools/Pology}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Tools|Tools]]|&lt;br /&gt;
name=Pology|&lt;br /&gt;
prereqs=[[Localization/Tools/Gettext_Tools|Gettext Tools]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== About ==&lt;br /&gt;
&lt;br /&gt;
Pology is a Python library and a set of command-line tools for processing PO files. The library aims to enable easy, fast and robust creation of scripts for tackling problems encountered in the &amp;quot;field&amp;quot;, in everyday translation work. The tools perform various specialized operations, beyond that of other PO-handling software. Some of the tools are designed to (or have provisions to) treat a collection of PO files as an entity unto itself.&lt;br /&gt;
&lt;br /&gt;
In Pology, no attempt is made to handle any other translation file format but PO. All of the end-user tools and library programming interfaces are geared towards the technical aspects, conventions and workflows around the PO format. For example, some tools explicitly take into account that PO files are frequently kept under version control, providing the functionality to support that workflow.&lt;br /&gt;
&lt;br /&gt;
Language- and project-specific support is present throughout Pology, and it is designed to be easily expanded in the future. In the context of KDE, for example, there is a tool for validating PO files within the KDE Translation Project: it will recognize the &amp;quot;role&amp;quot; of the particular PO file (e.g. a native KDE code PO file, a .desktop PO file, Docbook PO file...) and then apply checks appropriate for that role. (This tool is run weekly on KDE servers, on PO files of all languages, and results announced to &amp;lt;tt&amp;gt;kde-i18n-doc&amp;lt;/tt&amp;gt; mailing list.)&lt;br /&gt;
&lt;br /&gt;
Pology source distribution can be fetched from its home page at:&lt;br /&gt;
&lt;br /&gt;
 http://pology.nedohodnik.net&lt;br /&gt;
&lt;br /&gt;
The home page also links to on-line documentation (user manual and library API), and provides instructions for browsing or fetching the current development code.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Concepts/Transcript</id>
		<title>Localization/Concepts/Transcript</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Concepts/Transcript"/>
				<updated>2011-08-18T07:56:25Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: New method: warnputs().&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Concepts|Concepts]]|&lt;br /&gt;
name=Translation Scripting with Transcript|&lt;br /&gt;
prereqs=[[Localization/Concepts/PO_Odyssey|The PO Format]]|&lt;br /&gt;
extread=[http://developer.mozilla.org/en/docs/JavaScript JavaScript Guide and Reference]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Translation Scripting? ==&lt;br /&gt;
&lt;br /&gt;
The current state of affairs in the localization of user-visible strings (messages) in application interfaces is such that the translator is sometimes forced to supply an inadequate translation. This problem typically occurs when a message contains a placeholder to be substituted at runtime, or when two unrelated strings become related by placement in the interface. In either case, the modest requirements of the English language on the congruence of words in a sentence allow the original string to remain grammatically correct, while in many other languages this is not the case.&lt;br /&gt;
&lt;br /&gt;
Translators and programmers sometimes try to work out a change in the code which would provide a more workable alternative. However, this process is difficult, and worse yet, the outcome is still language-dependent: solving the problem for a few languages does not necessarily solve it for all of them.&lt;br /&gt;
&lt;br /&gt;
One way to overcome these problems in a more general and compartmentalized manner is to provide translators with a way to modify translated strings at runtime, depending on the context (eg. particular placeholder substitutes). In other words, to script translation. The translator should be able to operate on any interface string he wishes, while the programmer should not bear any extra burden (or know about translation scripting at all).&lt;br /&gt;
&lt;br /&gt;
== The Transcript Engine ==&lt;br /&gt;
&lt;br /&gt;
KDE4 comes ready with a translation scripting system, called ''Transcript''. Several strategic choices were made in its design:&lt;br /&gt;
&lt;br /&gt;
* programmers are unaware of scripting, which means that translator can script any message without outside coordination&lt;br /&gt;
&lt;br /&gt;
* unless the translator wants to script a message, he is faced with the familiar standard Gettext PO environment (i.e. translators, too, can ignore scripting)&lt;br /&gt;
&lt;br /&gt;
* scripting is a low-level bolt-on to Gettext environment, to keep existing PO tools in the game&lt;br /&gt;
&lt;br /&gt;
* in order to be powerful enough for unforeseen needs, a general-purpose scripting language is provided: JavaScript (with extensions for interfacing with Transcript)&lt;br /&gt;
&lt;br /&gt;
{{note|For comparison, another translation scripting approach taking some different decisions (new translation environment down to the file format, scripting facilities more specialized, etc.) is brewing at http://wiki.mozilla.org/L20n}}&lt;br /&gt;
&lt;br /&gt;
To script a particular message, the translator writes short scripting calls into msgstr in the PO file which expand into parts of msgstr (''interpolations''), and JavaScript code which defines these calls into an accompanying Transcript module file (eg. {{path|foo.po}} can be augmented with {{path|foo.js}}).&lt;br /&gt;
&lt;br /&gt;
In case where the application draws translations from several PO files, scripting calls defined in one of the Transcript modules are available in all used PO files. Since every KDE app uses {{path|kdelibs.po}}, calls defined in {{path|kdelibs.js}} are available everywhere.&lt;br /&gt;
&lt;br /&gt;
The scripting process is illustrated by several examples. More detailed explanations of the elements are given in following sections.&lt;br /&gt;
&lt;br /&gt;
=== A Useless Example ===&lt;br /&gt;
&lt;br /&gt;
In Nevernessian it is impolite to speak a greeting with the same tone of voice throughout; instead, the name of the person must be shouted out. Hence, the translator wants to capitalize the placeholder substitute in the following login greeting in {{path|neverness.po}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#: neverness_login.cpp:10&lt;br /&gt;
msgid &amp;quot;Hello, %1!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Heelyy, %1!&amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So the translator adds a scripted msgstr, with an interpolation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
#: neverness_login.cpp:10&lt;br /&gt;
msgid &amp;quot;Hello, %1!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Heelyy, %1!&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;Heelyy, $[shout %1]!&amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first thing to note is that, while a bit longer, msgstr is still a proper PO msgstr, which means that it can be edited and processed by the usual PO tools.&lt;br /&gt;
&lt;br /&gt;
The first part of msgstr is same as before, and called the ''fallback'' in this context: if the scripted part happens to fail in some way, the fallback translation is used. The fallback is followed by the ''fence'' &amp;lt;tt&amp;gt;|/|&amp;lt;/tt&amp;gt;, which separates the fallback and scripted translation (and also indicates that this message is scripted).&lt;br /&gt;
&lt;br /&gt;
Finally, there is the scripted translation after the fence. It is different from the fallback in that it contains the interpolation &amp;lt;tt&amp;gt;$[shout %1]&amp;lt;/tt&amp;gt;, which is supposed to evaluate to a capitalized version of the placeholder substitute. It is composed of the call name, &amp;lt;tt&amp;gt;shout&amp;lt;/tt&amp;gt;, and one argument to it, the &amp;lt;tt&amp;gt;%1&amp;lt;/tt&amp;gt; placeholder which will be replaced by its substitute. The syntax and expansion rules for interpolations are similar to Unix shell.&lt;br /&gt;
&lt;br /&gt;
The call &amp;lt;tt&amp;gt;shout&amp;lt;/tt&amp;gt; itself is defined in the Transcript module {{path|neverness.js}}, which contains only these lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
function capitalize (str) {&lt;br /&gt;
    return str.toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Ts.setcall(&amp;quot;shout&amp;quot;, capitalize);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the function &amp;lt;tt&amp;gt;capitalize&amp;lt;/tt&amp;gt; is an ordinary JavaScript function which takes a string argument and returns all-caps version of it.&lt;br /&gt;
&lt;br /&gt;
The link with the PO file is established by the call to &amp;lt;tt&amp;gt;Ts.setcall()&amp;lt;/tt&amp;gt; -- the Transcript interface is represented by the property functions of the &amp;lt;tt&amp;gt;Ts&amp;lt;/tt&amp;gt; object. In this variant, the &amp;lt;tt&amp;gt;Ts.setcall()&amp;lt;/tt&amp;gt; takes the name of the call for the interpolations in the PO messages (a string), and the JavaScript function which will actually be invoked (''bound'' to the call).&lt;br /&gt;
&lt;br /&gt;
That's it: now the fair Nevernesse folks are greeted properly.&lt;br /&gt;
&lt;br /&gt;
=== Basic Case Resolution ===&lt;br /&gt;
&lt;br /&gt;
One problem frequently encountered is use of the wrong noun case when the placeholder is substituted in the msgstr. For example, in many languages every KDE app has such a problem in the Help menu, with one or both of &amp;quot;About %1...&amp;quot; and &amp;quot;%1 &amp;amp;Handbook&amp;quot;. This can be scripted in {{path|kdelibs.po}} like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
msgid &amp;quot;&amp;amp;About %1&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;amp;O %1&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;&amp;amp;O $[get-case dative %1]&amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get-case&amp;lt;/tt&amp;gt; interpolation is supposed to get the &amp;lt;tt&amp;gt;dative&amp;lt;/tt&amp;gt; case of whatever app name the &amp;lt;tt&amp;gt;%1&amp;lt;/tt&amp;gt; happens to be. The Transcript module {{path|kdelibs.js}} contains the definition of &amp;lt;tt&amp;gt;get-case&amp;lt;/tt&amp;gt;, as well as the dictionary of cases:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
function getProperty (prop, key) {&lt;br /&gt;
    return _dict_[key][prop];&lt;br /&gt;
}&lt;br /&gt;
Ts.setcall(&amp;quot;get-case&amp;quot;, getProperty);&lt;br /&gt;
&lt;br /&gt;
_dict_ = {};&lt;br /&gt;
function addDictCases (key, gen, dat, acc, ins) {&lt;br /&gt;
    if (!_dict_[key])&lt;br /&gt;
        _dict_[key] = {};&lt;br /&gt;
    _dict_[key][&amp;quot;genitive&amp;quot;]     = gen;&lt;br /&gt;
    _dict_[key][&amp;quot;dative&amp;quot;]       = dat;&lt;br /&gt;
    _dict_[key][&amp;quot;accusative&amp;quot;]   = acc;&lt;br /&gt;
    _dict_[key][&amp;quot;instrumental&amp;quot;] = ins;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// dictionary entries follow:&lt;br /&gt;
addDictCases(&amp;quot;KWrite&amp;quot;, &amp;quot;KWritea&amp;quot;, &amp;quot;KWriteu&amp;quot;, &amp;quot;KWrite&amp;quot;, &amp;quot;KWriteom&amp;quot;);&lt;br /&gt;
addDictCases(&amp;quot;Konsole&amp;quot;, &amp;quot;Konsole&amp;quot;, &amp;quot;Konsoli&amp;quot;, &amp;quot;Konsolu&amp;quot;, &amp;quot;Konsolom&amp;quot;);&lt;br /&gt;
...&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Function &amp;lt;tt&amp;gt;getProperty&amp;lt;/tt&amp;gt;, bound to &amp;lt;tt&amp;gt;get-case&amp;lt;/tt&amp;gt; call, simply returns the entry from the dictionary of forms. Function &amp;lt;tt&amp;gt;addDictCases&amp;lt;/tt&amp;gt; is responsible for adding the static entries (name and its cases) into the dictionary, which is done in the final few lines for all apps of interest.&lt;br /&gt;
&lt;br /&gt;
This completes the example, but for better modularization, it is also possible split out the dictionary insertion in a separate file, eg. {{path|appdict.js}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// appdict.js&lt;br /&gt;
addDictCases(&amp;quot;KWrite&amp;quot;, &amp;quot;KWritea&amp;quot;, &amp;quot;KWriteu&amp;quot;, &amp;quot;KWrite&amp;quot;, &amp;quot;KWriteom&amp;quot;);&lt;br /&gt;
addDictCases(&amp;quot;Konsole&amp;quot;, &amp;quot;Konsole&amp;quot;, &amp;quot;Konsoli&amp;quot;, &amp;quot;Konsolu&amp;quot;, &amp;quot;Konsolom&amp;quot;);&lt;br /&gt;
...&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and use Transcript interface to load this file in the {{path|kdelibs.js}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// kdelibs.js&lt;br /&gt;
...&lt;br /&gt;
...&lt;br /&gt;
...&lt;br /&gt;
Ts.load(&amp;quot;appdict&amp;quot;);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Ts.load()&amp;lt;/tt&amp;gt; takes filename without extension, and assumes its location is relative to the folder of the parent file (ie. in this case {{path|kdelibs.js}} and {{path|appdict.js}} should be in the same folder).&lt;br /&gt;
&lt;br /&gt;
=== Dynamic Case Setting ===&lt;br /&gt;
&lt;br /&gt;
The previous scripted example solves the original problem, but introduces the burden of maintaining the dictionary insertion file. There is no way around this when the placeholder substitutes are &amp;quot;dead&amp;quot; strings from outside (eg. from {{path|.desktop}} files), but when they are coming from KDE's PO files at runtime, this burden can be removed.&lt;br /&gt;
&lt;br /&gt;
The app name in KDE's Help menu indeed comes from the app PO file, and it is of course encountered at runtime before the menu strings come into focus. This allows setting the cases of app name in the PO msgstr which contains it. For example, {{path|katepart.po}} contains the &amp;quot;KWrite&amp;quot; string, and the forms could be set at that point:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
msgid &amp;quot;KWrite&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KWrite&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;$[set-cases KWritea KWriteu KWrite KWriteom]&amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;set-cases&amp;lt;/tt&amp;gt; is a ''side-effect'' interpolation: it should set the dictionary entries, but this particular message should in any case use the ordinary translation. Assuming all the definitions from previous example are still in effect, here is how &amp;lt;tt&amp;gt;set-cases&amp;lt;/tt&amp;gt; could be defined in {{path|kdelibs.js}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
function dynamicSetCases (gen, dat, acc, ins) {&lt;br /&gt;
    addDictCases(Ts.msgstrf(), gen, dat, acc, ins);&lt;br /&gt;
    Ts.fallback();&lt;br /&gt;
}&lt;br /&gt;
Ts.setcall(&amp;quot;set-cases&amp;quot;, dynamicSetCases);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In other words, this is little more than a wrapper to &amp;quot;static&amp;quot; &amp;lt;tt&amp;gt;addDictCases&amp;lt;/tt&amp;gt; from previous example, but two new elements of Transcript interface appear. First is the &amp;lt;tt&amp;gt;Ts.msgstrf()&amp;lt;/tt&amp;gt; function, which returns the finalized ordinary translation (placeholders substituted), and which is needed in this case as the dictionary key. Second is the &amp;lt;tt&amp;gt;Ts.fallback()&amp;lt;/tt&amp;gt; function, which signalizes the Transcript engine to disregard the result of the scripted part of msgstr and use the ordinary translation.&lt;br /&gt;
&lt;br /&gt;
Admittedly, the use of &amp;lt;tt&amp;gt;Ts.fallback()&amp;lt;/tt&amp;gt; in this case is not necessary, but given for introductory purpose; &amp;lt;tt&amp;gt;dynamicSetCases&amp;lt;/tt&amp;gt; might as well ''return'' the ordinary translation via &amp;lt;tt&amp;gt;Ts.msgstrf()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The PO Shell ==&lt;br /&gt;
&lt;br /&gt;
This section gives the details of how the interpolations in the PO msgstr are expanded before evaluation.&lt;br /&gt;
&lt;br /&gt;
The interpolations are parts of msgstr between &amp;lt;tt&amp;gt;$[...]&amp;lt;/tt&amp;gt;, and are parsed into a number of strings. The first string is the name of the call registered in the scripting module via &amp;lt;tt&amp;gt;Ts.setcall()&amp;lt;/tt&amp;gt;, and the rest are the arguments to bound JavaScript function. The arguments are typically passed as JavaScript type &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, except in a special case detailed below.&lt;br /&gt;
&lt;br /&gt;
The special characters in the interpolation are whitespace, single quote (') and backslash (\). Whitespace separates arguments, whereas single quote can be used for text which contains whitespaces. The backslash is used as escape; it can escape whitespace in non-quoted text, or single quotes in quoted text. This is pretty much like a typical Unix shell.&lt;br /&gt;
&lt;br /&gt;
Double quotes are not special. Single quotes are used instead of double quotes because it makes it easier to edit interpolations in PO files, where double quotes would have to be escaped. This also means that when escape is needed in the interpolation, it must be escaped once itself for the PO msgstr.&lt;br /&gt;
&lt;br /&gt;
The biggest difference from the shell expansion is that unlike with shell variables, the placeholders are expanded such that no characters within them are treated as special. Otherwise, many tricky problems could arise with whitespace or single quotes contained inside.&lt;br /&gt;
&lt;br /&gt;
The call name bound to a JavaScript function using &amp;lt;tt&amp;gt;Ts.setcall()&amp;lt;/tt&amp;gt; does not have to be a proper JavaScript identifier, but any Unicode string not containing the interpolation-special characters. This means that more &amp;quot;natural&amp;quot; call names can be used inside the msgstr, like those with dashes or non-Latin1 characters. E.g. call names can be in the language of the PO file, for an aesthetic impression.&lt;br /&gt;
&lt;br /&gt;
Sub-interpolations, &amp;lt;tt&amp;gt;$[... $[...] ...]&amp;lt;/tt&amp;gt;, are also possible. If put inside inside single quotes, they will be treated as ordinary text. Thus, if a literal closing square bracket is needed as an argument inside the interpolation, it can be given within single quotes.&lt;br /&gt;
&lt;br /&gt;
In case that the argument is given as &amp;lt;tt&amp;gt;^''number''&amp;lt;/tt&amp;gt;, it will evaluate to the value supplied for the corresponding placeholder -- unlike the &amp;lt;tt&amp;gt;%''number''&amp;lt;/tt&amp;gt; form, which evaluates to the placeholder substitution string. Also, the argument type as seen by JavaScript need no longer be &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, but will correspond to the value substituted (e.g. &amp;lt;tt&amp;gt;Number&amp;lt;/tt&amp;gt;). This distinction may be important in some situations. Even if the value is originally a string, the substitution string may have extra formatting (padding, tags...), which may not be desirable. In particular, the number substitutes may come tagged or locale-formatted, such that they cannot be easily parsed back into &amp;lt;tt&amp;gt;Number&amp;lt;/tt&amp;gt;. In these cases, &amp;lt;tt&amp;gt;^''number''&amp;lt;/tt&amp;gt; form can be used to get the raw values.&lt;br /&gt;
&lt;br /&gt;
== The Transcript Interface ==&lt;br /&gt;
&lt;br /&gt;
Transcript provides extensions to the JavaScript, which interface with the PO file and the Transcript environment. They are all function properties of the &amp;lt;tt&amp;gt;Ts&amp;lt;/tt&amp;gt; object, accessible as &amp;lt;tt&amp;gt;Ts.''func''(''args'')&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;setcall (''name'', ''func'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;setcall (''name'', ''func'', ''obj'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Binds the call name to the JavaScript function, for use in the interpolations inside the PO file.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; name of the call. Can be any Unicode string, for ease of use in the msgstr&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''func''&amp;lt;/tt&amp;gt; function object&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''obj''&amp;lt;/tt&amp;gt; object to act as &amp;lt;tt&amp;gt;this&amp;lt;/tt&amp;gt; inside the function; if omitted, &amp;lt;tt&amp;gt;this&amp;lt;/tt&amp;gt; refers to global object&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;hascall (''name'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Check if the call for use in PO file has been set.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; name of the call&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if set, &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;acall (''name'', ''arg''*)&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Applies previously set PO call to a list of arguments, within the scripting module itself. Indirect calls can be made this way, e.g. by passing a call name as a string within PO file interpolation.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; name of the call&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''arg''*&amp;lt;/tt&amp;gt; arguments to the call&lt;br /&gt;
: Returns what the indirect call would return.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;load (''file''*)&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Evaluates the code in the specified files, in the left to right order. File paths are expected to be relative to current module's folder.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''file''&amp;lt;/tt&amp;gt; file name without extension&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;fallback ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Forces Transcript to use ordinary translation, regardless of whether the interpolation evaluates successfully or fails. The evaluation of the script is not aborted, any other interpolations will evaluate too.&lt;br /&gt;
: &amp;amp;nbsp;&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;msgid ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns msgid of the last message, with placeholders intact.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;msgstrf ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns finalized ordinary translation of the last message, with placeholders substituted.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;msgctxt ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns msgctxt of the last message, with placeholders intact.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;msgkey ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns a &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt; which is implementation-dependent combination of msgctxt and msgid with placeholders intact. Used to uniquely identify the message within the PO file, usefull as a dictionary key.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;nsubs ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns the number of substitutes provided for placeholders in the last message. It is equal to the highest-numbered placeholder for a proper i18n call in the application code, but i18n calls do not have to be quite proper.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;subs (''index'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Used to access values of placeholder substitutes provided to the last message. Numbering is zero-based.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''index''&amp;lt;/tt&amp;gt; index of placeholder substitute&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, regardless of the value type substituted in the application code.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;vals (''index'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Used to access values of placeholder values provided to the last message. Numbering is zero-based.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''index''&amp;lt;/tt&amp;gt; index of placeholder value&lt;br /&gt;
: Returns the matching JavaScript type to the value type used in the application code. E.g. strings will be &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, integers and doubles &amp;lt;tt&amp;gt;Number&amp;lt;/tt&amp;gt;. May also return &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;, in case the value cannot be represented as a reasonable JavaScript type.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;dynctxt (''key'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Programmers may append ''dynamic'' context to the message, which is a pair of strings: a context key and its value. Use this function to retrieve such contexts.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''key''&amp;lt;/tt&amp;gt; context key string&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt; if dynamic context with the given key does not exist.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;dbgputs (''msg'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Outputs a debug message in the shell. The message is seen only if KDE libraries have been compiled in debug mode.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''msg''&amp;lt;/tt&amp;gt; message string&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;warnputs (''msg'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Outputs a warning message in the shell.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''msg''&amp;lt;/tt&amp;gt; message string&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
: ''Since KDE 4.7.1.''&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;setcallForall (''name'', ''func'', ''obj'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;setcallForall (''name'', ''func'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Similar to &amp;lt;tt&amp;gt;setcall()&amp;lt;/tt&amp;gt;, but the function is executed on every message after it has been finalized (if the message was explicitly scripted, the function is executed after the script has been evaluated). The function receives no arguments, and its return value is ignored, i.e. it cannot change the finalized message; the call is used for side-effects. The &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; parameter is used only for reporting errors. When several &amp;lt;tt&amp;gt;setcallForall()&amp;lt;/tt&amp;gt; have been issued, the functions are invoked in the order of issue.&lt;br /&gt;
: &amp;amp;nbsp;&lt;br /&gt;
: More precisely, these calls are made on every message ''after'' the Transcript engine has been initialized, which happens on first explicitly scripted message. Thus, if earlier application of the calls is necessary, Transcript can be jump-started by scripting one early encountered message with only a single empty interpolation: &amp;lt;tt&amp;gt;msgstr &amp;quot;...|/|$[]&amp;quot;&amp;lt;/tt&amp;gt;; this will do nothing for that message, but it will start the engine.&lt;br /&gt;
: &amp;amp;nbsp;&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;toUpperFirst (''text'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Converts the first letter in the string into upper case, even if the first character in the string is not a letter. Unicode specification is used to determine what a letter is (i.e. works for non-ASCII letters).&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''text''&amp;lt;/tt&amp;gt; string to process&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;toLowerFirst (''text'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Converts the first letter in the string into lower case, under same assumptions as for &amp;lt;tt&amp;gt;toUpperFirst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''text''&amp;lt;/tt&amp;gt; string to process&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;loadProps (''file''*)&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Loads [[#Property Maps|property maps]] from the specified files. File paths are expected to be relative to current module's folder.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''file''&amp;lt;/tt&amp;gt; file name without extension&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;getProp (''phrase'', ''prop'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Fetches the property value of the phrase, as defined by [[#Property Maps|property map]].&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''phrase''&amp;lt;/tt&amp;gt; text for which the property is requested&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''prop''&amp;lt;/tt&amp;gt; property key string&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt; if the given text has no such property.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;setProp (''phrase'', ''prop'', ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Sets the property value of the phrase. The phrase and property key will be automatically normalized, as they would have been when loaded from a [[#Property Maps|property map]] file.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''phrase''&amp;lt;/tt&amp;gt; text for which the property is set&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''prop''&amp;lt;/tt&amp;gt; property key string&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''value''&amp;lt;/tt&amp;gt; value of the property (string)&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;normKey (''phrase'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Normalizes the text by removing all whitespace, removing the accelerator, and lowercasing it, e.g. for use in near-match lookups.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''phrase''&amp;lt;/tt&amp;gt; text to be normalized&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfString (''key'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfString (''key'', ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfBool (''key'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfBool (''key'', ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfNumber (''key'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfNumber (''key'', ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Fetches a value of the requested type from the [[#User Configuration|user-configuration]] file. A default value of the same type can be stated too (or else it defaults to &amp;lt;tt&amp;gt;undefined&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''key''&amp;lt;/tt&amp;gt; the name of the field in the configuration file&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''value''&amp;lt;/tt&amp;gt; the default value, in case the key is not found&lt;br /&gt;
: Returns the configuration value if the key is found, or the default value or &amp;lt;tt&amp;gt;undefined&amp;lt;/tt&amp;gt; otherwise. If the configuration string is not a valid representation of the requested type, again the default or &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt; is returned instead.&lt;br /&gt;
&lt;br /&gt;
=== Property Maps ===&lt;br /&gt;
&lt;br /&gt;
There is a frequent need to have different properties attached to the particular pieces of text. For example, case, gender, etc. may be considered as properties of a noun, or phrase with a subject/object role in a sentence. Sometimes it may be convenient (or necessary) to define and maintain the phrases and their properties in an external file. ''Property map'' is Transcript's built-in (i.e. efficient) way to handle such definitions.&lt;br /&gt;
&lt;br /&gt;
Property map files are text files in a simple dictionary format for writing down phrases with their properties (filenames must end in &amp;lt;tt&amp;gt;.pmap&amp;lt;/tt&amp;gt;). The format is best shown on the example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# cities.pmap&lt;br /&gt;
=:Athens:Atina:nom=Atina:gen=Atine:dat=Atini:acc=Atinu::&lt;br /&gt;
=:Paris:Pariz:nom=Pariz:gen=Pariza:dat=Parizu:acc=Pariz::&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Each entry starts with two characters, &amp;lt;tt&amp;gt;=:&amp;lt;/tt&amp;gt; in this example, which may be chosen arbitrarily (but must be non-letters, and non-#), and can change from entry to entry. The first character defines the separator in the property key-value pair, and the second character is the separator of pairs. E.g. the &amp;lt;tt&amp;gt;gen=Atine&amp;lt;/tt&amp;gt; segment above is defining the genitive case of the localized form of Athens. The &amp;quot;pairs&amp;quot; which actually lack the property key (first two in the entries above) are considered phrase identifiers. The completely empty pair (&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt; in the example) terminates the entry.&lt;br /&gt;
&lt;br /&gt;
The property map is loaded inside the scripting module using the &amp;lt;tt&amp;gt;Ts.loadProps()&amp;lt;/tt&amp;gt; call. The map file should normally reside in the same folder as the scripting module that uses it; if so, the map from the above example is loaded simply with &amp;lt;tt&amp;gt;Ts.loadProps(&amp;quot;cities&amp;quot;)&amp;lt;/tt&amp;gt;. The property values are obtained in the scripts using &amp;lt;tt&amp;gt;Ts.getProp()&amp;lt;/tt&amp;gt; call. E.g. the genitive form of Athens would be obtained either by &amp;lt;tt&amp;gt;Ts.getProp(&amp;quot;Athens&amp;quot;, &amp;quot;gen&amp;quot;)&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Ts.getProp(&amp;quot;Atina&amp;quot;, &amp;quot;gen&amp;quot;)&amp;lt;/tt&amp;gt; -- because the map defined both as phrase identifiers for Athens. The phrase/key lookup is performed using normalized values; this normalization can be checked or used for own purposes by &amp;lt;tt&amp;gt;Ts.normKey()&amp;lt;/tt&amp;gt; call.&lt;br /&gt;
&lt;br /&gt;
The comments are a bit of an issue in property map files. Since the phrases and property values can be anything (hence the possibility to choose separators), fixing any single character as your typical to-the-end-of-line comment would introduce limitations. Instead, the #-comments are allowed only ''between'' the entries, span to the end of line, and # cannot be a separator character.&lt;br /&gt;
&lt;br /&gt;
The whitespace in property values is mostly preserved (for the keys it does not matter, as it gets stripped for lookups). However, if the leading sequence of whitespace contains a newline, all whitespace to the first newline and including it is stripped; symmetrically, in a trailing whitespace sequence, the last newline (if any) and the whitespace following it are removed.&lt;br /&gt;
&lt;br /&gt;
=== User Configuration ===&lt;br /&gt;
&lt;br /&gt;
Using a configuration file located at {{path|$HOME/.transcriptrc}}, the user can be allowed to configure certain aspects of Transcript operation. The configuration file is in ini-style, where group names are language codes to which the selections apply. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Settings for German.&lt;br /&gt;
[de]&lt;br /&gt;
serve-sausages = no&lt;br /&gt;
wine-instead-of-beer = yes&lt;br /&gt;
&lt;br /&gt;
# Settings for Italian.&lt;br /&gt;
[it]&lt;br /&gt;
with-mozzarella = no&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Within scripting modules, the configuration values can be fetched using &amp;lt;tt&amp;gt;Ts.getConf*()&amp;lt;/tt&amp;gt; series of calls. These calls will automatically look for the configuration fields under the proper language group, as the scripting modules are language-dependent too.&lt;br /&gt;
&lt;br /&gt;
For boolean-valued keys, &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;no&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; can be used to indicate negative (false) values, and everything else is treated as positive (true). Also, the boolean values are not case sensitive.&lt;br /&gt;
&lt;br /&gt;
== Repository Organization ==&lt;br /&gt;
&lt;br /&gt;
For the PO file in the KDE repository {{path|LL/messages/kdemodule/foo.po}}, the corresponding Transcript module should be located at {{path|LL/scripts/kdemodule/foo/foo.js}}. Note the extra subfolder in the module path, named like the basename of the PO/JS file. This subfolder is introduced because the module's main JS file might need other supporting files, which can then be located conveniently in the same folder.&lt;br /&gt;
&lt;br /&gt;
The {{path|autogen.sh}} script, used for some time already to generate build system support for PO files, will also generate build support for Transcript modules. In particular, it must be rerun whenever a new module subfolder is added (e.g. the {{path|LL/scripts/kdemodule/foo}}), but not when particular files within it are added or removed. Every file in the module subfolder will be installed automatically, so put there only what is needed at runtime.&lt;br /&gt;
&lt;br /&gt;
== Real-Life Examples ==&lt;br /&gt;
&lt;br /&gt;
=== CJK Accelerator Keys ===&lt;br /&gt;
In CJK environment, accelerator keys are wrapped in the parenthesis. For example, translation of &amp;quot;&amp;amp;File&amp;quot; in Korean is &amp;quot;파일(&amp;amp;F)&amp;quot;, and in Japanese, &amp;quot;ファイル(&amp;amp;F)&amp;quot;. When it comes to the names of action, it is shared among toolbar icon names, menu bar, and so on.&lt;br /&gt;
&lt;br /&gt;
However, in toolbar icon name, &amp;quot;Configure shortcut&amp;quot; dialog, etc., those access keys are remaining in the name, makes the name little bit awkward. In this situation, we can use transcript to get rid of those accelerator keys. Currently,  the code is in Japanese and Korean kdelibs4.js file.&lt;br /&gt;
&lt;br /&gt;
=== Korean Postpositions ===&lt;br /&gt;
In Korean language, postpositions are widely used. Among those, 8 postpositions are in pair and they change forms according to the word. Because PO file itself doesn't know what the substituted word(like %1) is, proper postpositions couldn't be added to the string. &lt;br /&gt;
&lt;br /&gt;
Fortunately, the rule is programmable, and proper postpositions could be added via transcript. Right now a little part of postposition rules is programmed into Korean version of kdelibs4.js.&lt;br /&gt;
&lt;br /&gt;
=== Automatic Property Calls ===&lt;br /&gt;
Leveraging [[#Property Maps|property maps]] interface, we can make a generalization of the [[#Dynamic Case Setting|dynamic case setting]] example. We want to set named properties by key-value pairs for a given message, and then, to use calls named as property keys to retrieve the values when that message is used as placeholder replacement in another message.&lt;br /&gt;
&lt;br /&gt;
For example, Nevernessians need to match the noun case of &amp;quot;baloon&amp;quot; when it is inserted into sentence &amp;quot;I see a %1&amp;quot;, and additionally the adjective form of &amp;quot;red&amp;quot; to baloon in &amp;quot;I see a red %1&amp;quot;, so they do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
msgid &amp;quot;baloon&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;beeluun&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;$[properties see-it beeluuno see-red raado]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
msgid &amp;quot;I see a %1&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;O sii e %1&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;O sii e $[see-it %1]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
msgid &amp;quot;I see a red %1&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;O sii e raad %1&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;O sii e $[see-red %1] $[see-it %1]&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;properties&amp;lt;/tt&amp;gt; call, which does all the work -- setting properties, setting new calls by property keys -- looks like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Set properties of the phrase given by the finalized msgstr in the PO file.&lt;br /&gt;
// The arguments to the call are consecutive pairs of keys and values,&lt;br /&gt;
// as many as needed (i.e. total number of arguments must be even).&lt;br /&gt;
//&lt;br /&gt;
// The property keys are registered as PO calls taking single argument,&lt;br /&gt;
// which can be used to retrive the property values for this msgstr&lt;br /&gt;
// when it is later used as placeholder replacement in another message.&lt;br /&gt;
//&lt;br /&gt;
// Always signals fallback.&lt;br /&gt;
//&lt;br /&gt;
function setMsgstrProps (/*KEY1, VALUE1, ...*/)&lt;br /&gt;
{&lt;br /&gt;
    if (arguments.length % 2 != 0)&lt;br /&gt;
        throw Error(&amp;quot;Property setter given odd number of arguments.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    // Collect finalized msgstr.&lt;br /&gt;
    phrase = Ts.msgstrf()&lt;br /&gt;
&lt;br /&gt;
    // Go through all key-value pairs.&lt;br /&gt;
    for (var i = 0; i &amp;lt; arguments.length; i += 2) {&lt;br /&gt;
        var pkey = arguments[i];&lt;br /&gt;
        var pval = arguments[i + 1];&lt;br /&gt;
&lt;br /&gt;
        // Set the value of the property for this phrase.&lt;br /&gt;
        Ts.setProp(phrase, pkey, pval);&lt;br /&gt;
&lt;br /&gt;
        // Set the PO call for getting this property, if not already set.&lt;br /&gt;
        if (!Ts.hascall(pkey)) {&lt;br /&gt;
            Ts.setcall(pkey,&lt;br /&gt;
                       function (phr) { return Ts.getProp(phr, this.pkey) },&lt;br /&gt;
                       {&amp;quot;pkey&amp;quot; : pkey});&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    throw Ts.fallback();&lt;br /&gt;
}&lt;br /&gt;
Ts.setcall(&amp;quot;properties&amp;quot;, setMsgstrProps);&lt;br /&gt;
// NOTE: You can replace &amp;quot;properties&amp;quot; in the line above with any UTF-8 string,&lt;br /&gt;
// e.g. one in your language so that it blends nicely inside POs.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Labels Dependent on Dynamic Values ===&lt;br /&gt;
Sometimes the text of a standalone label should grammatically conform to the a changing value elsewhere in the interface. The typical example of this is when a sentence-like row of different widgets is used to specify an action:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Search in files modified:&lt;br /&gt;
( ) ...&lt;br /&gt;
(*) during the last {day|week|month|year}&lt;br /&gt;
( ) ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;( )&amp;lt;/tt&amp;gt; stand for radio buttons, and &amp;lt;tt&amp;gt;{...|...|...}&amp;lt;/tt&amp;gt; for a list box with several choices. The label &amp;lt;tt&amp;gt;&amp;quot;during the last&amp;quot;&amp;lt;/tt&amp;gt; contains the adjective &amp;quot;last&amp;quot;, which in some languages needs to have different forms according to the noun it describes (one of the choices from list box). Whenever the list box value changes, the label should change to match it. But this label is a standalone message in the PO file, so based on what can its translation be scripted?&lt;br /&gt;
&lt;br /&gt;
The solution is to ask the programmer to make the label refresh on every change of the list box value, and to add a ''dynamic context'' to the label's message (using &amp;lt;tt&amp;gt;inContext&amp;lt;/tt&amp;gt; method of &amp;lt;tt&amp;gt;KLocalizedString&amp;lt;/tt&amp;gt;). The dynamic context is a key-value string pair which indicates the current list box value; the key and possible values should be documented in the message's context. If the programmer did this properly, the translator should now see in the PO file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
msgctxt &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;Part of logical sentence 'Search in files modified &amp;gt;during the last&amp;lt; &amp;quot;&lt;br /&gt;
&amp;quot;day|week|...'; provides dynamic context 'last-what': 'd' for day, &amp;quot;&lt;br /&gt;
&amp;quot;'w' for week, 'm' for month, 'y' for year.&amp;quot;&lt;br /&gt;
msgid &amp;quot;during the last&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The translation can now be scripted based on the &amp;lt;tt&amp;gt;last-what&amp;lt;/tt&amp;gt; dynamic context:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;duureeng thee leestee&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;duureeng $[by-context last-what 'd|m' 'thee leestee' 'w|y' 'thaa leestaa']&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;by-context&amp;lt;/tt&amp;gt; call takes the context key, followed by pairs of context value matches (regular expressions) and corresponding phrases; in this example, one form is selected for context values &amp;lt;tt&amp;gt;d&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;, and another form for &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;. The definition of this call is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Select a phrase according to dynamic context.&lt;br /&gt;
// The first argument is the context keyword,&lt;br /&gt;
// followed by arbitrary numer of pairs of context values and&lt;br /&gt;
// corresponding phrases, optionally followed by default phrase.&lt;br /&gt;
//&lt;br /&gt;
// Context values are actually regular experessions, so that if one phrase&lt;br /&gt;
// corresponds to several context values, it does not have to be repeated&lt;br /&gt;
// but its context value can be given e.g. as 'foo|bar|...'.&lt;br /&gt;
//&lt;br /&gt;
// If the context was not matched, default phrase is returned if&lt;br /&gt;
// it was given; otherwise fallback is signaled.&lt;br /&gt;
//&lt;br /&gt;
function selectByContext (/* ctxt_key,&lt;br /&gt;
                             valrx_1, phrase_1, ..., valrx_N, phrase_N&lt;br /&gt;
                             [, default_phrase] */)&lt;br /&gt;
{&lt;br /&gt;
    if (arguments.length &amp;lt; 1) {&lt;br /&gt;
        throw Error(&amp;quot;Selector by context needs at least one argument.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Collect context value for the given key.&lt;br /&gt;
    var ctxtkey = arguments[0];&lt;br /&gt;
    var ctxtval = Ts.dynctxt(ctxtkey);&lt;br /&gt;
&lt;br /&gt;
    // Match the context and select the corresponding phrase.&lt;br /&gt;
    var phrase;&lt;br /&gt;
    for (var i = 1; i &amp;lt; arguments.length; i += 2) {&lt;br /&gt;
        if (ctxtval.match(RegExp(arguments[i]))) {&lt;br /&gt;
            phrase = arguments[i + 1];&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // If context was not matched, select default phrase or signal fallback.&lt;br /&gt;
    if (phrase == undefined) {&lt;br /&gt;
        if (arguments.length % 2 == 0) {&lt;br /&gt;
            phrase = arguments[arguments.length - 1];&lt;br /&gt;
        } else {&lt;br /&gt;
            throw Ts.fallback();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return phrase;&lt;br /&gt;
}&lt;br /&gt;
Ts.setcall(&amp;quot;by-context&amp;quot;, selectByContext);&lt;br /&gt;
// NOTE: You can replace &amp;quot;by-context&amp;quot; in the line above with any UTF-8 string,&lt;br /&gt;
// e.g. one in your language so that it blends nicely inside POs.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Summit</id>
		<title>Localization/Workflows/PO Summit</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Summit"/>
				<updated>2011-04-06T12:35:43Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Spacing.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Translating in Summit|&lt;br /&gt;
prereqs=[[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Software Branches and Translation ==&lt;br /&gt;
&lt;br /&gt;
The obvious approach to releasing software is for developers to focus on one central body of code, a single &amp;quot;branch&amp;quot;, fixing bugs and adding new features to it, and from time to time taking a &amp;quot;snapshot&amp;quot; of the branch and packing it as next release. One approach to make the release process more robust, is for development to proceed in two parallel branches. From the &amp;quot;stable&amp;quot; branch the actual releases are made, mostly with bugs fixed and only very important features added. The other, &amp;quot;unstable&amp;quot; branch, is used to develop new and redesign existing features, and at some point will become the next stable branch. Depending on the project, releases may be made from the unstable branch as well, in parallel with stable releases, in order for eager users to help testing the novelties.&lt;br /&gt;
&lt;br /&gt;
In KDE, all three release models may be present at any given moment. Core KDE modules, which are together labeled as &amp;quot;the KDE&amp;quot; and released in unison, follow the two branch model, with stable and trunk branch, and releases from stable branch only. KDE extragear applications may do the same, but they are not required to; they may instead make releases from the trunk branch only, or also use stable and trunk branch, but make releases from both. This presents translators with the workflow as on the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_branches.png|center|Classic translation by branches]]&lt;br /&gt;
&lt;br /&gt;
The KDE [[Localization/Workflows/Repository_Automation|repository automation]] (aka &amp;quot;Scripty&amp;quot;) is preparing template POs and merging them with language POs. From the point of view of language teams, real people who perform global actions (e.g. moving around POs for all languages when an application moves from module to another) can also be grouped here. However, the translation team is still presented with two branches of POs to translate.&lt;br /&gt;
&lt;br /&gt;
In general, this means that, just like programmers, at times translators have to work on both branches, and propagate fixes from one branch to another (&amp;quot;backport&amp;quot; from trunk to stable, or &amp;quot;forwardport&amp;quot; from stable to trunk). This may be prone to coordinatorial confusion, and demand extra effort and attention when updating translations. Keeping up with two branches is easier in core KDE modules, as they are released from stable branch only and with singular schedule, but could be more taxing with extragear applications.&lt;br /&gt;
&lt;br /&gt;
The exact amount of effort spent due to parallel translation, porting of fixes, and coordination, depends on the translation team. For example, a well-manned and well-coordinated team, with established style and terminology guides, custom automation to support these, may be able to keep all POs in both branches fully translated at all times with ease. Or, a team may have worked out well-defined schedules, such that any given member of the team at one point switches from translating one branch to another, without looking back, thus effectively having everyone always working on one branch (even if not the same one).&lt;br /&gt;
&lt;br /&gt;
If, however, you as the team coordinator have said and thought &amp;quot;Should do that in trunk too, bugger&amp;quot;, &amp;quot;Didn't we fix that already?&amp;quot;, &amp;quot;No, you should take it from stable&amp;quot;, &amp;quot;It was released from WHAT branch?&amp;quot;, more often than you would have liked, the following presents one possibility for sidestepping such issues.&lt;br /&gt;
&lt;br /&gt;
== Translating in Summit ==&lt;br /&gt;
&lt;br /&gt;
For a PO catalog which exists in both stable and trunk branch, a new same-named catalog can be made by ''gathering'' all the unique messages from branch PO files, i.e. the ''summit'' of branch POs. Assuming that branch POs were not all that different, since they are two versions of the same catalog, the summit PO shouldn't have much more messages than either. Translators at all times work on the summit PO, from which the messages are periodically ''scattered'' back to original branch POs. Thus, translators can always work on summit POs, not having to do any parallel translation, branch switching or porting of fixes. The summit workflow is presented by the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_summit.png|center|Translation in summit]]&lt;br /&gt;
&lt;br /&gt;
In the summit mode, repository automation gathers summit PO templates from branch templates, and stores them separately from real branches, at {{path|trunk/l10n-support/templates/summit/}}. The language team also has a collection summit POs, at {{path|trunk/l10n-support/LANG/summit/}}, which is the sole location where translation happens. As before, repository automation handles merging of templates in branches, but merging of summit POs is done by the team coordinator; team coordinator can opt to manually merge branch POs as well (more on why-and-how of this later). From time to time, the team coordinator fills out branch POs by scattering from summit. Not to worry, each of these special actions upon the team coordinator is done with a single command.&lt;br /&gt;
&lt;br /&gt;
While it is in principle obvious that two branch POs can be made into one summit PO with the union of their messages, there are some important details that should be handled the right way by the summitting system:&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes modules in one branch, so that it no longer belongs to the same module in both branches (e.g. application is moved from one to another module in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes its name in one branch, but not in the other (e.g. application is renamed in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO in one branch is split into two POs in another (e.g. extracting a library out of monolithic application in trunk)?&lt;br /&gt;
&lt;br /&gt;
* Where to place messages unique to one branch in the summit PO? The original file context of a message, which messages precede it and which follow it, should be kept as much as possible.&lt;br /&gt;
&lt;br /&gt;
* If source references are used to achieve good ordering of messages in summit PO, what to do if some source file paths change in one branch (e.g. application gets restructured in trunk)?&lt;br /&gt;
&lt;br /&gt;
* How to handle messages with different plurality across branches (since messages are identified only by their &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, an not &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt;)?&lt;br /&gt;
&lt;br /&gt;
And handle these details it does, the present summitting system. This also means that teams working in the summit need not take care of the first three issues above, which are affecting manual branch handling too.&lt;br /&gt;
&lt;br /&gt;
Summit POs are normal, fully valid POs in their own right. A message in a summit PO is different from branch PO only by being equipped with another comment, &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt;, showing in which branches the message exists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgctxt &amp;quot;The destination url of a job&amp;quot;&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:517&lt;br /&gt;
msgid &amp;quot;&amp;amp;Keep this window open after transfer is complete&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first message above thus exists in trunk only, the second in stable only, and the third in both branches. The source reference always points to the source file in the first listed branch. Any extracted comments (&amp;lt;tt&amp;gt;#.&amp;lt;/tt&amp;gt;) other than the branch list are also taken from the first listed branch.&lt;br /&gt;
&lt;br /&gt;
Note that the two messages above are different only by context; the context was added in trunk, but not in stable, in order not to break message freeze. However, due to careful ordering of messages in summit POs, these two messages appear together, allowing translator to immediately make correction in stable branch too if the new context in trunk shows it to be necessary.&lt;br /&gt;
&lt;br /&gt;
=== Setting Up and Daily Operation ===&lt;br /&gt;
&lt;br /&gt;
Before initializing language summit, the team coordinator has to have all the necessary paths checked out from the KDE repository, and structured on the local machine exactly as in the repository. If the path to the root of KDE repository on the local machine is &amp;lt;tt&amp;gt;$KDEREPO&amp;lt;/tt&amp;gt;, and the language code &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt;, then the structure should be as follows, with leaf directories checked out in full:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            scripts/&lt;br /&gt;
            pology/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                templates/&lt;br /&gt;
                LANG/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that this structure is fully under version control (rather than e.g. top directories being manually created), so if that is not the case, the following commands will fetch everything anew in proper order:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
cd $KDEREPO&lt;br /&gt;
svn co --depth=empty svn+ssh://svn.kde.org/home/kde .&lt;br /&gt;
svn up --depth=empty branches branches/stable branches/stable/l10n-kde4&lt;br /&gt;
svn up --depth=empty trunk trunk/l10n-support trunk/l10n-kde4&lt;br /&gt;
svn up branches/stable/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the trailing dot in the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command, and do not miss to substitute LANG for the real language code in the last three commands. &amp;lt;tt&amp;gt;--depth=empty&amp;lt;/tt&amp;gt; option prevents recursive fetching, so that e.g. the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command does not fetch the complete repository tree. Later you can regularly update this tree with single command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
svn up $KDEREPO/{trunk,branches/stable}/l10n-kde4/{scripts,templates,LANG} \&lt;br /&gt;
       $KDEREPO/trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Summit operations are performed using the &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; command, which is part of [[Localization/Tools/Pology|Pology]], residing in {{path|trunk/l10n-support/pology/}}. Therefore the first thing to do is to setup Pology, which amounts only to setting the proper path:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ export PATH=$KDEREPO/trunk/l10n-support/pology/bin:$PATH&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To initialize the summit, by gathering from existing translation in branches, the team coordinator executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Depending on the amount of translation, after some minutes the initial gathering will have been completed, and language summit located under {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages/}}. This is the only time when the coordinator performs the gather operation on language POs; it is daily done only on templates by repository automation. Then, the created language summit should be merged with current summit templates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Merging the summit is something that the coordinator does periodically, with frequency of own desire. For example, it can be done daily, or with increasing frequency as the last day for translation for the next release approaches.&lt;br /&gt;
&lt;br /&gt;
After the first merging, language summit is ready for active translation. The coordinator should now commit {{path|$KDEREPO/trunk/l10n-support/LANG/}}, and, importantly, notify team members to stop working on branch POs and focus exclusively on summit POs.&lt;br /&gt;
&lt;br /&gt;
To scatter the summit, i.e. fill out POs in stable and trunk branch from the summit POs, the coordinator periodically executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As with merging, there is no fixed schedule when scattering should be done. Of course, it must necessarily be done before the next release is tagged, and in between it is useful to scatter for runtime testing, or to have translation statistics by branches on l10n.kde.org up to date.&lt;br /&gt;
&lt;br /&gt;
Periodic scattering and merging of the complete summit are basically all that a language team coordinator needs to do specifically to operate the summit. Also, since {{path|l10n-support/scripts/}} and {{path|l10n-support/pology/}} contain scripts and settings critical for proper functioning of summit operations, and may be tweaked at any time, they should always be updated from the repository together with PO files and templates (in fact, it is best to always update at once the whole tree as outlined above).&lt;br /&gt;
&lt;br /&gt;
{{note|For documentation POs, summit setup and operation is the same, only replacing every &amp;lt;tt&amp;gt;messages&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;docmessages&amp;lt;/tt&amp;gt; in the command lines above. The user interface and documentation summits are fully independent, so for a trial period it is reasonable to work with the interface summit only, and engage documentation summit once the trial has been deemed successfull.}}&lt;br /&gt;
&lt;br /&gt;
=== Operation Targets ===&lt;br /&gt;
&lt;br /&gt;
Sometimes it is advantageous to merge or scatter just a single catalog, a single module, a single branch, or any combination thereof. To this end, scatter and merge operations accept any number of ''operation targets'' after the operation keyword, specified as one of &amp;lt;tt&amp;gt;''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''MODULE''/&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''MODULE''/&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;''BRANCH'':&amp;lt;/tt&amp;gt;. For example, to scatter just to Dolphin's PO in stable branch, in order to test translation at runtime, one would execute:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(note no &amp;lt;tt&amp;gt;.po&amp;lt;/tt&amp;gt; ending on catalog name). Or, to scatter to every PO in &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; module in stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:kdeplasma-addons/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the trailing slash is mandatory, or else &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; would think that &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; is a catalog name). Finally, to scatter to all catalogs in the stable branch (with the trailing colon for the same reason as earlier):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command line arguments of &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; operations are intentionally arranged such that all the arguments fixed for one language are placed first. If operation targets are used frequently, then it is convenient to place the immutable part of the command line under a shell alias, with absolute path to the summit setup file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ alias posummit-kde-LANG=&amp;quot;posummit $KDEREPO/trunk/l10n-support/scripts/messages.summit LANG&amp;quot;&lt;br /&gt;
$ cd ANYWHERE&lt;br /&gt;
$ posummit-kde-LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Externally Injected Branch Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Once the summit is in operation, normally the only way for a catalog to appear in branches (trunk or stable) is through scattering from the summit. However, sometimes an application which had seen considerable development outside of the infrastructure of KDE project gets moved in, drawing in any of its existing translations into branches. Such externally injected branch catalogs cause warnings to be issued on summit merging, and outright failure on scattering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/foobar.po  # dummy injection&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/libfoobar.po  # dummy injection&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
...&lt;br /&gt;
posummit: warning: No summit catalog for branch catalog &lt;br /&gt;
    '../l10n-kde4/LANG/messages/kdetoys/foobar.po'.&lt;br /&gt;
posummit: warning: No summit catalog for branch catalog &lt;br /&gt;
    '../l10n-kde4/LANG/messages/kdetoys/libfoobar.po'.&lt;br /&gt;
...&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
...&lt;br /&gt;
posummit: error: Missing necessary summit catalogs: foobar libfoobar&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When this happens, the injected catalogs need to be gathered into the summit. This is done just like the initial gathering, only giving injected catalogs' names as operation targets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force foobar libfoobar&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Summit Customization ===&lt;br /&gt;
&lt;br /&gt;
File {{path|scripts/messages.summit}} (i.e. {{path|$KDEREPO/trunk/l10n-support/scripts/messages.summit}}), given as first argument to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, contains the general summit setup for all languages. This file is set to include customization file per language, if it exists at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages.extras.summit}}, which contains additions and overrides to the general setup as desired by the language team. Same as the general setup file, the customization file is a Python source. It uses an external object named &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; to define summit settings, and can, of course, contain any helper Python code (the file is executed only once, at the beginning of a &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; run). It has the following general layout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# -*- coding: UTF-8 -*-&lt;br /&gt;
# kate: syntax Python;&lt;br /&gt;
# This file is included by scripts/messages.summit&lt;br /&gt;
# for language-specific additions/overrides.&lt;br /&gt;
#&lt;br /&gt;
# ...&lt;br /&gt;
# ... operations with object S and other Python code ...&lt;br /&gt;
# ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Object &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; provides both data attributes and methods to configure different aspects of summit operation. For example, while the general setup specifies that text fields in summit catalogs should not be wrapped on column but should be wrapped on logical breaks (like some markup tags), this can be overriden using &amp;lt;tt&amp;gt;summit_wrap&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;summit_fine_wrap&amp;lt;/tt&amp;gt; attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.summit_wrap = True&lt;br /&gt;
S.summit_fine_wrap = False&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, to get the path to a file relative to the summit customization file itself (rather than to current working directory, where &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; was executed), method &amp;lt;tt&amp;gt;resolve_path_rooted&amp;lt;/tt&amp;gt; can be used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
relpath = S.resolve_path_rooted(&amp;quot;../whatever.txt&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following sections will present some typical customization possibilities.&lt;br /&gt;
&lt;br /&gt;
=== Fully Local Merging ===&lt;br /&gt;
&lt;br /&gt;
When scattering from the summit, sometimes there will be reports of &amp;quot;messages missing in the summit&amp;quot;. This happens because of time rift created by the Scripty merging branch POs, gathering summit templates, and a team coordinator merging the language summit, thus making some messages in branch POs not always present in the summit. This condition is benign, as such warnings will start to disappear with the message freeze approaching, but can be annoying. For this reason, team coordinator can stop Scripty from merging branch POs, and have the &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; command alone merge not only summit POs, but stable and trunk POs as well, such that summit and branches are always in perfect sync.&lt;br /&gt;
&lt;br /&gt;
First, to stop Scripty from merging branch POs, a file named &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; (with arbitrary content) should be committed to the roots of respective trees, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$ touch $KDEREPO/trunk/l10n-kde4/messages/LANG/no-auto-merge&lt;br /&gt;
$ touch $KDEREPO/branches/stable/l10n-kde4/LANG/messages/no-auto-merge&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, to make summit &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; merge everything, the following lines should be added into the summit customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Set local merging for all branches.&lt;br /&gt;
for branch in S.branches:&lt;br /&gt;
    branch[&amp;quot;merge_locally&amp;quot;] = True&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once local merging of all branches is set, the coordinator can also use operation targets for selective merging, e.g. to merge only stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge stable:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Merging with Compendium ===&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; takes into account only the catalog itself to fill out near-match translations to new messages introduced by merging. i.e. to produce fuzzy messages. However, an arbitrary PO file can be given to &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; as another possible source of earlier translations, through the &amp;lt;tt&amp;gt;--compendium&amp;lt;/tt&amp;gt; option. For maximum effect, this PO file is usually constructed as the collection of messages from all PO files project-wide, and hence called the ''compendium''.&lt;br /&gt;
&lt;br /&gt;
Compendium can be used in summit merge operations simply by setting &amp;lt;tt&amp;gt;compendium_on_merge&amp;lt;/tt&amp;gt; attribute in summit customization file. If the compendium is located at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages-compendium.po}}, then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Compendium to use when merging summit catalogs.&lt;br /&gt;
S.compendium_on_merge = S.resolve_path_rooted(&amp;quot;messages-compendium.po&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that if not located as above, compendium should not be placed within {{path|.../LANG/summit/messages/}}, as then it would be considered a summit catalog itself. In case fully local merging is engaged, only summit POs will be merged with compendium; it makes no sense for branch POs, since they are not being directly translated.&lt;br /&gt;
&lt;br /&gt;
See [http://www.gnu.org/software/automake/manual/gettext/Creating-Compendia.html &amp;quot;Creating Compendia&amp;quot;] section of Gettext manual for details on how to create a compendium out of current body of summit translations. Once you establish the precise commands to create the compendium (whether to collect fuzzies too, whether to include old compendium as one of sources for the new, etc.), you would periodically refresh and commit the updated compendium.&lt;br /&gt;
&lt;br /&gt;
=== Vivifying Summit Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Translation of a summit catalog normally starts the same way as it did for branch catalogs, by copying it over from template and initializing the header. This can be done manually, but it can also be quite automatic when using project manager as sometimes provided by dedicated PO editors. However, relying on the editor's project manager can be disadvantageous at times. For example, aside from the PO editor, other, frequently command line tools may be used to process the body of translation, and these tools might need to consider non-started templates as if they were empty POs (e.g. statistics). Team members who do not have full local checkout, or no project set up in the editor, may need to jump between language and template directories when looking for files to translate.&lt;br /&gt;
&lt;br /&gt;
Therefore, summit setup can be customized to automatically create (&amp;quot;vivify&amp;quot;) summit catalogs for every new summit template, so that there is never the need (for a tool or human) to specifically treat templates as empty catalogs. This is done by adding the following lines into customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Create empty summit catalog for every new summit template.&lt;br /&gt;
S.vivify_on_merge = True&lt;br /&gt;
S.vivify_w_translator = &amp;quot;Noone Noonian &amp;lt;noone.noonian@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_langteam = &amp;quot;Neverneese &amp;lt;neverteam@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_plurals = &amp;quot;nplurals=2; plural=n != 1;&amp;quot;&lt;br /&gt;
# Minimum translation state to create branch catalog on scatter.&lt;br /&gt;
S.scatter_min_completeness = 0.9&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;vivify_w_*&amp;lt;/tt&amp;gt; attributes set the necessary data to initialize headers of newly created summit catalogs. Aside from those listed above, there is also the &amp;lt;tt&amp;gt;vivify_w_charset&amp;lt;/tt&amp;gt; attribute, which is by default &amp;lt;tt&amp;gt;&amp;quot;UTF-8&amp;quot;&amp;lt;/tt&amp;gt;, and very probably should not be changed.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; attribute does not refer to vivification of summit catalogs, but should invariably be set in this context. When scattering from summit, normally the branch catalog is automatically created if there is the corresponding summit catalog. When vivification is engaged, this would result in creation of empty branch catalogs too, which is not desired for two reasons. Firstly, empty branch catalogs would become part of the released language pack, for which there is no practical reason. Secondly, KDE's i18n system regards an application with installed catalog as translated, so messages coming from basic system catalogs (e.g. &amp;lt;tt&amp;gt;kdelibs4&amp;lt;/tt&amp;gt;) would show through, resulting in mostly untranslated user interface with specks of translation -- many users consider this rather ungainly. Therefore, &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; sets how complete the translation of currently non-existing branch catalog should be after scatter (0.0 empty, 1.0 fully complete), for the branch catalog to actually be created. If the &amp;lt;tt&amp;gt;--force&amp;lt;/tt&amp;gt; option is given to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, the branch catalog will be created regardless of its translation state, which may be handy in combination with [[#Operation Targets|operation target]] when wanting to check work in progress in running application.&lt;br /&gt;
&lt;br /&gt;
If [[#Merging with Compendium|the compendium has been set]] for merging, every vivified summit catalog will also be merged against the compendium, to fill out as many of messages with approximate translations.&lt;br /&gt;
&lt;br /&gt;
=== Scatter Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Checks, modifications...))&lt;br /&gt;
&lt;br /&gt;
=== Merge Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Special header fields...))&lt;br /&gt;
&lt;br /&gt;
== Disadvantages to Summit and Remedies ==&lt;br /&gt;
&lt;br /&gt;
Although hopefully shadowed by the advantages, working in summit is not without its disadvantages. These should be weighed when deciding of whether to try out the summit workflow.&lt;br /&gt;
&lt;br /&gt;
Obviously, while summit operations are made to be quite automatic, some extra aptitude is asked of the team coordinator. Reasonable shell handling, understanding of version control operations, feeling the pulse of repository automation, are all prerequisites, and some scripting ability advantageous.&lt;br /&gt;
&lt;br /&gt;
After the summit is put in operation, any changes made manually in branch POs will not propagate to summit, and will be soon lost to scattering -- summit translations override everything in branches. This means that the whole team must work in the summit, it is not possible for some members to use the summit, and some not.&lt;br /&gt;
&lt;br /&gt;
A summit PO file will necessarily have more messages than either of the branch files. For example, in the KDE 4.0/4.1 and 4.1/4.2 cycle, summit POs of core KDE modules had on average less than 5% more words than their stable counterparts. However, the said percent is the top, never approached limit of wasted workload due to trunk messages coming and going, given that as the next feature KDE release approaches, more and more trunk messages will find their way into it.&lt;br /&gt;
&lt;br /&gt;
Another, more pressing issue with increased size of summit POs is the following scenario: a stable release is around the corner, and the team has no time to update summit POs fully, but could update only stable messages in them. E.g. there are 1000 untranslated and fuzzy messages, out of which only 100 are from the stable branch. A clever dedicated PO editor could allow jumping only through untranslated and fuzzy messages which also satisfy a general search criteria, which in this case would be that a comment matches &amp;lt;tt&amp;gt;#\.\+&amp;gt;.*stable&amp;lt;/tt&amp;gt; regular expression. On the other hand, with some external help, it is enough if the PO editor can merely search through comments. Then, the &amp;lt;tt&amp;gt;posieve&amp;lt;/tt&amp;gt; command (ready to use next to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;) can equip untranslated and fuzzy stable messages with &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag (producing &amp;lt;tt&amp;gt;#, ..., untranslated&amp;lt;/tt&amp;gt; comment), and this flag can be searched for in the PO editor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve tag-untranslated -sbranch:stable -swfuzzy PATHS_TO_PO_FILES_OR_DIRS&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag does not need to be manually removed when the message is updated. It will automatically disappear on the next merge, as it is not among flags known to Gettext.&lt;br /&gt;
&lt;br /&gt;
If an automatic source lookup mechanism (to check the message context by following its source references) was available for branches, it may not entirely work for summit. Already the branch POs in KDE are kept separate from the code, which means that paths given by source references cannot be followed directly, but appropriate root paths have to be added in some way (a dedicated PO editor may provide a way to do this); this should continue to work with summit for those messages which exist both in trunk and stable branch, since their source references correspond to trunk code. But for messages found only in stable branch, whose source references correspond to stable code, existing source lookup mechanism will likely assume trunk roots again, and try to fetch wrong sources. To fix this, the source lookup mechanism should be flexible enough to select roots based on branch keywords given in summit messages' &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt; comment.&lt;br /&gt;
&lt;br /&gt;
There is also the organizational issue with starting to use the summit, and, if it does not help as expected, stopping to use it. Team members have to be reminded to not send in branch POs at start, and then to be sent back to branch POs if summit is disbanded. On the plus side, disbanding summit is technically simple: just remove from the repository {{path|l10n-supprot/LANG/summit}}, possibly also &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; files if [[#Fully Local Merging|fully local merging]] was set up, and that is it.&lt;br /&gt;
&lt;br /&gt;
== Another Way to Improve Branch Handling ==&lt;br /&gt;
&lt;br /&gt;
If summit seems a lot to digest, or is simply an overkill for team's needs, but still some improvement to manual handling of branches would be welcomed, KDE's dedicated PO editor [[Localization/Tools/Lokalize|Lokalize]] offers a ''branch sync'' mode. It works as follows.&lt;br /&gt;
&lt;br /&gt;
In Lokalize project definition, the local paths of trunk and stable PO roots are set in ''Translation directory:'' and ''Branch directory:'' fields. Then, when a trunk PO file is opened, if it has a stable counterpart with same name and location as in the trunk, this stable PO is also going to be opened. For each trunk message in the main editing pane, if such a message exists in stable PO too, the stable message will be shown in the ''Secondary Sync'' pane; changes in the translation of trunk message will reflect to the stable message, and stable PO file will also be saved when the trunk is saved.&lt;br /&gt;
&lt;br /&gt;
Furthermore, any team member can personally choose to work like this, there is no need to change the workflow of the language team as whole. When sending modifications to the coordinator, team members who rely on this feature of Lokalize simply send both trunk and stable POs that got modified.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Summit</id>
		<title>Localization/Workflows/PO Summit</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Summit"/>
				<updated>2011-04-06T12:35:20Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Note on problem with following source references in summit.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Translating in Summit|&lt;br /&gt;
prereqs=[[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Software Branches and Translation ==&lt;br /&gt;
&lt;br /&gt;
The obvious approach to releasing software is for developers to focus on one central body of code, a single &amp;quot;branch&amp;quot;, fixing bugs and adding new features to it, and from time to time taking a &amp;quot;snapshot&amp;quot; of the branch and packing it as next release. One approach to make the release process more robust, is for development to proceed in two parallel branches. From the &amp;quot;stable&amp;quot; branch the actual releases are made, mostly with bugs fixed and only very important features added. The other, &amp;quot;unstable&amp;quot; branch, is used to develop new and redesign existing features, and at some point will become the next stable branch. Depending on the project, releases may be made from the unstable branch as well, in parallel with stable releases, in order for eager users to help testing the novelties.&lt;br /&gt;
&lt;br /&gt;
In KDE, all three release models may be present at any given moment. Core KDE modules, which are together labeled as &amp;quot;the KDE&amp;quot; and released in unison, follow the two branch model, with stable and trunk branch, and releases from stable branch only. KDE extragear applications may do the same, but they are not required to; they may instead make releases from the trunk branch only, or also use stable and trunk branch, but make releases from both. This presents translators with the workflow as on the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_branches.png|center|Classic translation by branches]]&lt;br /&gt;
&lt;br /&gt;
The KDE [[Localization/Workflows/Repository_Automation|repository automation]] (aka &amp;quot;Scripty&amp;quot;) is preparing template POs and merging them with language POs. From the point of view of language teams, real people who perform global actions (e.g. moving around POs for all languages when an application moves from module to another) can also be grouped here. However, the translation team is still presented with two branches of POs to translate.&lt;br /&gt;
&lt;br /&gt;
In general, this means that, just like programmers, at times translators have to work on both branches, and propagate fixes from one branch to another (&amp;quot;backport&amp;quot; from trunk to stable, or &amp;quot;forwardport&amp;quot; from stable to trunk). This may be prone to coordinatorial confusion, and demand extra effort and attention when updating translations. Keeping up with two branches is easier in core KDE modules, as they are released from stable branch only and with singular schedule, but could be more taxing with extragear applications.&lt;br /&gt;
&lt;br /&gt;
The exact amount of effort spent due to parallel translation, porting of fixes, and coordination, depends on the translation team. For example, a well-manned and well-coordinated team, with established style and terminology guides, custom automation to support these, may be able to keep all POs in both branches fully translated at all times with ease. Or, a team may have worked out well-defined schedules, such that any given member of the team at one point switches from translating one branch to another, without looking back, thus effectively having everyone always working on one branch (even if not the same one).&lt;br /&gt;
&lt;br /&gt;
If, however, you as the team coordinator have said and thought &amp;quot;Should do that in trunk too, bugger&amp;quot;, &amp;quot;Didn't we fix that already?&amp;quot;, &amp;quot;No, you should take it from stable&amp;quot;, &amp;quot;It was released from WHAT branch?&amp;quot;, more often than you would have liked, the following presents one possibility for sidestepping such issues.&lt;br /&gt;
&lt;br /&gt;
== Translating in Summit ==&lt;br /&gt;
&lt;br /&gt;
For a PO catalog which exists in both stable and trunk branch, a new same-named catalog can be made by ''gathering'' all the unique messages from branch PO files, i.e. the ''summit'' of branch POs. Assuming that branch POs were not all that different, since they are two versions of the same catalog, the summit PO shouldn't have much more messages than either. Translators at all times work on the summit PO, from which the messages are periodically ''scattered'' back to original branch POs. Thus, translators can always work on summit POs, not having to do any parallel translation, branch switching or porting of fixes. The summit workflow is presented by the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_summit.png|center|Translation in summit]]&lt;br /&gt;
&lt;br /&gt;
In the summit mode, repository automation gathers summit PO templates from branch templates, and stores them separately from real branches, at {{path|trunk/l10n-support/templates/summit/}}. The language team also has a collection summit POs, at {{path|trunk/l10n-support/LANG/summit/}}, which is the sole location where translation happens. As before, repository automation handles merging of templates in branches, but merging of summit POs is done by the team coordinator; team coordinator can opt to manually merge branch POs as well (more on why-and-how of this later). From time to time, the team coordinator fills out branch POs by scattering from summit. Not to worry, each of these special actions upon the team coordinator is done with a single command.&lt;br /&gt;
&lt;br /&gt;
While it is in principle obvious that two branch POs can be made into one summit PO with the union of their messages, there are some important details that should be handled the right way by the summitting system:&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes modules in one branch, so that it no longer belongs to the same module in both branches (e.g. application is moved from one to another module in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes its name in one branch, but not in the other (e.g. application is renamed in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO in one branch is split into two POs in another (e.g. extracting a library out of monolithic application in trunk)?&lt;br /&gt;
&lt;br /&gt;
* Where to place messages unique to one branch in the summit PO? The original file context of a message, which messages precede it and which follow it, should be kept as much as possible.&lt;br /&gt;
&lt;br /&gt;
* If source references are used to achieve good ordering of messages in summit PO, what to do if some source file paths change in one branch (e.g. application gets restructured in trunk)?&lt;br /&gt;
&lt;br /&gt;
* How to handle messages with different plurality across branches (since messages are identified only by their &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, an not &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt;)?&lt;br /&gt;
&lt;br /&gt;
And handle these details it does, the present summitting system. This also means that teams working in the summit need not take care of the first three issues above, which are affecting manual branch handling too.&lt;br /&gt;
&lt;br /&gt;
Summit POs are normal, fully valid POs in their own right. A message in a summit PO is different from branch PO only by being equipped with another comment, &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt;, showing in which branches the message exists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgctxt &amp;quot;The destination url of a job&amp;quot;&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:517&lt;br /&gt;
msgid &amp;quot;&amp;amp;Keep this window open after transfer is complete&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first message above thus exists in trunk only, the second in stable only, and the third in both branches. The source reference always points to the source file in the first listed branch. Any extracted comments (&amp;lt;tt&amp;gt;#.&amp;lt;/tt&amp;gt;) other than the branch list are also taken from the first listed branch.&lt;br /&gt;
&lt;br /&gt;
Note that the two messages above are different only by context; the context was added in trunk, but not in stable, in order not to break message freeze. However, due to careful ordering of messages in summit POs, these two messages appear together, allowing translator to immediately make correction in stable branch too if the new context in trunk shows it to be necessary.&lt;br /&gt;
&lt;br /&gt;
=== Setting Up and Daily Operation ===&lt;br /&gt;
&lt;br /&gt;
Before initializing language summit, the team coordinator has to have all the necessary paths checked out from the KDE repository, and structured on the local machine exactly as in the repository. If the path to the root of KDE repository on the local machine is &amp;lt;tt&amp;gt;$KDEREPO&amp;lt;/tt&amp;gt;, and the language code &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt;, then the structure should be as follows, with leaf directories checked out in full:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            scripts/&lt;br /&gt;
            pology/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                templates/&lt;br /&gt;
                LANG/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that this structure is fully under version control (rather than e.g. top directories being manually created), so if that is not the case, the following commands will fetch everything anew in proper order:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
cd $KDEREPO&lt;br /&gt;
svn co --depth=empty svn+ssh://svn.kde.org/home/kde .&lt;br /&gt;
svn up --depth=empty branches branches/stable branches/stable/l10n-kde4&lt;br /&gt;
svn up --depth=empty trunk trunk/l10n-support trunk/l10n-kde4&lt;br /&gt;
svn up branches/stable/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the trailing dot in the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command, and do not miss to substitute LANG for the real language code in the last three commands. &amp;lt;tt&amp;gt;--depth=empty&amp;lt;/tt&amp;gt; option prevents recursive fetching, so that e.g. the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command does not fetch the complete repository tree. Later you can regularly update this tree with single command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
svn up $KDEREPO/{trunk,branches/stable}/l10n-kde4/{scripts,templates,LANG} \&lt;br /&gt;
       $KDEREPO/trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Summit operations are performed using the &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; command, which is part of [[Localization/Tools/Pology|Pology]], residing in {{path|trunk/l10n-support/pology/}}. Therefore the first thing to do is to setup Pology, which amounts only to setting the proper path:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ export PATH=$KDEREPO/trunk/l10n-support/pology/bin:$PATH&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To initialize the summit, by gathering from existing translation in branches, the team coordinator executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Depending on the amount of translation, after some minutes the initial gathering will have been completed, and language summit located under {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages/}}. This is the only time when the coordinator performs the gather operation on language POs; it is daily done only on templates by repository automation. Then, the created language summit should be merged with current summit templates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Merging the summit is something that the coordinator does periodically, with frequency of own desire. For example, it can be done daily, or with increasing frequency as the last day for translation for the next release approaches.&lt;br /&gt;
&lt;br /&gt;
After the first merging, language summit is ready for active translation. The coordinator should now commit {{path|$KDEREPO/trunk/l10n-support/LANG/}}, and, importantly, notify team members to stop working on branch POs and focus exclusively on summit POs.&lt;br /&gt;
&lt;br /&gt;
To scatter the summit, i.e. fill out POs in stable and trunk branch from the summit POs, the coordinator periodically executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As with merging, there is no fixed schedule when scattering should be done. Of course, it must necessarily be done before the next release is tagged, and in between it is useful to scatter for runtime testing, or to have translation statistics by branches on l10n.kde.org up to date.&lt;br /&gt;
&lt;br /&gt;
Periodic scattering and merging of the complete summit are basically all that a language team coordinator needs to do specifically to operate the summit. Also, since {{path|l10n-support/scripts/}} and {{path|l10n-support/pology/}} contain scripts and settings critical for proper functioning of summit operations, and may be tweaked at any time, they should always be updated from the repository together with PO files and templates (in fact, it is best to always update at once the whole tree as outlined above).&lt;br /&gt;
&lt;br /&gt;
{{note|For documentation POs, summit setup and operation is the same, only replacing every &amp;lt;tt&amp;gt;messages&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;docmessages&amp;lt;/tt&amp;gt; in the command lines above. The user interface and documentation summits are fully independent, so for a trial period it is reasonable to work with the interface summit only, and engage documentation summit once the trial has been deemed successfull.}}&lt;br /&gt;
&lt;br /&gt;
=== Operation Targets ===&lt;br /&gt;
&lt;br /&gt;
Sometimes it is advantageous to merge or scatter just a single catalog, a single module, a single branch, or any combination thereof. To this end, scatter and merge operations accept any number of ''operation targets'' after the operation keyword, specified as one of &amp;lt;tt&amp;gt;''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''MODULE''/&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''MODULE''/&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;''BRANCH'':&amp;lt;/tt&amp;gt;. For example, to scatter just to Dolphin's PO in stable branch, in order to test translation at runtime, one would execute:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(note no &amp;lt;tt&amp;gt;.po&amp;lt;/tt&amp;gt; ending on catalog name). Or, to scatter to every PO in &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; module in stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:kdeplasma-addons/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the trailing slash is mandatory, or else &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; would think that &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; is a catalog name). Finally, to scatter to all catalogs in the stable branch (with the trailing colon for the same reason as earlier):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command line arguments of &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; operations are intentionally arranged such that all the arguments fixed for one language are placed first. If operation targets are used frequently, then it is convenient to place the immutable part of the command line under a shell alias, with absolute path to the summit setup file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ alias posummit-kde-LANG=&amp;quot;posummit $KDEREPO/trunk/l10n-support/scripts/messages.summit LANG&amp;quot;&lt;br /&gt;
$ cd ANYWHERE&lt;br /&gt;
$ posummit-kde-LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Externally Injected Branch Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Once the summit is in operation, normally the only way for a catalog to appear in branches (trunk or stable) is through scattering from the summit. However, sometimes an application which had seen considerable development outside of the infrastructure of KDE project gets moved in, drawing in any of its existing translations into branches. Such externally injected branch catalogs cause warnings to be issued on summit merging, and outright failure on scattering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/foobar.po  # dummy injection&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/libfoobar.po  # dummy injection&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
...&lt;br /&gt;
posummit: warning: No summit catalog for branch catalog &lt;br /&gt;
    '../l10n-kde4/LANG/messages/kdetoys/foobar.po'.&lt;br /&gt;
posummit: warning: No summit catalog for branch catalog &lt;br /&gt;
    '../l10n-kde4/LANG/messages/kdetoys/libfoobar.po'.&lt;br /&gt;
...&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
...&lt;br /&gt;
posummit: error: Missing necessary summit catalogs: foobar libfoobar&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When this happens, the injected catalogs need to be gathered into the summit. This is done just like the initial gathering, only giving injected catalogs' names as operation targets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force foobar libfoobar&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Summit Customization ===&lt;br /&gt;
&lt;br /&gt;
File {{path|scripts/messages.summit}} (i.e. {{path|$KDEREPO/trunk/l10n-support/scripts/messages.summit}}), given as first argument to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, contains the general summit setup for all languages. This file is set to include customization file per language, if it exists at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages.extras.summit}}, which contains additions and overrides to the general setup as desired by the language team. Same as the general setup file, the customization file is a Python source. It uses an external object named &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; to define summit settings, and can, of course, contain any helper Python code (the file is executed only once, at the beginning of a &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; run). It has the following general layout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# -*- coding: UTF-8 -*-&lt;br /&gt;
# kate: syntax Python;&lt;br /&gt;
# This file is included by scripts/messages.summit&lt;br /&gt;
# for language-specific additions/overrides.&lt;br /&gt;
#&lt;br /&gt;
# ...&lt;br /&gt;
# ... operations with object S and other Python code ...&lt;br /&gt;
# ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Object &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; provides both data attributes and methods to configure different aspects of summit operation. For example, while the general setup specifies that text fields in summit catalogs should not be wrapped on column but should be wrapped on logical breaks (like some markup tags), this can be overriden using &amp;lt;tt&amp;gt;summit_wrap&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;summit_fine_wrap&amp;lt;/tt&amp;gt; attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.summit_wrap = True&lt;br /&gt;
S.summit_fine_wrap = False&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, to get the path to a file relative to the summit customization file itself (rather than to current working directory, where &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; was executed), method &amp;lt;tt&amp;gt;resolve_path_rooted&amp;lt;/tt&amp;gt; can be used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
relpath = S.resolve_path_rooted(&amp;quot;../whatever.txt&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following sections will present some typical customization possibilities.&lt;br /&gt;
&lt;br /&gt;
=== Fully Local Merging ===&lt;br /&gt;
&lt;br /&gt;
When scattering from the summit, sometimes there will be reports of &amp;quot;messages missing in the summit&amp;quot;. This happens because of time rift created by the Scripty merging branch POs, gathering summit templates, and a team coordinator merging the language summit, thus making some messages in branch POs not always present in the summit. This condition is benign, as such warnings will start to disappear with the message freeze approaching, but can be annoying. For this reason, team coordinator can stop Scripty from merging branch POs, and have the &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; command alone merge not only summit POs, but stable and trunk POs as well, such that summit and branches are always in perfect sync.&lt;br /&gt;
&lt;br /&gt;
First, to stop Scripty from merging branch POs, a file named &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; (with arbitrary content) should be committed to the roots of respective trees, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$ touch $KDEREPO/trunk/l10n-kde4/messages/LANG/no-auto-merge&lt;br /&gt;
$ touch $KDEREPO/branches/stable/l10n-kde4/LANG/messages/no-auto-merge&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, to make summit &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; merge everything, the following lines should be added into the summit customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Set local merging for all branches.&lt;br /&gt;
for branch in S.branches:&lt;br /&gt;
    branch[&amp;quot;merge_locally&amp;quot;] = True&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once local merging of all branches is set, the coordinator can also use operation targets for selective merging, e.g. to merge only stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge stable:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Merging with Compendium ===&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; takes into account only the catalog itself to fill out near-match translations to new messages introduced by merging. i.e. to produce fuzzy messages. However, an arbitrary PO file can be given to &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; as another possible source of earlier translations, through the &amp;lt;tt&amp;gt;--compendium&amp;lt;/tt&amp;gt; option. For maximum effect, this PO file is usually constructed as the collection of messages from all PO files project-wide, and hence called the ''compendium''.&lt;br /&gt;
&lt;br /&gt;
Compendium can be used in summit merge operations simply by setting &amp;lt;tt&amp;gt;compendium_on_merge&amp;lt;/tt&amp;gt; attribute in summit customization file. If the compendium is located at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages-compendium.po}}, then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Compendium to use when merging summit catalogs.&lt;br /&gt;
S.compendium_on_merge = S.resolve_path_rooted(&amp;quot;messages-compendium.po&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that if not located as above, compendium should not be placed within {{path|.../LANG/summit/messages/}}, as then it would be considered a summit catalog itself. In case fully local merging is engaged, only summit POs will be merged with compendium; it makes no sense for branch POs, since they are not being directly translated.&lt;br /&gt;
&lt;br /&gt;
See [http://www.gnu.org/software/automake/manual/gettext/Creating-Compendia.html &amp;quot;Creating Compendia&amp;quot;] section of Gettext manual for details on how to create a compendium out of current body of summit translations. Once you establish the precise commands to create the compendium (whether to collect fuzzies too, whether to include old compendium as one of sources for the new, etc.), you would periodically refresh and commit the updated compendium.&lt;br /&gt;
&lt;br /&gt;
=== Vivifying Summit Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Translation of a summit catalog normally starts the same way as it did for branch catalogs, by copying it over from template and initializing the header. This can be done manually, but it can also be quite automatic when using project manager as sometimes provided by dedicated PO editors. However, relying on the editor's project manager can be disadvantageous at times. For example, aside from the PO editor, other, frequently command line tools may be used to process the body of translation, and these tools might need to consider non-started templates as if they were empty POs (e.g. statistics). Team members who do not have full local checkout, or no project set up in the editor, may need to jump between language and template directories when looking for files to translate.&lt;br /&gt;
&lt;br /&gt;
Therefore, summit setup can be customized to automatically create (&amp;quot;vivify&amp;quot;) summit catalogs for every new summit template, so that there is never the need (for a tool or human) to specifically treat templates as empty catalogs. This is done by adding the following lines into customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Create empty summit catalog for every new summit template.&lt;br /&gt;
S.vivify_on_merge = True&lt;br /&gt;
S.vivify_w_translator = &amp;quot;Noone Noonian &amp;lt;noone.noonian@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_langteam = &amp;quot;Neverneese &amp;lt;neverteam@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_plurals = &amp;quot;nplurals=2; plural=n != 1;&amp;quot;&lt;br /&gt;
# Minimum translation state to create branch catalog on scatter.&lt;br /&gt;
S.scatter_min_completeness = 0.9&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;vivify_w_*&amp;lt;/tt&amp;gt; attributes set the necessary data to initialize headers of newly created summit catalogs. Aside from those listed above, there is also the &amp;lt;tt&amp;gt;vivify_w_charset&amp;lt;/tt&amp;gt; attribute, which is by default &amp;lt;tt&amp;gt;&amp;quot;UTF-8&amp;quot;&amp;lt;/tt&amp;gt;, and very probably should not be changed.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; attribute does not refer to vivification of summit catalogs, but should invariably be set in this context. When scattering from summit, normally the branch catalog is automatically created if there is the corresponding summit catalog. When vivification is engaged, this would result in creation of empty branch catalogs too, which is not desired for two reasons. Firstly, empty branch catalogs would become part of the released language pack, for which there is no practical reason. Secondly, KDE's i18n system regards an application with installed catalog as translated, so messages coming from basic system catalogs (e.g. &amp;lt;tt&amp;gt;kdelibs4&amp;lt;/tt&amp;gt;) would show through, resulting in mostly untranslated user interface with specks of translation -- many users consider this rather ungainly. Therefore, &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; sets how complete the translation of currently non-existing branch catalog should be after scatter (0.0 empty, 1.0 fully complete), for the branch catalog to actually be created. If the &amp;lt;tt&amp;gt;--force&amp;lt;/tt&amp;gt; option is given to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, the branch catalog will be created regardless of its translation state, which may be handy in combination with [[#Operation Targets|operation target]] when wanting to check work in progress in running application.&lt;br /&gt;
&lt;br /&gt;
If [[#Merging with Compendium|the compendium has been set]] for merging, every vivified summit catalog will also be merged against the compendium, to fill out as many of messages with approximate translations.&lt;br /&gt;
&lt;br /&gt;
=== Scatter Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Checks, modifications...))&lt;br /&gt;
&lt;br /&gt;
=== Merge Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Special header fields...))&lt;br /&gt;
&lt;br /&gt;
== Disadvantages to Summit and Remedies ==&lt;br /&gt;
&lt;br /&gt;
Although hopefully shadowed by the advantages, working in summit is not without its disadvantages. These should be weighed when deciding of whether to try out the summit workflow.&lt;br /&gt;
&lt;br /&gt;
Obviously, while summit operations are made to be quite automatic, some extra aptitude is asked of the team coordinator. Reasonable shell handling, understanding of version control operations, feeling the pulse of repository automation, are all prerequisites, and some scripting ability advantageous.&lt;br /&gt;
&lt;br /&gt;
After the summit is put in operation, any changes made manually in branch POs will not propagate to summit, and will be soon lost to scattering -- summit translations override everything in branches. This means that the whole team must work in the summit, it is not possible for some members to use the summit, and some not.&lt;br /&gt;
&lt;br /&gt;
A summit PO file will necessarily have more messages than either of the branch files. For example, in the KDE 4.0/4.1 and 4.1/4.2 cycle, summit POs of core KDE modules had on average less than 5% more words than their stable counterparts. However, the said percent is the top, never approached limit of wasted workload due to trunk messages coming and going, given that as the next feature KDE release approaches, more and more trunk messages will find their way into it.&lt;br /&gt;
&lt;br /&gt;
Another, more pressing issue with increased size of summit POs is the following scenario: a stable release is around the corner, and the team has no time to update summit POs fully, but could update only stable messages in them. E.g. there are 1000 untranslated and fuzzy messages, out of which only 100 are from the stable branch. A clever dedicated PO editor could allow jumping only through untranslated and fuzzy messages which also satisfy a general search criteria, which in this case would be that a comment matches &amp;lt;tt&amp;gt;#\.\+&amp;gt;.*stable&amp;lt;/tt&amp;gt; regular expression. On the other hand, with some external help, it is enough if the PO editor can merely search through comments. Then, the &amp;lt;tt&amp;gt;posieve&amp;lt;/tt&amp;gt; command (ready to use next to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;) can equip untranslated and fuzzy stable messages with &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag (producing &amp;lt;tt&amp;gt;#, ..., untranslated&amp;lt;/tt&amp;gt; comment), and this flag can be searched for in the PO editor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve tag-untranslated -sbranch:stable -swfuzzy PATHS_TO_PO_FILES_OR_DIRS&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag does not need to be manually removed when the message is updated. It will automatically disappear on the next merge, as it is not among flags known to Gettext.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If an automatic source lookup mechanism (to check the message context by following its source references) was available for branches, it may not entirely work for summit. Already the branch POs in KDE are kept separate from the code, which means that paths given by source references cannot be followed directly, but appropriate root paths have to be added in some way (a dedicated PO editor may provide a way to do this); this should continue to work with summit for those messages which exist both in trunk and stable branch, since their source references correspond to trunk code. But for messages found only in stable branch, whose source references correspond to stable code, existing source lookup mechanism will likely assume trunk roots again, and try to fetch wrong sources. To fix this, the source lookup mechanism should be flexible enough to select roots based on branch keywords given in summit messages' &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt; comment.&lt;br /&gt;
&lt;br /&gt;
There is also the organizational issue with starting to use the summit, and, if it does not help as expected, stopping to use it. Team members have to be reminded to not send in branch POs at start, and then to be sent back to branch POs if summit is disbanded. On the plus side, disbanding summit is technically simple: just remove from the repository {{path|l10n-supprot/LANG/summit}}, possibly also &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; files if [[#Fully Local Merging|fully local merging]] was set up, and that is it.&lt;br /&gt;
&lt;br /&gt;
== Another Way to Improve Branch Handling ==&lt;br /&gt;
&lt;br /&gt;
If summit seems a lot to digest, or is simply an overkill for team's needs, but still some improvement to manual handling of branches would be welcomed, KDE's dedicated PO editor [[Localization/Tools/Lokalize|Lokalize]] offers a ''branch sync'' mode. It works as follows.&lt;br /&gt;
&lt;br /&gt;
In Lokalize project definition, the local paths of trunk and stable PO roots are set in ''Translation directory:'' and ''Branch directory:'' fields. Then, when a trunk PO file is opened, if it has a stable counterpart with same name and location as in the trunk, this stable PO is also going to be opened. For each trunk message in the main editing pane, if such a message exists in stable PO too, the stable message will be shown in the ''Secondary Sync'' pane; changes in the translation of trunk message will reflect to the stable message, and stable PO file will also be saved when the trunk is saved.&lt;br /&gt;
&lt;br /&gt;
Furthermore, any team member can personally choose to work like this, there is no need to change the workflow of the language team as whole. When sending modifications to the coordinator, team members who rely on this feature of Lokalize simply send both trunk and stable POs that got modified.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-08-02T19:10:33Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Fixed some leftovers of previous modifications.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading'', ''approving''), each of which may return the translation to a previous stage, or forward it to some special stage. The process can also be more finer grained, where each message in the file goes through stages separately.&lt;br /&gt;
&lt;br /&gt;
Regardless of the particularities, workflows of this kind all have the following in common. Members of the translation team are assigned ''roles'' -- such as ''translator'', ''reviewer'', ''approver'', ''committer'' -- by which they enter into the workflow (single person can have more roles). The later review stages must wait for the earlier stages to complete, and the translation cannot be updated again before the current version clears the pipeline (or the pipeline is aborted). Most importantly, once the translation is committed, it becomes part of simply &amp;quot;admitted&amp;quot; translations, with no further qualifiers.&lt;br /&gt;
&lt;br /&gt;
The system of prescribed roles requires that team members assign them between themselves, stick to them, and shuffle them along the way. The prescribed review pipeline requires a tool to enforce and keep track of the stages in which translations are. This makes the review workflow complex and rigid, most probably with choke points for efficiency. Distribution of roles may become disbalanced by people coming and going, or the workflow tool may be prohibitive to some scenarios (e.g. single translator making small adjustments in dozens of files across the project, but having to upload each manually through a web interface).&lt;br /&gt;
&lt;br /&gt;
Of course, &amp;quot;rigid&amp;quot;, &amp;quot;complex&amp;quot;, &amp;quot;inefficient&amp;quot;, are comparative qualifications, so what is it that the classical review by stages can be compared to in this way?&lt;br /&gt;
&lt;br /&gt;
== Reviewing by Ascriptions ==&lt;br /&gt;
&lt;br /&gt;
Reviewing by ascriptions is even simpler conceptually, and yet less rigid, less complex, and much more efficient than the review by stages. It works on the message-level, rather than file-level. Anyone can simply translate some messages and directly commit modified files, without any review, but with ''ascribing'' modifications to own name. Anyone can review any committed messages at any moment, commit the modifications-on-review and ascribe reviews to own name and (possibly) to certain class -- full review, review of context, of terminology, of style, etc. Only when the translation is to be shipped to end users, the ''insufficiently'' reviewed messages are automatically omitted from the package, by evaluating the ''ascription history'' of each message.&lt;br /&gt;
&lt;br /&gt;
Most importantly, based on the ascription history, the reviewer can select only some particular messages, and review only the difference between their historical and current versions. For example, Alice can select to review only messages modified since she or Bob had last reviewed them for style; she could see the difference from that last review to current version, e.g. if in the whole paragraph only a single word has changed by Charlie when he reviewed the terminology. In terms of PO workflow, the ascription history propagates through merges, so the reviewer can compare the change in original and the change in translation since the last review, to judge if one fits the other.&lt;br /&gt;
&lt;br /&gt;
Since everyone just commits, translations can be efficiently kept in a version control repository, with the ascription system added on top. After having done some translating, the team member simply substitutes commit command of the version control system (VCS) with ascribe-modifications command of the ascription system (AS, which calls the underlying VCS internally). After reviewing, the team member uses ascribe-reviews command of the AS to commit reviews to ascription history (as well as modifications made during the review). To select messages for review, the team member issues diff-for-review command of the AS (with suitable parameters to narrow the set) and selected messages are marked in-place in PO files and [[Localization/Tools/Pology/PO_Embedded_Diffing|embedded with differences]], and possibly popped open in a PO editor.&lt;br /&gt;
&lt;br /&gt;
When the translations are to be released, the team coordinator issues filter-for-release command of the AS, which takes the working PO files and creates final PO files with insufficiently reviewed messages removed. &amp;quot;Release time&amp;quot; is used here only figuratively: this should be a fully automatic process, so it can be performed at any interval of convenience.&lt;br /&gt;
&lt;br /&gt;
What constitutes &amp;quot;sufficient review&amp;quot; can be defined in fine detail. It could be specified that messages modified by Alice need to have only review for terminology, but not necessarily for style; Charlie may belong to the group which needs to be reviewed on style, but not necessarily on context; Bob's reviews for style may be nice to have, but never blocking if missing. These decisions do not preclude released messages to be reviewed later on missing points, after higher priority reviews have been completed. The definition of sufficiency may be changed at any point, e.g. as team members get more experienced and require less review, without interfering with direct translation and review work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- (Here is one unorthodox possibility of using reviews by ascriptions. A random translator may want to keep an eye on what the reviewers change in the files he maintains. For example, to learn what are typical small errors that he makes while translating. Therefore, he himself reviews any modifications not made by him after his last review, and commits them. This will in no way interfere with &amp;quot;canonical&amp;quot; reviews, those considered at release time.) //--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In summary, with reviewing by ascriptions the lean efficiency of raw VCS operation is preserved while providing for great flexibility of review. All team members can be given commit access, no web or email detours are needed. There are no prescribed roles, but an equivalent of role assignment happens automatically at last possible moment, and can take into account both translators' and reviewers' abilities. There is no staging between completing and committing the translation, which enables translator to keep on polishing the translation undisturbed until the reviewer comes around. There is no inefficiency in handling small changes throughout many files, since single AS command commits all changes just as single VCS command would. AS in effect abstracts VCS, so general team members do not have to know the particularities of the underlying VCS. On commit operations, AS can also apply checks (e.g. decline to commit syntactically invalid PO files) and modifications (e.g. update translator's data in the PO header).&lt;br /&gt;
&lt;br /&gt;
== Ascription System in Pology ==&lt;br /&gt;
&lt;br /&gt;
[[Localization/Tools/Pology|Pology]] is a collection of various modular tools for supporting translation based on PO files. Among them is the script &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which implements an ascription system (AS); at present, it can use Subversion or Git as the underlying VCS. &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is still in experimental stage, so what follows is a brief description of how to use it in context of the KDE translation project. However, very little is truly specific to KDE; the only major assumption is that there exists a VCS repository with PO files of a given language grouped together, and that the translation team can use it without special restrictions.&lt;br /&gt;
&lt;br /&gt;
Very important for the AS is how branches are handled (in KDE, the rolling trunk and stable branches). AS can in principle be deployed by branch, but then there is the added complexity of porting translations between branches, which ascriptions should follow. Therefore, the AS implemented by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is currently limited to assumption that there is a single branch of translations at all times. The article [[Localization/Workflows/PO_Summit|&amp;quot;Translating in Summit&amp;quot;]] explains how a KDE translation team can set up and operate such a single branch, the summit, and this is the prerequisite for the following instructions. (Note that the summit system is useful on its own, and should be conductive to any kind of review workflow.)&lt;br /&gt;
&lt;br /&gt;
== Setting Up ==&lt;br /&gt;
&lt;br /&gt;
The summit branch for the language &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt; is positioned like this in the KDE repository:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            LANG/&lt;br /&gt;
                summit/&lt;br /&gt;
                    messages/&lt;br /&gt;
                    docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The team coordinator already has this part of the repository tree locally due to regular summit operations. For the same reason Pology is already set up. Setting up the ascription system is now simple. The file &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; is created in the parent directory of the summit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        ascription-config&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# ---------------------------&lt;br /&gt;
# Global ascription settings.&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
&lt;br /&gt;
# Roots of the catalog and ascription trees.&lt;br /&gt;
catalog-root = summit&lt;br /&gt;
ascript-root = summit-ascript&lt;br /&gt;
&lt;br /&gt;
# The underlying version control system.&lt;br /&gt;
version-control = svn&lt;br /&gt;
&lt;br /&gt;
# Data for updating catalog headers.&lt;br /&gt;
# - language code&lt;br /&gt;
language = LANG&lt;br /&gt;
# - full language name&lt;br /&gt;
language-team = LANGUAGE&lt;br /&gt;
# - email address of the team&lt;br /&gt;
team-email = kde-i18n-LANG@kde.org&lt;br /&gt;
&lt;br /&gt;
# Default commit message.&lt;br /&gt;
commit-message = Translation updates.&lt;br /&gt;
&lt;br /&gt;
# -----------------------&lt;br /&gt;
# Registered translators.&lt;br /&gt;
&lt;br /&gt;
[user-alice]&lt;br /&gt;
name = Alice Akmalryn&lt;br /&gt;
original-name = Алиса Акмалрин&lt;br /&gt;
email = alice.akmalryn@someplacenice.org&lt;br /&gt;
&lt;br /&gt;
[user-bob]&lt;br /&gt;
name = Bob Byomkin&lt;br /&gt;
original-name = Бобан Бјомкин&lt;br /&gt;
email = bob.byomkin@otherplacenice.org&lt;br /&gt;
&lt;br /&gt;
# ...and so on.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;ascript-root&amp;lt;/tt&amp;gt; setting should be exactly &amp;lt;tt&amp;gt;summit-ascript&amp;lt;/tt&amp;gt;, for the reason mentioned later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit-message&amp;lt;/tt&amp;gt; field, if defined, allows team members to commit without providing a commit message. The value given by this field will be used by default, with translator's user name appended to the end in special syntax. For example: &amp;lt;tt&amp;gt;Translation updates. [&amp;gt;alice]&amp;lt;/tt&amp;gt;. (Translator's user name is also appended to manually supplied commit messages.) Translators can still supply a commit message when they wish, as shown later. If this field is not set, the commit message is supplied as usual on committing.&lt;br /&gt;
&lt;br /&gt;
* Team members are defined by &amp;lt;tt&amp;gt;[user-USERNAME]&amp;lt;/tt&amp;gt; sections. Ascription user names can be any valid ASCII identifier: ASCII letters, digits and underscores only, digit cannot be the first character. Ascription user names have no technical relation to the underlying VCS accounts, though it is mnemonically convenient if they are the same (in case of SVN). This means that a translator who does not have a VCS account (yet) can and should be added here, with assigned user name (best one suitable as SVN account name later); why this should be done will be explained later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field in user sections is there in case the preferred renderings of the name in English and in target language are not the same. When this is not the case, &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; can be omitted.&lt;br /&gt;
&lt;br /&gt;
As soon as the &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; file is committed, the ascription system is ready for operation. Only regular modifications to this file are those of adding new team members. (On the other hand, team members should never be removed, because even after they no longer contribute, their ascription records remain in the system.)&lt;br /&gt;
&lt;br /&gt;
=== Initial Ascription ===&lt;br /&gt;
&lt;br /&gt;
The most common situation at start of ascription workflow is that there already exists a body of translations, contributed to by many different people over time. The coordinator should ascribe all existing translations as initial modifications, but to whom? It cannot be said precisely who translated what. The solution is to introduce a generic user in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;, suitably known as &amp;quot;Unknown Hero&amp;quot; (or &amp;quot;Lost Translator&amp;quot;, you can be inventive):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[user-uhero]&lt;br /&gt;
name = Unknown Hero&lt;br /&gt;
original-name = Незнани јунак&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ascribe all existing translations as modified and reviewed by this user. The coordinator does this with the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe commit -u uhero --all-reviewed -C LANG/summit/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; is the ascription mode, and the &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option provides the user name to which ascriptions are made. This is an important point: ascriptions are made to a user defined in ascription configuration, and have nothing to do with VCS accounts; someone who has the account can commit in the name of someone who does not. It is the &amp;lt;tt&amp;gt;--all-reviewed&amp;lt;/tt&amp;gt; option that declares all messages to be reviewed as well (note that it is normally used only this once, and not for normal day to day reviewing). The &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option prevents automatic adding and committing to version control, which is useful for this initial step. Finally the paths which contain all summit catalogs are given.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command is issued, a progress bar will appear, and the following output will start to unfold:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
LANG/summit/messages/extragear-base/rellinks.po  (50/50)&lt;br /&gt;
LANG/summit/messages/extragear-base/autorefresh.po  (13/13)&lt;br /&gt;
LANG/summit/messages/extragear-base/babelfish.po  (38/38)&lt;br /&gt;
...&lt;br /&gt;
LANG/summit/messages/qt/libphonon.po  (13/13)&lt;br /&gt;
LANG/summit/messages/qt/phonon-xine.po  (24/24)&lt;br /&gt;
LANG/summit/messages/qt/phonon_gstreamer.po  (12/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated    111775    111775&lt;br /&gt;
fuzzy          26943     26943&lt;br /&gt;
obsolete/t      2965      2965&lt;br /&gt;
obsolete/f      1626      1626&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number in parenthesis indicates how many messages have been ascribed in the given PO file (modified/reviewed), and at the end the totals are given. Ascribing the complete summit for the first time will take quite some time (on the order of 10-20 minutes).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--If, on the contrary, it is known who translated and reviewed what, ascription can be performed piece-wise with user names of real translators:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support/LANG/summit&lt;br /&gt;
$ poascribe commit -u alice --all-reviewed -C kdelibs/ kdepimlibs/ kdebase/&lt;br /&gt;
$ poascribe commit -u bob --all-reviewed -C kdemultimedia/ kdeutils/&lt;br /&gt;
$ ...&lt;br /&gt;
&amp;lt;/code&amp;gt;//--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the initial ascription has been made, the ascription tree will appear next to the summit tree. This tree will contain one ascription PO file for each summit PO file, with the same name and relative location within the tree:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        ascription-config&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
        summit-ascript/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During the ascription some summit PO files may have been modified as well, in that any previous fields (&amp;lt;tt&amp;gt;#| ...&amp;lt;/tt&amp;gt;) on translated messages have been removed. (These fields are sometimes erroneously left in by older PO editors.)&lt;br /&gt;
&lt;br /&gt;
The newly created ascription tree (and any modifications to summit tree) can now be committed as usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn add LANG/summit-ascript&lt;br /&gt;
$ svn commit LANG/summit LANG/summit-ascript -m &amp;quot;Initial ascription.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Translators ==&lt;br /&gt;
&lt;br /&gt;
Team members other than the coordinator, whether translators or reviewers, need to keep around only the &amp;lt;tt&amp;gt;trunk/l10n-support/LANG/&amp;lt;/tt&amp;gt; directory. But they always need to update this directory fully (rather than just one particular module or file under &amp;lt;tt&amp;gt;.../*messages/&amp;lt;/tt&amp;gt;), so that the summit tree and the ascription tree (and configuration) are kept in sync.&lt;br /&gt;
&lt;br /&gt;
In order not to have to issue their own user name (&amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;) all the time, translators can set it in Pology user configuration &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, in &amp;lt;tt&amp;gt;[poascribe]&amp;lt;/tt&amp;gt; section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = alice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translators can then submit updated PO files simply by substituting &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt; (or whatever the VCS commit command is) with &amp;lt;tt&amp;gt;poascribe commit&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;co&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;ci&amp;lt;/tt&amp;gt; for short):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdefoo/*fooapp*.po&lt;br /&gt;
LANG/summit/messages/kdefoo/fooapp.po  (144)&lt;br /&gt;
LANG/summit/messages/kdefoo/libfooapp.po  (25)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified&lt;br /&gt;
translated       169&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; VCS is committing catalogs:&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/libfooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/libfooapp.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1267069.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will add ascription records into ascription catalogs corresponding to summit catalogs to be committed, and commit them all. Like &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt; can take any number of file or directory paths, and can be issued from any working directory (it will always find ascription catalogs). If default commit message has not been set in the ascription configuration, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will ask for it; or it can be given in command line through &amp;lt;tt&amp;gt;-m&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
=== Translators Without Commit Access ===&lt;br /&gt;
&lt;br /&gt;
With the ascription system in place, every regular team member should have commit access. But, there may be some period of time before new translators are given accounts, revision control may be too technical for some, and even those with the account may not be able to commit temporarily for some reason.&lt;br /&gt;
&lt;br /&gt;
These translators may send in their work by email, to ''any'' team member with commit access (not necessarily the coordinator or a reviewer); this team member can commit received files without any review, as review can be conducted at any later time. If Bob sends some files to Alice, she can commit them immediately by stating Bob's user name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -u bob ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, the translator who sent in the files has to be defined in the ascription configuration. There are no hidden costs or security issues to this (as opposed to opening a VCS account), so every new translator should be defined there before any work of that person is committed.&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Reviewers ==&lt;br /&gt;
&lt;br /&gt;
The ascription system opens up all sorts of possibilities for concrete review patterns. Reviewers should keep in mind that for each message the full modification and review history is available, so that the team can think about how to make good use of it. Therefore, what follows are some examples to illustrate the review facilities that &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; provides.&lt;br /&gt;
&lt;br /&gt;
=== Basic Reviewing ===&lt;br /&gt;
&lt;br /&gt;
At the very basic level (which is the only level in classical review by stages), messages can be classified into simply unreviewed and reviewed, without further qualifiers. Alice now wants to review all unreviewed messages in a group of PO files, say &amp;lt;tt&amp;gt;kdetoys&amp;lt;/tt&amp;gt; module. She issues (&amp;lt;tt&amp;gt;di&amp;lt;/tt&amp;gt; is short for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe di LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===== Diffed for review: 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unreviewed messages have now been marked and diffed, inside the listed PO files. What is this about &amp;quot;diffing&amp;quot;? If the files had already been reviewed before, some of the messages modified since then (those marked for review) may have changed very little (e.g. a few words in a paragraph-length message, or even just punctuation). Therefore, for each message marked for review, Alice also wants to see the diff since last review to current version. Here are two messages in typical review states added by &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: charlie:m&lt;br /&gt;
#: gui/mainwindow.cc:372&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;GAME OVER. {-You won-}{+Tie+}!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KRAJ IGRE. {-Pobeda-}{+Nerešeno+}!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: bob:m charlie:m&lt;br /&gt;
#: game-state.cpp:117&lt;br /&gt;
#, ediff-total&lt;br /&gt;
msgid &amp;quot;Click the pause button again to resume the game.&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Kliknite ponovo na dugme pauze da nastavite igru.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the first one in Kate:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_poascribe_diff_01.png|center|Message diffed for review by poascribe in Kate.]]&lt;br /&gt;
&lt;br /&gt;
In the first message, the first to note is the &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment. This comment succinctly lists who did what with the message since the last review; here &amp;lt;tt&amp;gt;charlie:m&amp;lt;/tt&amp;gt; means that Charlie is the one who modified it. Then, there is the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, which alice can use it to jump through messages marked for review. Finally, the original and translation have been diffed; here they show that, since the last review, the message was fuzzied by changing &amp;quot;You won&amp;quot; to &amp;quot;Tie&amp;quot;, and what Charlie did in translation to unfuzzy it. Even on a message as short as this, the diff tells something useful to Alice: the phrase &amp;quot;Game over&amp;quot; likely has a formulaic translation, and the fact that it is not part of the diff means that the earlier reviewer had made sure it is consistent, so Alice does not have to check that.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment of the second message reveals that both Charlie and Bob had been translating it. &amp;lt;tt&amp;gt;ediff-total&amp;lt;/tt&amp;gt; flag instead of plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; means that this message had no review at all up to now, so there are no embedded diffs in text fields.&lt;br /&gt;
&lt;br /&gt;
Alice can now go through marked files and messages, review translations, and possibly make modifications. When making changes in a message with embedded diffs, she can freely edit text outside of difference segments and within &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments (as these are the ones which belong to current version of the text). While reviewing, Alice does ''not'' remove any of the added message elements while reviewing (save for an occasional difference segment, when translation should be modified), as these elements are needed for later. If a message is particularly hard and Alice wants to defer its review for later, she can add the &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; for short) flag to it.&lt;br /&gt;
&lt;br /&gt;
Once the review is complete, Alice simply commits the reviewed files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (0/2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (0/7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (3/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated         3        21&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; VCS is committing catalogs:&lt;br /&gt;
Sending      LANG/summit/messages/kdegames/palapeli.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/bovo.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/kdiamond.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/palapeli.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1284220.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three things have happened here. First, all review states (flags, embedded diffs, etc.) have been removed, restoring the PO file to normal. Then, any modifications that Alice have made during review are ascribed to her (here 3 out of 21 messages). Finally, all marked messages are ascribed as reviewed by Alice (any with &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; flags would have been omitted here). When committing, the only summit catalog that got committed is the one with modifications made during review, and all the ascription catalogs were committed because of the reviews recorded in them.&lt;br /&gt;
&lt;br /&gt;
When many files with few changes in each are to be reviewed, it becomes burdensome to manually open each and every diffed for review, and then to make sure that all are committed with &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt;. To make this easier, &amp;lt;tt&amp;gt;-w torevivew.out&amp;lt;/tt&amp;gt; option can be added to &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;, which requests that paths of all diffed PO files are written into &amp;lt;tt&amp;gt;torevivew.out&amp;lt;/tt&amp;gt; file. This file can then be used to batch open POs for review in the editor, as well as fed back on &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;-f torevivew.out&amp;lt;/tt&amp;gt;. There is also the &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; option which causes &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; to directly open PO files in a PO editor (though this is currently applicable only to Lokalize). Putting it together, to efficiently review a whole bunch of small changes throughout many files, Alice can:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di PATHS... -w toreview.out -o lokalize&lt;br /&gt;
$ # ...only marked messages opened in Lokalize, review them...&lt;br /&gt;
$ poascribe ci -f toreview.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selecting Messages for Review ===&lt;br /&gt;
&lt;br /&gt;
Invocations of &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; without any options, as in the previous section, were actually equivalent to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; is issuing the message ''selector''. &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is the default selector for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt; mode, and stands for MODified-After-Review: it selects the earliest historical modification of the message after the last (or no) review of that message, if there is any such. By selecting a historical modification of the message, the diff from it to current version can be computed and embedded into the PO file, as in previous examples.&lt;br /&gt;
&lt;br /&gt;
There are various specialized selectors, and fall into two groups: ''shallow selectors'' and ''history selectors''. Shallow selectors look only into the current version of the message, and cannot select historical versions, which means that they cannot provide embedded diffs. History selectors (&amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is of this type) can select messages from history and provide diffs. Several selectors can be issued on the command line, and the message is selected only if all selectors select it. Shallow selectors are then normally used as a pre-filter for history selectors. For example, to select messages modified after last reviewed, but only those found in stable branch, &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; selectors are chained:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s branch:stable -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that the history selector is given last, because the last selector determines which historical message is selected. If the ordering had been reversed here, same messages would get selected, but they would not have embedded diffs, because &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; is a shallow selector.&lt;br /&gt;
&lt;br /&gt;
Selectors can take parameters themselves, like &amp;lt;tt&amp;gt;branch:stable&amp;lt;/tt&amp;gt; in the previous example. Parameters are separated from the selector name by any non-alphanumeric character; this is colon by convention, but if a parameter contains a colon, something like slash, tilde, etc. can be used. Number of parameters can be variable, and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; in particular can take from none to three. If Alice wants to review only those messages modified ''by Charlie'' since last review, she states this by first argument to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:charlie PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Alice does not give too much credit to other reviewers, she can request selection of messages modified after last review ''by her'' with second parameter to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar::alice PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the first parameter (&amp;quot;modified by...&amp;quot;), which is not needed, must be explicitly skipped, before going to the second parameter (&amp;quot;reviewed by...&amp;quot;). The third optional parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; will be mentioned in the next section.&lt;br /&gt;
&lt;br /&gt;
When a selector parameter is a user name, normally it can also be a comma-separated list of user names (&amp;lt;tt&amp;gt;modar:bob,charlie&amp;lt;/tt&amp;gt;) or prefixed with tilde to negate, i.e. select all other users (&amp;lt;tt&amp;gt;modar:~alice&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Any selector can be negated by prepending &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; to its name. For example, the history selector &amp;lt;tt&amp;gt;modafter:DATE&amp;lt;/tt&amp;gt; selects first modification after the given date; to select messages modified after last review, but only if modified during June 2010:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modafter:2010-06 -s nmodafter:2010-07 -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Negating a history selector produces a shallow selector: while &amp;lt;tt&amp;gt;modafter&amp;lt;/tt&amp;gt; is history selector, &amp;lt;tt&amp;gt;nmodafter&amp;lt;/tt&amp;gt; is shallow. But the order of the two in the previous command line is not important, as the last selector is the usual &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selectors can be issued in other modes too. If the PO file is big and Alice has reviewed messages up to and including entry 246 when she has to pause until another day, she can commit reviews only up to this entry by issuing the &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; selector:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -s espan::246 PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the first parameter to &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; is the first entry number, given if messages are not to be selected from the first). There is also the counterpart &amp;lt;tt&amp;gt;lspan&amp;lt;/tt&amp;gt; selector, which works with referent line numbers (those of &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; keywords) instead of entry numbers.&lt;br /&gt;
&lt;br /&gt;
=== Fine-Grained Reviews ===&lt;br /&gt;
&lt;br /&gt;
In the introduction, several distinct types of what can go wrong in translation were described. Not all reviewers may be able to check translation against all those problems. Here is a typical scenario of this kind:&lt;br /&gt;
&lt;br /&gt;
Alice is very computer-savvy and knows the translation project inside and out, which means that she can review well for context, terminology, and technical style. But, her language style leaves something to be desired, which shows through longer sentences and passages. Dan, on the other hand, is a very literary person, but not that much into the technical aspects. Dan's style reviews would thus be a perfect complement to Alice's general reviews.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; can support this scenario in the following way. A ''review type'' tag for language style is defined in the ascription configuration, using the &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[global]&lt;br /&gt;
...&lt;br /&gt;
review-tags = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The value to &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; is a space-separated list of identifiers, when more than one special review type is needed.) With this addition to configuration, Alice can continue to review as she did before, without any changes to her workflow.&lt;br /&gt;
&lt;br /&gt;
Dan selects messages for review similarly to Alice, but aditionally giving the &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; tag as ''third'' parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;, and indicating that ascribed reviews should be tagged as &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:::lstyle -t lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After finishing the review, Dan commits as usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Dan is always going to review the language style, in order not to have to issue the selector and tag in the command line all the time, he can make them default per mode in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = dan&lt;br /&gt;
selectors/diff = modar:::lstyle&lt;br /&gt;
tags/diff = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this Dan can use plain &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; just like Alice does.&lt;br /&gt;
&lt;br /&gt;
The important point of review tags is that they make reviews by types independent. For example, Dan may come around to review the language style of the given message after several modifications and general reviews have been ascribed to it -- &amp;lt;tt&amp;gt;modar:::lstyle&amp;lt;/tt&amp;gt; will simply ignore all reviews except for &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews. This is going to be reflected in the &amp;lt;tt&amp;gt;ascto:&amp;lt;/tt&amp;gt; comment to marked messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: charlie:m alice:r bob:m&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here Alice has made one review between Charlie's and Bob's modifications, and that review, being general instead of &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;, did not cause &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; to stop at it. After Dan reviews this message for language style, Alice runs selection for review and gets this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: bob:m dan:r(lstyle)&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, since &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews do not mix with general reviews, Dan's review did not hide Bob's modification that Alice did not check so far.&lt;br /&gt;
&lt;br /&gt;
(General review too has a tag assigned, the empty string, in case the reviewer needs to explicitly issue it in some context.)&lt;br /&gt;
&lt;br /&gt;
== Daily Use for The Coordinator ==&lt;br /&gt;
&lt;br /&gt;
After setting up the ascription system, the team coordinator should have to do very little to maintain it.&lt;br /&gt;
&lt;br /&gt;
=== Ascribing Merges ===&lt;br /&gt;
&lt;br /&gt;
Modifications made to summit catalogs by merging with templates must also be ascribed. Therefore, after merging the summit (&amp;lt;tt&amp;gt;posummit ... merge ...&amp;lt;/tt&amp;gt;) the coordinator substitutes the VCS command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command in &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the user is not explicitly given by &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option, this will ascribe merge modifications to the coordinator (more precisely, to the user set as default in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;), which is just fine. It is also possible to define a special user only for ascribing merge modifications, though there is no known advantage to that.&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option is not issued, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will automatically commit all modified summit and ascription catalogs when done.&lt;br /&gt;
&lt;br /&gt;
=== Shuffling Ascription Catalogs  ===&lt;br /&gt;
&lt;br /&gt;
Sometimes summit catalogs are shuffled in the repository: moved to another module, renamed, one catalog split into two, two catalogs merged into one. Such shuffling should be exactly mirrored in the ascription tree, and this too is done on the repository side, at the same time. This relies on the ascription root being set exactly to &amp;lt;tt&amp;gt;summit-ascript&amp;lt;/tt&amp;gt; in the ascription configuration. So the team coordinator has nothing special to do here.&lt;br /&gt;
&lt;br /&gt;
If instead in the central KDE repository the translation team is working in an external repository, by consequence the ascription system must be set up in that repository. But so long as &amp;lt;tt&amp;gt;process_orphans.sh&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; is used to shuffle catalogs in the external repository as well, the ascription catalogs will be properly handled.&lt;br /&gt;
&lt;br /&gt;
== Filtering for Release ==&lt;br /&gt;
&lt;br /&gt;
The last component of the ascription system is how to prevent insufficiently reviewed messages from leaking into a release. In context of Pology and summit workflow, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; itself is not used directly to this end. Instead, in the summit configuration (as opposed to ascription configuration), the team coordinator defines filters which pass messages by applying selectors.&lt;br /&gt;
&lt;br /&gt;
Each top level PO tree has its own summit configuration file, named &amp;lt;tt&amp;gt;MSGTREE.extras.summit&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            messages.extras.summit&lt;br /&gt;
            docmessages/&lt;br /&gt;
            docmessages.extras.summit&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the simple case of all reviews being general reviews, the filter is added to summit configuration like this (anywhere within &amp;lt;tt&amp;gt;*.extras.summit&amp;lt;/tt&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the filter is named &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;, and is defined as application of &amp;lt;tt&amp;gt;nmodar&amp;lt;/tt&amp;gt; selector, the negation of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;. This simply means: pass all messages ''not'' modified after the last review.&lt;br /&gt;
&lt;br /&gt;
When the team coordinator scatters to branches (executes &amp;lt;tt&amp;gt;posummit scatter&amp;lt;/tt&amp;gt;), messages from summit POs which do not pass this filter will not be sent to branch POs. The count of stopped messages by branch PO will be reported in the output as scattering proceeds.&lt;br /&gt;
&lt;br /&gt;
Why did we have to name the filter &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;? (Those knowing some Python will also notice that it is defined as a list element.) Because it is possible to define more than one filter, and select which one is used on each scattering. For example, the coordinator may wish that, when the release is near and time is short to review everything, messages from a few experienced translators can be passed into release without review. If those translators are Alice and Bob, an &amp;quot;emergency&amp;quot; filter can be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; uses the first filter in the list. When the coordinator needs to do emergency scattering, he requests the emergency filter by the &amp;lt;tt&amp;gt;-a&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter -a emergency&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What if several selectors are needed to pass the message? For example, the language style review (the earlier example with Alice and Dan) too may be requested for regular scattering, but omitted from emergency scattering. The filter setup for this scenario looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;, &amp;quot;nmodar:::lstyle&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The regular filter now reads: pass the message if it has not been modified after the last (general) review ''and'' has not been modified after the last style review.&lt;br /&gt;
&lt;br /&gt;
Simple combination of predefined selectors by AND-conditions may not be sufficient for more involved scenarios. When this is the case, the coordinator may write (or ask someone to write) a custom selector in Python, and plug it in as the second element in the filter tuple (instead of the list of predefined selectors).&lt;br /&gt;
&lt;br /&gt;
=== Writing a Selector Function ===&lt;br /&gt;
&lt;br /&gt;
((To be written.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Tools/Pology</id>
		<title>Localization/Tools/Pology</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Tools/Pology"/>
				<updated>2010-08-01T16:46:49Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Adaptations to changes in Pology directory structure.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Tools/Pology}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Tools|Tools]]|&lt;br /&gt;
name=Pology|&lt;br /&gt;
prereqs=[[Localization/Tools/Gettext_Tools|Gettext Tools]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== About ==&lt;br /&gt;
&lt;br /&gt;
Pology is a Python framework for custom processing of PO files. It aims to facilitate easy, fast and robust creation of scripts for tackling problems encountered in the &amp;quot;field&amp;quot;, everyday translation work, and to collect all sorts of specific, narrow purpose tools written in this direction. It does not aim to be a collection of several feature-rounded, monolithic, and general purpose tools (though it may contain some which could qualify). In particular, it does not attempt to handle any other translation formats but PO. All of Pology's end-user tools and programming interfaces are geared towards the PO format and conventions. The name itself should be parsed as PO-logy, &amp;quot;the study of POs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
At the moment, Pology still has not reached release state. But it can already be used effectively for day-to-day work, especially through end-user scripts. Obtaining and preparing Pology for use is simple: fetch its code repository, set &amp;lt;tt&amp;gt;PATH&amp;lt;/tt&amp;gt; to use the scripts that come with it, and possibly set &amp;lt;tt&amp;gt;PYTHONPATH&amp;lt;/tt&amp;gt; to be able to write own code based on Pology. The following commands should suffice:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn co svn://anonsvn.kde.org/home/kde/trunk/l10n-support/pology&lt;br /&gt;
$ export PATH=$PWD/pology/bin:$PATH&lt;br /&gt;
$ export PYTHONPATH=$PWD/pology:$PYTHONPATH&lt;br /&gt;
$ . $PWD/pology/completion/bash/pology&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Of course, for continuous use, environment variables should rather be set in &amp;lt;tt&amp;gt;~/.bashrc&amp;lt;/tt&amp;gt; (or another shell configuration file). The last line sources programmable shell completion for some of Pology's commands. After these steps are successfully performed, Pology is fully prepared for use and scripting.&lt;br /&gt;
&lt;br /&gt;
== Ready-Made Tools ==&lt;br /&gt;
&lt;br /&gt;
Pology provides a number of tools for end use, with varying degrees of specificity, embodied as several scripts within &amp;lt;tt&amp;gt;scripts/&amp;lt;/tt&amp;gt; subfolder of Pology's source. Details of operation of each script are provided within Pology documentation (&amp;lt;tt&amp;gt;doc/html/index.html&amp;lt;/tt&amp;gt;, node &amp;lt;tt&amp;gt;pology.scripts&amp;lt;/tt&amp;gt;), and the following sections give overview and some examples of their functionality.&lt;br /&gt;
&lt;br /&gt;
=== Sieving ===&lt;br /&gt;
&lt;br /&gt;
((To be done.))&lt;br /&gt;
&lt;br /&gt;
=== Diffing and Patching ===&lt;br /&gt;
&lt;br /&gt;
Line-oriented diffing and patching, as conducted by &amp;lt;tt&amp;gt;diff(1)&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;patch(1)&amp;lt;/tt&amp;gt; commands, is not quite appropriate for PO files. Due to PO content being composed of variably-formatted multiline entries, which combine translator, programmer, and automatically controlled elements, line-oriented diff may indicate difference where semantically there is none, or not show real difference in a useful form. One could even claim line diffing of PO files to be almost useless, especially for the purpose of sending patches for translation.&lt;br /&gt;
&lt;br /&gt;
For this reason, Pology contains two scripts, &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt;, which create message-oriented, ''embedded'' diffs of PO files. These diffs can be used both for reviewing changes and applying patches to PO files. Concept of embedded diffing and details on operation of the mentioned scripts are described in a [[Localization/Tools/Pology/PO_Embedded_Diffing|separate article]].&lt;br /&gt;
&lt;br /&gt;
=== Reformatting ===&lt;br /&gt;
&lt;br /&gt;
((To be done.))&lt;br /&gt;
&lt;br /&gt;
=== Heavy Artillery ===&lt;br /&gt;
&lt;br /&gt;
((To be done.))&lt;br /&gt;
&lt;br /&gt;
== Writing Own Tools ==&lt;br /&gt;
&lt;br /&gt;
Pology comes with detailed API documentation, but for a quick start into writing custom tools based on Pology, the following sections will describe and illustrate some of its more salient elements.&lt;br /&gt;
&lt;br /&gt;
=== Catalogs and Messages ===&lt;br /&gt;
&lt;br /&gt;
For an obligatory hello-world demonstration, let us create a PO template named &amp;lt;tt&amp;gt;hello.pot&amp;lt;/tt&amp;gt; with a single message of this greet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
from pology.catalog import Catalog&lt;br /&gt;
from pology.message import Message&lt;br /&gt;
&lt;br /&gt;
cat = Catalog(&amp;quot;hello.pot&amp;quot;, create=True, truncate=True)&lt;br /&gt;
msg = Message()&lt;br /&gt;
msg.msgid = u&amp;quot;Hello, world!&amp;quot;&lt;br /&gt;
cat.add(msg)&lt;br /&gt;
cat.sync()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Most of these few lines are self-explanatory, except the last one: modifications to catalogs in Pology are never automatically written to disk, instead the &amp;lt;tt&amp;gt;sync()&amp;lt;/tt&amp;gt; method must be called to initiate writes. Catalog is not gone after this, but you can continue to use it normally, including further syncings. In this example, after syncing the file &amp;lt;tt&amp;gt;hello.pot&amp;lt;/tt&amp;gt; will be created in current working directory.&lt;br /&gt;
&lt;br /&gt;
Practically, however, it is usually Gettext tools that will be used to create templates and catalogs, while a much more common use of Pology is to iterate over existing catalogs. The following code will open a catalog with various greetings, look for all messages that contain &amp;quot;hello&amp;quot; in the original text but do ''not'' contain &amp;quot;zdravo&amp;quot; in the translation, and report their content to standard output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
from pology.catalog import Catalog&lt;br /&gt;
from pology.msgreport import report_msg_content&lt;br /&gt;
&lt;br /&gt;
cat = Catalog(&amp;quot;greets.po&amp;quot;)&lt;br /&gt;
for msg in cat:&lt;br /&gt;
    if &amp;quot;hello&amp;quot; in msg.msgid.lower():&lt;br /&gt;
        matched = False&lt;br /&gt;
        for text in msg.msgstr:&lt;br /&gt;
            if &amp;quot;zdravo&amp;quot; in text.lower():&lt;br /&gt;
                matched = True&lt;br /&gt;
                break&lt;br /&gt;
        if not matched:&lt;br /&gt;
            report_msg_content(msg, cat)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note how &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; is represented as a list regardless of whether the message is plural or not, the difference being only in the number of elements. This removes the special case of singular/plural translations, and makes programmer always think of plural messages (though plural of original text is accessed through &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt; instance variable). Function &amp;lt;tt&amp;gt;report_msg_content&amp;lt;/tt&amp;gt; will output the message to standard output, nicely formatted and preceded with a line stating the originating catalog and message's referent line and entry number in it. But &amp;lt;tt&amp;gt;report_msg_content&amp;lt;/tt&amp;gt; can do much more, e.g. highlight parts of the message in the shell, add notes and delimiters, and so on (its API documentation provides all the details). Since no changes were done to the catalog, it is perfectly fine, even appropriate, not to call &amp;lt;tt&amp;gt;sync()&amp;lt;/tt&amp;gt; at the end.&lt;br /&gt;
&lt;br /&gt;
Of course, the previous snippet is just an illustration of iterating through catalogs and examining messages, in practice superfluous next to the functionality already provided by &amp;lt;tt&amp;gt;find-messages&amp;lt;/tt&amp;gt; sieve:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve find-messages -smsgid:'hello' -snmsgstr:'zdravo' greets.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
((To be continued...))&lt;br /&gt;
&lt;br /&gt;
=== Sieves ===&lt;br /&gt;
&lt;br /&gt;
((To be done.))&lt;br /&gt;
&lt;br /&gt;
=== Hooks ===&lt;br /&gt;
&lt;br /&gt;
((To be done.))&lt;br /&gt;
&lt;br /&gt;
=== Language Support ===&lt;br /&gt;
&lt;br /&gt;
((To be done.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Concepts/Transcript</id>
		<title>Localization/Concepts/Transcript</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Concepts/Transcript"/>
				<updated>2010-07-23T21:53:57Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Example of dynamic contexts with dependent labels.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Concepts|Concepts]]|&lt;br /&gt;
name=Translation Scripting with Transcript|&lt;br /&gt;
prereqs=[[Localization/Concepts/PO_Odyssey|The PO Format]]|&lt;br /&gt;
extread=[http://developer.mozilla.org/en/docs/JavaScript JavaScript Guide and Reference]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Translation Scripting? ==&lt;br /&gt;
&lt;br /&gt;
Current state of affairs in localization of user-visible strings (messages) in application interfaces is such that translator is sometimes forced to supply an inadequate translation. This problem typically occurs when a message contains a placeholder to be substituted at runtime, or when two unrelated strings become related by placement in the interface. In either case, the modest requirements of english language on congruence of words in a sentence allow original string to remain grammatically correct, while not so in many other languages.&lt;br /&gt;
&lt;br /&gt;
Translators and programmers sometimes try to work out a change in the code which would provide a more workable alternative. However, this process is difficult, and worse yet, the outcome is still language-dependent: solving the problem for a few languages does not necessarily solve it for all other.&lt;br /&gt;
&lt;br /&gt;
One way to overcome these problems in a more general and compartmentalized manner, is to provide translators with a way to modify translated strings at runtime, depending on the context (eg. particular placeholder substitutes). In other words, to script translation. Translator should be able to operate on any interface string he wishes, while the programmer should not bear any extra burden (or know about translation scripting at all).&lt;br /&gt;
&lt;br /&gt;
== The Transcript Engine ==&lt;br /&gt;
&lt;br /&gt;
KDE4 comes ready with a translation scripting system, the ''Transcript''. Several strategic choices were made in its design:&lt;br /&gt;
&lt;br /&gt;
* programmers are unaware of scripting, which means that translator can script any message without outside coordination&lt;br /&gt;
&lt;br /&gt;
* unless translator wants to script a message, he is faced with familiar, standard Gettext PO environment (i.e. translators too ''can'' be scripting-agnostic)&lt;br /&gt;
&lt;br /&gt;
* scripting is a low-level bolt-on to Gettext environment, to keep existing PO tools in the game&lt;br /&gt;
&lt;br /&gt;
* to have enough power for unforeseen needs, a general-purpose scripting language is provided: JavaScript (with extensions for interfacing with Transcript)&lt;br /&gt;
&lt;br /&gt;
{{note|For comparison, another translation scripting approach taking some different decisions (new translation environment down to the file format, scripting facilities more specialized, etc.) is brewing at http://wiki.mozilla.org/L20n}}&lt;br /&gt;
&lt;br /&gt;
To script a particular message, translator writes short scripting calls into msgstr in the PO file which expand into parts of msgstr (''interpolations''), and JavaScript code which defines these calls into accompanying Transcript module file (eg. {{path|foo.po}} can be augmented with {{path|foo.js}}).&lt;br /&gt;
&lt;br /&gt;
In case the application draws translations from several PO files, scripting calls defined in one of the Transcript modules are available in all used PO files. Since every KDE app uses {{path|kdelibs.po}}, calls defined in {{path|kdelibs.js}} are available everywhere.&lt;br /&gt;
&lt;br /&gt;
The scripting process is illustrated by several examples. More detailed explanations of the elements are given in following sections.&lt;br /&gt;
&lt;br /&gt;
=== A Useless Example ===&lt;br /&gt;
&lt;br /&gt;
In Nevernessian it is impolite to speak out a greet with the same tone of voice throughout; instead, the name of the person must be shouted out. Hence, the translator wants to capitalize the placeholder substitute in the following login greet in {{path|neverness.po}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: neverness_login.cpp:10&lt;br /&gt;
msgid &amp;quot;Hello, %1!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Heelyy, %1!&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So the translator adds a scripted msgstr, with an interpolation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: neverness_login.cpp:10&lt;br /&gt;
msgid &amp;quot;Hello, %1!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Heelyy, %1!&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;Heelyy, $[shout %1]!&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first thing to note is that, while a bit longer, msgstr is still a proper PO msgstr, which means that it can be edited and processed by the usual PO tools.&lt;br /&gt;
&lt;br /&gt;
The first part of msgstr is same as before, and called the ''fallback'' in this context: if the scripted part happens to fail in some way, the fallback translation is used. The fallback is followed by the ''fence'' &amp;lt;tt&amp;gt;|/|&amp;lt;/tt&amp;gt;, which separates the fallback and scripted translation (and, for that matter, indicates that this message is scripted).&lt;br /&gt;
&lt;br /&gt;
Finally, there is the scripted translation after the fence. Compared to fallback, it contains the interpolation &amp;lt;tt&amp;gt;$[shout %1]&amp;lt;/tt&amp;gt;, which is supposed to evaluate to a capitalized version of the placeholder substitute. It is composed of the call name, &amp;lt;tt&amp;gt;shout&amp;lt;/tt&amp;gt;, and one argument to it, the &amp;lt;tt&amp;gt;%1&amp;lt;/tt&amp;gt; placeholder which will be replaced by its substitute. The syntax and expansion rules for interpolations are similar to Unix shell.&lt;br /&gt;
&lt;br /&gt;
The call &amp;lt;tt&amp;gt;shout&amp;lt;/tt&amp;gt; itself is defined in the Transcript module {{path|neverness.js}}, which contains only these lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function capitalize (str) {&lt;br /&gt;
    return str.toUpperCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Ts.setcall(&amp;quot;shout&amp;quot;, capitalize);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the function &amp;lt;tt&amp;gt;capitalize&amp;lt;/tt&amp;gt; is an ordinary JavaScript function which takes a string argument and returns all-caps version of it.&lt;br /&gt;
&lt;br /&gt;
The link with the PO file is established by the call to &amp;lt;tt&amp;gt;Ts.setcall()&amp;lt;/tt&amp;gt; -- the Transcript interface is represented by the property functions of the &amp;lt;tt&amp;gt;Ts&amp;lt;/tt&amp;gt; object. In this variant, the &amp;lt;tt&amp;gt;Ts.setcall()&amp;lt;/tt&amp;gt; takes the name of the call for the interpolations in the PO messages (a string), and the JavaScript function which will actually be invoked (''bound'' to the call).&lt;br /&gt;
&lt;br /&gt;
That's it, now the fair Nevernesse folks are greeted properly.&lt;br /&gt;
&lt;br /&gt;
=== Basic Case Resolution ===&lt;br /&gt;
&lt;br /&gt;
One problem frequently encountered is wrong noun case when placeholder is substituted in the msgstr. For example, in many languages every KDE app has such a problem in the Help menu, with one or both of &amp;quot;About %1...&amp;quot; and &amp;quot;%1 &amp;amp;Handbook&amp;quot;. This can be scripted in {{path|kdelibs.po}} like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
msgid &amp;quot;&amp;amp;About %1&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;amp;O %1&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;&amp;amp;O $[get-case dative %1]&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;get-case&amp;lt;/tt&amp;gt; interpolation is supposed to get the &amp;lt;tt&amp;gt;dative&amp;lt;/tt&amp;gt; case of whatever app name the &amp;lt;tt&amp;gt;%1&amp;lt;/tt&amp;gt; happens to be. The Transcript module {{path|kdelibs.js}} contains the definition of &amp;lt;tt&amp;gt;get-case&amp;lt;/tt&amp;gt;, as well as the dictionary of cases:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function getProperty (prop, key) {&lt;br /&gt;
    return _dict_[key][prop];&lt;br /&gt;
}&lt;br /&gt;
Ts.setcall(&amp;quot;get-case&amp;quot;, getProperty);&lt;br /&gt;
&lt;br /&gt;
_dict_ = {};&lt;br /&gt;
function addDictCases (key, gen, dat, acc, ins) {&lt;br /&gt;
    if (!_dict_[key])&lt;br /&gt;
        _dict_[key] = {};&lt;br /&gt;
    _dict_[key][&amp;quot;genitive&amp;quot;]     = gen;&lt;br /&gt;
    _dict_[key][&amp;quot;dative&amp;quot;]       = dat;&lt;br /&gt;
    _dict_[key][&amp;quot;accusative&amp;quot;]   = acc;&lt;br /&gt;
    _dict_[key][&amp;quot;instrumental&amp;quot;] = ins;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// dictionary entries follow:&lt;br /&gt;
addDictCases(&amp;quot;KWrite&amp;quot;, &amp;quot;KWritea&amp;quot;, &amp;quot;KWriteu&amp;quot;, &amp;quot;KWrite&amp;quot;, &amp;quot;KWriteom&amp;quot;);&lt;br /&gt;
addDictCases(&amp;quot;Konsole&amp;quot;, &amp;quot;Konsole&amp;quot;, &amp;quot;Konsoli&amp;quot;, &amp;quot;Konsolu&amp;quot;, &amp;quot;Konsolom&amp;quot;);&lt;br /&gt;
...&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Function &amp;lt;tt&amp;gt;getProperty&amp;lt;/tt&amp;gt;, bound to &amp;lt;tt&amp;gt;get-case&amp;lt;/tt&amp;gt; call, simply returns the entry from the dictionary of forms. Function &amp;lt;tt&amp;gt;addDictCases&amp;lt;/tt&amp;gt; is responsible for adding the static entries (name and its cases) into the dictionary, which is done in the final few lines for all apps of interest.&lt;br /&gt;
&lt;br /&gt;
This completes the example, but for better modularization, it is also possible split out the dictionary insertion in a separate file, eg. {{path|appdict.js}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// appdict.js&lt;br /&gt;
addDictCases(&amp;quot;KWrite&amp;quot;, &amp;quot;KWritea&amp;quot;, &amp;quot;KWriteu&amp;quot;, &amp;quot;KWrite&amp;quot;, &amp;quot;KWriteom&amp;quot;);&lt;br /&gt;
addDictCases(&amp;quot;Konsole&amp;quot;, &amp;quot;Konsole&amp;quot;, &amp;quot;Konsoli&amp;quot;, &amp;quot;Konsolu&amp;quot;, &amp;quot;Konsolom&amp;quot;);&lt;br /&gt;
...&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and use Transcript interface to load this file in the {{path|kdelibs.js}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// kdelibs.js&lt;br /&gt;
...&lt;br /&gt;
...&lt;br /&gt;
...&lt;br /&gt;
Ts.load(&amp;quot;appdict&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;Ts.load()&amp;lt;/tt&amp;gt; takes filename without extension, and assumes its location is relative to the folder of the parent file (ie. in this case {{path|kdelibs.js}} and {{path|appdict.js}} should be in the same folder).&lt;br /&gt;
&lt;br /&gt;
=== Dynamic Case Setting ===&lt;br /&gt;
&lt;br /&gt;
The previous scripted example solves the original problem, but introduces the burden of maintaining the dictionary insertion file. There is no way around this when the placeholder substitutes are &amp;quot;dead&amp;quot; strings from outside (eg. from {{path|.desktop}} files), but when they are coming from KDE's PO files at runtime, this burden can be removed.&lt;br /&gt;
&lt;br /&gt;
The app name in KDE's Help menu indeed comes from the app PO file, and it is of course encountered at runtime before the menu strings come into focus. This allows setting the cases of app name in the PO msgstr which contains it. For example, {{path|katepart.po}} contains the &amp;quot;KWrite&amp;quot; string, and the forms could be set at that point:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
msgid &amp;quot;KWrite&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KWrite&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;$[set-cases KWritea KWriteu KWrite KWriteom]&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;set-cases&amp;lt;/tt&amp;gt; is a ''side-effect'' interpolation: it should set the dictionary entries, but this particular message should in any case use the ordinary translation. Assuming all the definitions from previous example are still in effect, here is how &amp;lt;tt&amp;gt;set-cases&amp;lt;/tt&amp;gt; could be defined in {{path|kdelibs.js}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function dynamicSetCases (gen, dat, acc, ins) {&lt;br /&gt;
    addDictCases(Ts.msgstrf(), gen, dat, acc, ins);&lt;br /&gt;
    Ts.fallback();&lt;br /&gt;
}&lt;br /&gt;
Ts.setcall(&amp;quot;set-cases&amp;quot;, dynamicSetCases);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In other words, this is little more than a wrapper to &amp;quot;static&amp;quot; &amp;lt;tt&amp;gt;addDictCases&amp;lt;/tt&amp;gt; from previous example, but two new elements of Transcript interface appear. First is the &amp;lt;tt&amp;gt;Ts.msgstrf()&amp;lt;/tt&amp;gt; function, which returns the finalized ordinary translation (placeholders substituted), and which is needed in this case as the dictionary key. Second is the &amp;lt;tt&amp;gt;Ts.fallback()&amp;lt;/tt&amp;gt; function, which signalizes the Transcript engine to disregard the result of the scripted part of msgstr and use the ordinary translation.&lt;br /&gt;
&lt;br /&gt;
Admittedly, the use of &amp;lt;tt&amp;gt;Ts.fallback()&amp;lt;/tt&amp;gt; in this case is not necessary, but given for introductory purpose; &amp;lt;tt&amp;gt;dynamicSetCases&amp;lt;/tt&amp;gt; might as well ''return'' the ordinary translation via &amp;lt;tt&amp;gt;Ts.msgstrf()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The PO Shell ==&lt;br /&gt;
&lt;br /&gt;
This section gives the details of how the interpolations in the PO msgstr are expanded before evaluation.&lt;br /&gt;
&lt;br /&gt;
The interpolations are parts of msgstr between &amp;lt;tt&amp;gt;$[...]&amp;lt;/tt&amp;gt;, and are parsed into a number of strings. The first string is the name of the call registered in the scripting module via &amp;lt;tt&amp;gt;Ts.setcall()&amp;lt;/tt&amp;gt;, and the rest are the arguments to bound JavaScript function. The arguments are typically passed as JavaScript type &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, except in a special case detailed below.&lt;br /&gt;
&lt;br /&gt;
The special characters in the interpolation are whitespace, single quote (') and backslash (\). Whitespace separates arguments, whereas single quote can be used for text which contains whitespaces. The backslash is used as escape; it can escape whitespace in non-quoted text, or single quotes in quoted text. This is pretty much like a typical Unix shell.&lt;br /&gt;
&lt;br /&gt;
Double quotes are not special. Single quotes are used instead of double quotes because it makes it easier to edit interpolations in PO files, where double quotes would have to be escaped. This also means that when escape is needed in the interpolation, it must be escaped once itself for the PO msgstr.&lt;br /&gt;
&lt;br /&gt;
The biggest difference from the shell expansion is that unlike with shell variables, the placeholders are expanded such that no characters within them are treated as special. Otherwise, many tricky problems could arise with whitespace or single quotes contained inside.&lt;br /&gt;
&lt;br /&gt;
The call name bound to a JavaScript function using &amp;lt;tt&amp;gt;Ts.setcall()&amp;lt;/tt&amp;gt; does not have to be a proper JavaScript identifier, but any Unicode string not containing the interpolation-special characters. This means that more &amp;quot;natural&amp;quot; call names can be used inside the msgstr, like those with dashes or non-Latin1 characters. E.g. call names can be in the language of the PO file, for an aesthetic impression.&lt;br /&gt;
&lt;br /&gt;
Sub-interpolations, &amp;lt;tt&amp;gt;$[... $[...] ...]&amp;lt;/tt&amp;gt;, are also possible. If put inside inside single quotes, they will be treated as ordinary text. Thus, if a literal closing square bracket is needed as an argument inside the interpolation, it can be given within single quotes.&lt;br /&gt;
&lt;br /&gt;
In case that the argument is given as &amp;lt;tt&amp;gt;^''number''&amp;lt;/tt&amp;gt;, it will evaluate to the value supplied for the corresponding placeholder -- unlike the &amp;lt;tt&amp;gt;%''number''&amp;lt;/tt&amp;gt; form, which evaluates to the placeholder substitution string. Also, the argument type as seen by JavaScript need no longer be &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, but will correspond to the value substituted (e.g. &amp;lt;tt&amp;gt;Number&amp;lt;/tt&amp;gt;). This distinction may be important in some situations. Even if the value is originally a string, the substitution string may have extra formatting (padding, tags...), which may not be desirable. In particular, the number substitutes may come tagged or locale-formatted, such that they cannot be easily parsed back into &amp;lt;tt&amp;gt;Number&amp;lt;/tt&amp;gt;. In these cases, &amp;lt;tt&amp;gt;^''number''&amp;lt;/tt&amp;gt; form can be used to get the raw values.&lt;br /&gt;
&lt;br /&gt;
== The Transcript Interface ==&lt;br /&gt;
&lt;br /&gt;
Transcript provides extensions to the JavaScript, which interface with the PO file and the Transcript environment. They are all function properties of the &amp;lt;tt&amp;gt;Ts&amp;lt;/tt&amp;gt; object, accessible as &amp;lt;tt&amp;gt;Ts.''func''(''args'')&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;setcall (''name'', ''func'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;setcall (''name'', ''func'', ''obj'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Binds the call name to the JavaScript function, for use in the interpolations inside the PO file.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; name of the call. Can be any Unicode string, for ease of use in the msgstr&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''func''&amp;lt;/tt&amp;gt; function object&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''obj''&amp;lt;/tt&amp;gt; object to act as &amp;lt;tt&amp;gt;this&amp;lt;/tt&amp;gt; inside the function; if omitted, &amp;lt;tt&amp;gt;this&amp;lt;/tt&amp;gt; refers to global object&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;hascall (''name'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Check if the call for use in PO file has been set.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; name of the call&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if set, &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;acall (''name'', ''arg''*)&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Applies previously set PO call to a list of arguments, within the scripting module itself. Indirect calls can be made this way, e.g. by passing a call name as a string within PO file interpolation.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; name of the call&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''arg''*&amp;lt;/tt&amp;gt; arguments to the call&lt;br /&gt;
: Returns what the indirect call would return.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;load (''file''*)&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Evaluates the code in the specified files, in the left to right order. File paths are expected to be relative to current module's folder.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''file''&amp;lt;/tt&amp;gt; file name without extension&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;fallback ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Forces Transcript to use ordinary translation, regardless of whether the interpolation evaluates successfully or fails. The evaluation of the script is not aborted, any other interpolations will evaluate too.&lt;br /&gt;
: &amp;amp;nbsp;&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;msgid ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns msgid of the last message, with placeholders intact.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;msgstrf ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns finalized ordinary translation of the last message, with placeholders substituted.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;msgctxt ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns msgctxt of the last message, with placeholders intact.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;msgkey ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns a &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt; which is implementation-dependent combination of msgctxt and msgid with placeholders intact. Used to uniquely identify the message within the PO file, usefull as a dictionary key.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;nsubs ()&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns the number of substitutes provided for placeholders in the last message. It is equal to the highest-numbered placeholder for a proper i18n call in the application code, but i18n calls do not have to be quite proper.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;subs (''index'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Used to access values of placeholder substitutes provided to the last message. Numbering is zero-based.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''index''&amp;lt;/tt&amp;gt; index of placeholder substitute&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, regardless of the value type substituted in the application code.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;vals (''index'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Used to access values of placeholder values provided to the last message. Numbering is zero-based.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''index''&amp;lt;/tt&amp;gt; index of placeholder value&lt;br /&gt;
: Returns the matching JavaScript type to the value type used in the application code. E.g. strings will be &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, integers and doubles &amp;lt;tt&amp;gt;Number&amp;lt;/tt&amp;gt;. May also return &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;, in case the value cannot be represented as a reasonable JavaScript type.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;dynctxt (''key'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Programmers may append ''dynamic'' context to the message, which is a pair of strings: a context key and its value. Use this function to retrieve such contexts.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''key''&amp;lt;/tt&amp;gt; context key string&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt; if dynamic context with the given key does not exist.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;dbgputs (''msg'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Outputs a debug message in the shell when KDE has been compiled with debug option.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''msg''&amp;lt;/tt&amp;gt; message string&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;setcallForall (''name'', ''func'', ''obj'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;setcallForall (''name'', ''func'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Similar to &amp;lt;tt&amp;gt;setcall()&amp;lt;/tt&amp;gt;, but the function is executed on every message after it has been finalized (if the message was explicitly scripted, the function is executed after the script has been evaluated). The function receives no arguments, and its return value is ignored, i.e. it cannot change the finalized message; the call is used for side-effects. The &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; parameter is used only for reporting errors. When several &amp;lt;tt&amp;gt;setcallForall()&amp;lt;/tt&amp;gt; have been issued, the functions are invoked in the order of issue.&lt;br /&gt;
: &amp;amp;nbsp;&lt;br /&gt;
: More precisely, these calls are made on every message ''after'' the Transcript engine has been initialized, which happens on first explicitly scripted message. Thus, if earlier application of the calls is necessary, Transcript can be jump-started by scripting one early encountered message with only a single empty interpolation: &amp;lt;tt&amp;gt;msgstr &amp;quot;...|/|$[]&amp;quot;&amp;lt;/tt&amp;gt;; this will do nothing for that message, but it will start the engine.&lt;br /&gt;
: &amp;amp;nbsp;&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;toUpperFirst (''text'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Converts the first letter in the string into upper case, even if the first character in the string is not a letter. Unicode specification is used to determine what a letter is (i.e. works for non-ASCII letters).&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''text''&amp;lt;/tt&amp;gt; string to process&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;toLowerFirst (''text'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Converts the first letter in the string into lower case, under same assumptions as for &amp;lt;tt&amp;gt;toUpperFirst&amp;lt;/tt&amp;gt;.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''text''&amp;lt;/tt&amp;gt; string to process&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;loadProps (''file''*)&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Loads [[#Property Maps|property maps]] from the specified files. File paths are expected to be relative to current module's folder.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''file''&amp;lt;/tt&amp;gt; file name without extension&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;getProp (''phrase'', ''prop'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Fetches the property value of the phrase, as defined by [[#Property Maps|property map]].&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''phrase''&amp;lt;/tt&amp;gt; text for which the property is requested&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''prop''&amp;lt;/tt&amp;gt; property key string&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt; if the given text has no such property.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;setProp (''phrase'', ''prop'', ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Sets the property value of the phrase. The phrase and property key will be automatically normalized, as they would have been when loaded from a [[#Property Maps|property map]] file.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''phrase''&amp;lt;/tt&amp;gt; text for which the property is set&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''prop''&amp;lt;/tt&amp;gt; property key string&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''value''&amp;lt;/tt&amp;gt; value of the property (string)&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;normKey (''phrase'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Normalizes the text by removing all whitespace, removing the accelerator, and lowercasing it, e.g. for use in near-match lookups.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''phrase''&amp;lt;/tt&amp;gt; text to be normalized&lt;br /&gt;
: Returns &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfString (''key'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfString (''key'', ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfBool (''key'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfBool (''key'', ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfNumber (''key'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
; &amp;lt;tt&amp;gt;getConfNumber (''key'', ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Fetches a value of the requested type from the [[#User Configuration|user-configuration]] file. A default value of the same type can be stated too (or else it defaults to &amp;lt;tt&amp;gt;undefined&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''key''&amp;lt;/tt&amp;gt; the name of the field in the configuration file&lt;br /&gt;
:: &amp;lt;tt&amp;gt;''value''&amp;lt;/tt&amp;gt; the default value, in case the key is not found&lt;br /&gt;
: Returns the configuration value if the key is found, or the default value or &amp;lt;tt&amp;gt;undefined&amp;lt;/tt&amp;gt; otherwise. If the configuration string is not a valid representation of the requested type, again the default or &amp;lt;tt&amp;gt;Undefined&amp;lt;/tt&amp;gt; is returned instead.&lt;br /&gt;
&lt;br /&gt;
=== Property Maps ===&lt;br /&gt;
&lt;br /&gt;
There is a frequent need to have different properties attached to the particular pieces of text. For example, case, gender, etc. may be considered as properties of a noun, or phrase with a subject/object role in a sentence. Sometimes it may be convenient (or necessary) to define and maintain the phrases and their properties in an external file. ''Property map'' is Transcript's built-in (i.e. efficient) way to handle such definitions.&lt;br /&gt;
&lt;br /&gt;
Property map files are text files in a simple dictionary format for writing down phrases with their properties (filenames must end in &amp;lt;tt&amp;gt;.pmap&amp;lt;/tt&amp;gt;). The format is best shown on the example:&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# cities.pmap&lt;br /&gt;
=:Athens:Atina:nom=Atina:gen=Atine:dat=Atini:acc=Atinu::&lt;br /&gt;
=:Paris:Pariz:nom=Pariz:gen=Pariza:dat=Parizu:acc=Pariz::&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Each entry starts with two characters, &amp;lt;tt&amp;gt;=:&amp;lt;/tt&amp;gt; in this example, which may be chosen arbitrarily (but must be non-letters, and non-#), and can change from entry to entry. The first character defines the separator in the property key-value pair, and the second character is the separator of pairs. E.g. the &amp;lt;tt&amp;gt;gen=Atine&amp;lt;/tt&amp;gt; segment above is defining the genitive case of the localized form of Athens. The &amp;quot;pairs&amp;quot; which actually lack the property key (first two in the entries above) are considered phrase identifiers. The completely empty pair (&amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt; in the example) terminates the entry.&lt;br /&gt;
&lt;br /&gt;
The property map is loaded inside the scripting module using the &amp;lt;tt&amp;gt;Ts.loadProps()&amp;lt;/tt&amp;gt; call. The map file should normally reside in the same folder as the scripting module that uses it; if so, the map from the above example is loaded simply with &amp;lt;tt&amp;gt;Ts.loadProps(&amp;quot;cities&amp;quot;)&amp;lt;/tt&amp;gt;. The property values are obtained in the scripts using &amp;lt;tt&amp;gt;Ts.getProp()&amp;lt;/tt&amp;gt; call. E.g. the genitive form of Athens would be obtained either by &amp;lt;tt&amp;gt;Ts.getProp(&amp;quot;Athens&amp;quot;, &amp;quot;gen&amp;quot;)&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Ts.getProp(&amp;quot;Atina&amp;quot;, &amp;quot;gen&amp;quot;)&amp;lt;/tt&amp;gt; -- because the map defined both as phrase identifiers for Athens. The phrase/key lookup is performed using normalized values; this normalization can be checked or used for own purposes by &amp;lt;tt&amp;gt;Ts.normKey()&amp;lt;/tt&amp;gt; call.&lt;br /&gt;
&lt;br /&gt;
The comments are a bit of an issue in property map files. Since the phrases and property values can be anything (hence the possibility to choose separators), fixing any single character as your typical to-the-end-of-line comment would introduce limitations. Instead, the #-comments are allowed only ''between'' the entries, span to the end of line, and # cannot be a separator character.&lt;br /&gt;
&lt;br /&gt;
The whitespace in property values is mostly preserved (for the keys it does not matter, as it gets stripped for lookups). However, if the leading sequence of whitespace contains a newline, all whitespace to the first newline and including it is stripped; symmetrically, in a trailing whitespace sequence, the last newline (if any) and the whitespace following it are removed.&lt;br /&gt;
&lt;br /&gt;
=== User Configuration ===&lt;br /&gt;
&lt;br /&gt;
Using a configuration file located at {{path|$HOME/.transcriptrc}}, the user can be allowed to configure certain aspects of Transcript operation. The configuration file is in ini-style, where group names are language codes to which the selections apply. For example:&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# Settings for German.&lt;br /&gt;
[de]&lt;br /&gt;
serve-sausages = no&lt;br /&gt;
wine-instead-of-beer = yes&lt;br /&gt;
&lt;br /&gt;
# Settings for Italian.&lt;br /&gt;
[it]&lt;br /&gt;
with-mozzarella = no&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Within scripting modules, the configuration values can be fetched using &amp;lt;tt&amp;gt;Ts.getConf*()&amp;lt;/tt&amp;gt; series of calls. These calls will automatically look for the configuration fields under the proper language group, as the scripting modules are language-dependent too.&lt;br /&gt;
&lt;br /&gt;
For boolean-valued keys, &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;no&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; can be used to indicate negative (false) values, and everything else is treated as positive (true). Also, the boolean values are not case sensitive.&lt;br /&gt;
&lt;br /&gt;
== Repository Organization ==&lt;br /&gt;
&lt;br /&gt;
For the PO file in the KDE repository {{path|LL/messages/kdemodule/foo.po}}, the corresponding Transcript module should be located at {{path|LL/scripts/kdemodule/foo/foo.js}}. Note the extra subfolder in the module path, named like the basename of the PO/JS file. This subfolder is introduced because the module's main JS file might need other supporting files, which can then be located conveniently in the same folder.&lt;br /&gt;
&lt;br /&gt;
The {{path|autogen.sh}} script, used for some time already to generate build system support for PO files, will also generate build support for Transcript modules. In particular, it must be rerun whenever a new module subfolder is added (e.g. the {{path|LL/scripts/kdemodule/foo}}), but not when particular files within it are added or removed. Every file in the module subfolder will be installed automatically, so put there only what is needed at runtime.&lt;br /&gt;
&lt;br /&gt;
== Real-Life Examples ==&lt;br /&gt;
&lt;br /&gt;
=== CJK Accelerator Keys ===&lt;br /&gt;
In CJK environment, accelerator keys are wrapped in the parenthesis. For example, translation of &amp;quot;&amp;amp;File&amp;quot; in Korean is &amp;quot;파일(&amp;amp;F)&amp;quot;, and in Japanese, &amp;quot;ファイル(&amp;amp;F)&amp;quot;. When it comes to the names of action, it is shared among toolbar icon names, menu bar, and so on.&lt;br /&gt;
&lt;br /&gt;
However, in toolbar icon name, &amp;quot;Configure shortcut&amp;quot; dialog, etc., those access keys are remaining in the name, makes the name little bit awkward. In this situation, we can use transcript to get rid of those accelerator keys. Currently,  the code is in Japanese and Korean kdelibs4.js file.&lt;br /&gt;
&lt;br /&gt;
=== Korean Postpositions ===&lt;br /&gt;
In Korean language, postpositions are widely used. Among those, 8 postpositions are in pair and they change forms according to the word. Because PO file itself doesn't know what the substituted word(like %1) is, proper postpositions couldn't be added to the string. &lt;br /&gt;
&lt;br /&gt;
Fortunately, the rule is programmable, and proper postpositions could be added via transcript. Right now a little part of postposition rules is programmed into Korean version of kdelibs4.js.&lt;br /&gt;
&lt;br /&gt;
=== Automatic Property Calls ===&lt;br /&gt;
Leveraging [[#Property Maps|property maps]] interface, we can make a generalization of the [[#Dynamic Case Setting|dynamic case setting]] example. We want to set named properties by key-value pairs for a given message, and then, to use calls named as property keys to retrieve the values when that message is used as placeholder replacement in another message.&lt;br /&gt;
&lt;br /&gt;
For example, Nevernessians need to match the noun case of &amp;quot;baloon&amp;quot; when it is inserted into sentence &amp;quot;I see a %1&amp;quot;, and additionally the adjective form of &amp;quot;red&amp;quot; to baloon in &amp;quot;I see a red %1&amp;quot;, so they do:&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
msgid &amp;quot;baloon&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;beeluun&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;$[properties see-it beeluuno see-red raado]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
msgid &amp;quot;I see a %1&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;O sii e %1&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;O sii e $[see-it %1]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
msgid &amp;quot;I see a red %1&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;O sii e raad %1&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;O sii e $[see-red %1] $[see-it %1]&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;properties&amp;lt;/tt&amp;gt; call, which does all the work -- setting properties, setting new calls by property keys -- looks like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Set properties of the phrase given by the finalized msgstr in the PO file.&lt;br /&gt;
// The arguments to the call are consecutive pairs of keys and values,&lt;br /&gt;
// as many as needed (i.e. total number of arguments must be even).&lt;br /&gt;
//&lt;br /&gt;
// The property keys are registered as PO calls taking single argument,&lt;br /&gt;
// which can be used to retrive the property values for this msgstr&lt;br /&gt;
// when it is later used as placeholder replacement in another message.&lt;br /&gt;
//&lt;br /&gt;
// Always signals fallback.&lt;br /&gt;
//&lt;br /&gt;
function setMsgstrProps (/*KEY1, VALUE1, ...*/)&lt;br /&gt;
{&lt;br /&gt;
    if (arguments.length % 2 != 0)&lt;br /&gt;
        throw Error(&amp;quot;Property setter given odd number of arguments.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    // Collect finalized msgstr.&lt;br /&gt;
    phrase = Ts.msgstrf()&lt;br /&gt;
&lt;br /&gt;
    // Go through all key-value pairs.&lt;br /&gt;
    for (var i = 0; i &amp;lt; arguments.length; i += 2) {&lt;br /&gt;
        var pkey = arguments[i];&lt;br /&gt;
        var pval = arguments[i + 1];&lt;br /&gt;
&lt;br /&gt;
        // Set the value of the property for this phrase.&lt;br /&gt;
        Ts.setProp(phrase, pkey, pval);&lt;br /&gt;
&lt;br /&gt;
        // Set the PO call for getting this property, if not already set.&lt;br /&gt;
        if (!Ts.hascall(pkey)) {&lt;br /&gt;
            Ts.setcall(pkey,&lt;br /&gt;
                       function (phr) { return Ts.getProp(phr, this.pkey) },&lt;br /&gt;
                       {&amp;quot;pkey&amp;quot; : pkey});&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    throw Ts.fallback();&lt;br /&gt;
}&lt;br /&gt;
Ts.setcall(&amp;quot;properties&amp;quot;, setMsgstrProps);&lt;br /&gt;
// NOTE: You can replace &amp;quot;properties&amp;quot; in the line above with any UTF-8 string,&lt;br /&gt;
// e.g. one in your language so that it blends nicely inside POs.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Labels Dependent on Dynamic Values ===&lt;br /&gt;
Sometimes the text of a standalone label should grammatically conform to the a changing value elsewhere in the interface. The typical example of this is when a sentence-like row of different widgets is used to specify an action:&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
Search in files modified:&lt;br /&gt;
( ) ...&lt;br /&gt;
(*) during the last {day|week|month|year}&lt;br /&gt;
( ) ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;( )&amp;lt;/tt&amp;gt; stand for radio buttons, and &amp;lt;tt&amp;gt;{...|...|...}&amp;lt;/tt&amp;gt; for a list box with several choices. The label &amp;lt;tt&amp;gt;&amp;quot;during the last&amp;quot;&amp;lt;/tt&amp;gt; contains the adjective &amp;quot;last&amp;quot;, which in some languages needs to have different forms according to the noun it describes (one of the choices from list box). Whenever the list box value changes, the label should change to match it. But this label is a standalone message in the PO file, so based on what can its translation be scripted?&lt;br /&gt;
&lt;br /&gt;
The solution is to ask the programmer to make the label refresh on every change of the list box value, and to add a ''dynamic context'' to the label's message (using &amp;lt;tt&amp;gt;inContext&amp;lt;/tt&amp;gt; method of &amp;lt;tt&amp;gt;KLocalizedString&amp;lt;/tt&amp;gt;). The dynamic context is a key-value string pair which indicates the current list box value; the key and possible values should be documented in the message's context. If the programmer did this properly, the translator should now see in the PO file:&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
msgctxt &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;Part of logical sentence 'Search in files modified &amp;gt;during the last&amp;lt; &amp;quot;&lt;br /&gt;
&amp;quot;day|week|...'; provides dynamic context 'last-what': 'd' for day, &amp;quot;&lt;br /&gt;
&amp;quot;'w' for week, 'm' for month, 'y' for year.&amp;quot;&lt;br /&gt;
msgid &amp;quot;during the last&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The translation can now be scripted based on the &amp;lt;tt&amp;gt;last-what&amp;lt;/tt&amp;gt; dynamic context:&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;duureeng thee leestee&amp;quot;&lt;br /&gt;
&amp;quot;|/|&amp;quot;&lt;br /&gt;
&amp;quot;duureeng $[by-context last-what 'd|m' 'thee leestee' 'w|y' 'thaa leestaa']&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;by-context&amp;lt;/tt&amp;gt; call takes the context key, followed by pairs of context value matches (regular expressions) and corresponding phrases; in this example, one form is selected for context values &amp;lt;tt&amp;gt;d&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;, and another form for &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;. The definition of this call is:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Select a phrase according to dynamic context.&lt;br /&gt;
// The first argument is the context keyword,&lt;br /&gt;
// followed by arbitrary numer of pairs of context values and&lt;br /&gt;
// corresponding phrases, optionally followed by default phrase.&lt;br /&gt;
//&lt;br /&gt;
// Context values are actually regular experessions, so that if one phrase&lt;br /&gt;
// corresponds to several context values, it does not have to be repeated&lt;br /&gt;
// but its context value can be given e.g. as 'foo|bar|...'.&lt;br /&gt;
//&lt;br /&gt;
// If the context was not matched, default phrase is returned if&lt;br /&gt;
// it was given; otherwise fallback is signaled.&lt;br /&gt;
//&lt;br /&gt;
function selectByContext (/* ctxt_key,&lt;br /&gt;
                             valrx_1, phrase_1, ..., valrx_N, phrase_N&lt;br /&gt;
                             [, default_phrase] */)&lt;br /&gt;
{&lt;br /&gt;
    if (arguments.length &amp;lt; 1) {&lt;br /&gt;
        throw Error(&amp;quot;Selector by context needs at least one argument.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Collect context value for the given key.&lt;br /&gt;
    var ctxtkey = arguments[0];&lt;br /&gt;
    var ctxtval = Ts.dynctxt(ctxtkey);&lt;br /&gt;
&lt;br /&gt;
    // Match the context and select the corresponding phrase.&lt;br /&gt;
    var phrase;&lt;br /&gt;
    for (var i = 1; i &amp;lt; arguments.length; i += 2) {&lt;br /&gt;
        if (ctxtval.match(RegExp(arguments[i]))) {&lt;br /&gt;
            phrase = arguments[i + 1];&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // If context was not matched, select default phrase or signal fallback.&lt;br /&gt;
    if (phrase == undefined) {&lt;br /&gt;
        if (arguments.length % 2 == 0) {&lt;br /&gt;
            phrase = arguments[arguments.length - 1];&lt;br /&gt;
        } else {&lt;br /&gt;
            throw Ts.fallback();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return phrase;&lt;br /&gt;
}&lt;br /&gt;
Ts.setcall(&amp;quot;by-context&amp;quot;, selectByContext);&lt;br /&gt;
// NOTE: You can replace &amp;quot;by-context&amp;quot; in the line above with any UTF-8 string,&lt;br /&gt;
// e.g. one in your language so that it blends nicely inside POs.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-06-19T13:55:21Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: ascription-config file moved one level up, with implied adjustments.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading'', ''approving''), each of which may return the translation to a previous stage, or forward it to some special stage. The process can also be more finer grained, where each message in the file goes through stages separately.&lt;br /&gt;
&lt;br /&gt;
Regardless of the particularities, workflows of this kind all have the following in common. Members of the translation team are assigned ''roles'' -- such as ''translator'', ''reviewer'', ''approver'', ''committer'' -- by which they enter into the workflow (single person can have more roles). The later review stages must wait for the earlier stages to complete, and the translation cannot be updated again before the current version clears the pipeline (or the pipeline is aborted). Most importantly, once the translation is committed, it becomes part of simply &amp;quot;admitted&amp;quot; translations, with no further qualifiers.&lt;br /&gt;
&lt;br /&gt;
The system of prescribed roles requires that team members assign them between themselves, stick to them, and shuffle them along the way. The prescribed review pipeline requires a tool to enforce and keep track of the stages in which translations are. This makes the review workflow complex and rigid, most probably with choke points for efficiency. Distribution of roles may become disbalanced by people coming and going, or the workflow tool may be prohibitive to some scenarios (e.g. single translator making small adjustments in dozens of files across the project, but having to upload each manually through a web interface).&lt;br /&gt;
&lt;br /&gt;
Of course, &amp;quot;rigid&amp;quot;, &amp;quot;complex&amp;quot;, &amp;quot;inefficient&amp;quot;, are comparative qualifications, so what is it that the classical review by stages can be compared to in this way?&lt;br /&gt;
&lt;br /&gt;
== Reviewing by Ascriptions ==&lt;br /&gt;
&lt;br /&gt;
Reviewing by ascriptions is even simpler conceptually, and yet less rigid, less complex, and much more efficient than the review by stages. It works on the message-level, rather than file-level. Anyone can simply translate some messages and directly commit modified files, without any review, but with ''ascribing'' modifications to own name. Anyone can review any committed messages at any moment, commit the modifications-on-review and ascribe reviews to own name and (possibly) to certain class -- full review, review of context, of terminology, of style, etc. Only when the translation is to be shipped to end users, the ''insufficiently'' reviewed messages are automatically omitted from the package, by evaluating the ''ascription history'' of each message.&lt;br /&gt;
&lt;br /&gt;
Most importantly, based on the ascription history, the reviewer can select only some particular messages, and review only the difference between their historical and current versions. For example, Alice can select to review only messages modified since she or Bob had last reviewed them for style; she could see the difference from that last review to current version, e.g. if in the whole paragraph only a single word has changed by Charlie when he reviewed the terminology. In terms of PO workflow, the ascription history propagates through merges, so the reviewer can compare the change in original and the change in translation since the last review, to judge if one fits the other.&lt;br /&gt;
&lt;br /&gt;
Since everyone just commits, translations can be efficiently kept in a version control repository, with the ascription system added on top. After having done some translating, the team member simply substitutes commit command of the version control system (VCS) with ascribe-modifications command of the ascription system (AS, which calls the underlying VCS internally). After reviewing, the team member uses ascribe-reviews command of the AS to commit reviews to ascription history (as well as modifications made during the review). To select messages for review, the team member issues diff-for-review command of the AS (with suitable parameters to narrow the set) and selected messages are marked in-place in PO files and [[Localization/Tools/Pology/PO_Embedded_Diffing|embedded with differences]], and possibly popped open in a PO editor.&lt;br /&gt;
&lt;br /&gt;
When the translations are to be released, the team coordinator issues filter-for-release command of the AS, which takes the working PO files and creates final PO files with insufficiently reviewed messages removed. &amp;quot;Release time&amp;quot; is used here only figuratively: this should be a fully automatic process, so it can be performed at any interval of convenience.&lt;br /&gt;
&lt;br /&gt;
What constitutes &amp;quot;sufficient review&amp;quot; can be defined in fine detail. It could be specified that messages modified by Alice need to have only review for terminology, but not necessarily for style; Charlie may belong to the group which needs to be reviewed on style, but not necessarily on context; Bob's reviews for style may be nice to have, but never blocking if missing. These decisions do not preclude released messages to be reviewed later on missing points, after higher priority reviews have been completed. The definition of sufficiency may be changed at any point, e.g. as team members get more experienced and require less review, without interfering with direct translation and review work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- (Here is one unorthodox possibility of using reviews by ascriptions. A random translator may want to keep an eye on what the reviewers change in the files he maintains. For example, to learn what are typical small errors that he makes while translating. Therefore, he himself reviews any modifications not made by him after his last review, and commits them. This will in no way interfere with &amp;quot;canonical&amp;quot; reviews, those considered at release time.) //--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In summary, with reviewing by ascriptions the lean efficiency of raw VCS operation is preserved while providing for great flexibility of review. All team members can be given commit access, no web or email detours are needed. There are no prescribed roles, but an equivalent of role assignment happens automatically at last possible moment, and can take into account both translators' and reviewers' abilities. There is no staging between completing and committing the translation, which enables translator to keep on polishing the translation undisturbed until the reviewer comes around. There is no inefficiency in handling small changes throughout many files, since single AS command commits all changes just as single VCS command would. AS in effect abstracts VCS, so general team members do not have to know the particularities of the underlying VCS. On commit operations, AS can also apply checks (e.g. decline to commit syntactically invalid PO files) and modifications (e.g. update translator's data in the PO header).&lt;br /&gt;
&lt;br /&gt;
== Ascription System in Pology ==&lt;br /&gt;
&lt;br /&gt;
[[Localization/Tools/Pology|Pology]] is a collection of various modular tools for supporting translation based on PO files. Among them is the script &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which implements an ascription system (AS); at present, it can use Subversion or Git as the underlying VCS. &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is still in experimental stage, so what follows is a brief description of how to use it in context of the KDE translation project. However, very little is truly specific to KDE; the only major assumption is that there exists a VCS repository with PO files of a given language grouped together, and that the translation team can use it without special restrictions.&lt;br /&gt;
&lt;br /&gt;
Very important for the AS is how branches are handled (in KDE, the rolling trunk and stable branches). AS can in principle be deployed by branch, but then there is the added complexity of porting translations between branches, which ascriptions should follow. Therefore, the AS implemented by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is currently limited to assumption that there is a single branch of translations at all times. The article [[Localization/Workflows/PO_Summit|&amp;quot;Translating in Summit&amp;quot;]] explains how a KDE translation team can set up and operate such a single branch, the summit, and this is the prerequisite for the following instructions. (Note that the summit system is useful on its own, and should be conductive to any kind of review workflow.)&lt;br /&gt;
&lt;br /&gt;
== Setting Up ==&lt;br /&gt;
&lt;br /&gt;
The summit branch for the language &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt; is positioned like this in the KDE repository:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            LANG/&lt;br /&gt;
                summit/&lt;br /&gt;
                    messages/&lt;br /&gt;
                    docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The team coordinator already has this part of the repository tree locally due to regular summit operations. For the same reason Pology is already set up. Setting up the ascription system is now simple. The file &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; is created in the parent directory of the summit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        ascription-config&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# ---------------------------&lt;br /&gt;
# Global ascription settings.&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
&lt;br /&gt;
# Roots of the catalog and ascription trees.&lt;br /&gt;
catalog-root = summit&lt;br /&gt;
ascript-root = summit-ascript&lt;br /&gt;
&lt;br /&gt;
# The underlying version control system.&lt;br /&gt;
version-control = svn&lt;br /&gt;
&lt;br /&gt;
# Data for updating catalog headers.&lt;br /&gt;
# - language code&lt;br /&gt;
language = LANG&lt;br /&gt;
# - full language name&lt;br /&gt;
language-team = LANGUAGE&lt;br /&gt;
# - email address of the team&lt;br /&gt;
team-email = kde-i18n-LANG@kde.org&lt;br /&gt;
&lt;br /&gt;
# Default commit message.&lt;br /&gt;
commit-message = Translation updates.&lt;br /&gt;
&lt;br /&gt;
# -----------------------&lt;br /&gt;
# Registered translators.&lt;br /&gt;
&lt;br /&gt;
[user-alice]&lt;br /&gt;
name = Alice Akmalryn&lt;br /&gt;
original-name = Алиса Акмалрин&lt;br /&gt;
email = alice.akmalryn@someplacenice.org&lt;br /&gt;
&lt;br /&gt;
[user-bob]&lt;br /&gt;
name = Bob Byomkin&lt;br /&gt;
original-name = Бобан Бјомкин&lt;br /&gt;
email = bob.byomkin@otherplacenice.org&lt;br /&gt;
&lt;br /&gt;
# ...and so on.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;ascript-root&amp;lt;/tt&amp;gt; setting should be exactly &amp;lt;tt&amp;gt;summit-ascript&amp;lt;/tt&amp;gt;, for the reason mentioned later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit-message&amp;lt;/tt&amp;gt; field, if defined, allows team members to commit without providing a commit message. The value given by this field will be used by default, with translator's user name appended to the end in special syntax. For example: &amp;lt;tt&amp;gt;Translation updates. [&amp;gt;alice]&amp;lt;/tt&amp;gt;. (Translator's user name is also appended to manually supplied commit messages.) Translators can still supply a commit message when they wish, as shown later. If this field is not set, the commit message is supplied as usual on committing.&lt;br /&gt;
&lt;br /&gt;
* Team members are defined by &amp;lt;tt&amp;gt;[user-USERNAME]&amp;lt;/tt&amp;gt; sections. Ascription user names can be any valid ASCII identifier: ASCII letters, digits and underscores only, digit cannot be the first character. Ascription user names have no technical relation to the underlying VCS accounts, though it is mnemonically convenient if they are the same (in case of SVN). This means that a translator who does not have a VCS account (yet) can and should be added here, with assigned user name (best one suitable as SVN account name later); why this should be done will be explained later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field in user sections is there in case the preferred renderings of the name in English and in target language are not the same. When this is not the case, &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; can be omitted.&lt;br /&gt;
&lt;br /&gt;
As soon as the &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; file is committed, the ascription system is ready for operation. Only regular modifications to this file are those of adding new team members. (On the other hand, team members should never be removed, because even after they no longer contribute, their ascription records remain in the system.)&lt;br /&gt;
&lt;br /&gt;
=== Initial Ascription ===&lt;br /&gt;
&lt;br /&gt;
The most common situation at start of ascription workflow is that there already exists a body of translations, contributed to by many different people over time. The coordinator should ascribe all existing translations as initial modifications, but to whom? It cannot be said precisely who translated what. The solution is to introduce a generic user in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;, suitably known as &amp;quot;Unknown Hero&amp;quot; (or &amp;quot;Lost Translator&amp;quot;, you can be inventive):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[user-uhero]&lt;br /&gt;
name = Unknown Hero&lt;br /&gt;
original-name = Незнани јунак&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ascribe all existing translations as modified and reviewed by this user. The coordinator does this with the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe commit -u uhero --all-reviewed -C LANG/summit/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; is the ascription mode, and the &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option provides the user name to which ascriptions are made. This is an important point: ascriptions are made to a user defined in ascription configuration, and have nothing to do with VCS accounts; someone who has the account can commit in the name of someone who does not. It is the &amp;lt;tt&amp;gt;--all-reviewed&amp;lt;/tt&amp;gt; option that declares all messages to be reviewed as well (note that it is normally used only this once, and not for normal day to day reviewing). The &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option prevents automatic adding and committing to version control, which is useful for this initial step. Finally the paths which contain all summit catalogs are given.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command is issued, a progress bar will appear, and the following output will start to unfold:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
LANG/summit/messages/extragear-base/rellinks.po  (50/50)&lt;br /&gt;
LANG/summit/messages/extragear-base/autorefresh.po  (13/13)&lt;br /&gt;
LANG/summit/messages/extragear-base/babelfish.po  (38/38)&lt;br /&gt;
...&lt;br /&gt;
LANG/summit/messages/qt/libphonon.po  (13/13)&lt;br /&gt;
LANG/summit/messages/qt/phonon-xine.po  (24/24)&lt;br /&gt;
LANG/summit/messages/qt/phonon_gstreamer.po  (12/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated    111775    111775&lt;br /&gt;
fuzzy          26943     26943&lt;br /&gt;
obsolete/t      2965      2965&lt;br /&gt;
obsolete/f      1626      1626&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number in parenthesis indicates how many messages have been ascribed in the given PO file (modified/reviewed), and at the end the totals are given. Ascribing the complete summit for the first time will take quite some time (on the order of 10-20 minutes).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--If, on the contrary, it is known who translated and reviewed what, ascription can be performed piece-wise with user names of real translators:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support/LANG/summit&lt;br /&gt;
$ poascribe commit -u alice --all-reviewed -C kdelibs/ kdepimlibs/ kdebase/&lt;br /&gt;
$ poascribe commit -u bob --all-reviewed -C kdemultimedia/ kdeutils/&lt;br /&gt;
$ ...&lt;br /&gt;
&amp;lt;/code&amp;gt;//--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the initial ascription has been made, the ascription tree will appear next to the summit tree. This tree will contain one ascription PO file for each summit PO file, with the same name and relative location within the tree:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        ascription-config&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
        summit-ascript/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During the ascription some summit PO files may have been modified as well, in that any previous fields (&amp;lt;tt&amp;gt;#| ...&amp;lt;/tt&amp;gt;) on translated messages have been removed. (These fields are sometimes erroneously left in by older PO editors.)&lt;br /&gt;
&lt;br /&gt;
The newly created ascription tree (and any modifications to summit tree) can now be committed as usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn add LANG/summit-ascript&lt;br /&gt;
$ svn commit LANG/summit LANG/summit-ascript -m &amp;quot;Initial ascription.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Translators ==&lt;br /&gt;
&lt;br /&gt;
Team members other than the coordinator, whether translators or reviewers, need to keep around only the &amp;lt;tt&amp;gt;trunk/l10n-support/LANG/&amp;lt;/tt&amp;gt; directory. But they always need to update this directory fully (rather than just one particular module or file under &amp;lt;tt&amp;gt;.../*messages/&amp;lt;/tt&amp;gt;), so that the summit tree and the ascription tree (and configuration) are kept in sync.&lt;br /&gt;
&lt;br /&gt;
In order not to have to issue their own user name (&amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;) all the time, translators can set it in Pology user configuration &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, in &amp;lt;tt&amp;gt;[poascribe]&amp;lt;/tt&amp;gt; section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = alice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translators can then submit updated PO files simply by substituting &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt; (or whatever the VCS commit command is) with &amp;lt;tt&amp;gt;poascribe commit&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;co&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;ci&amp;lt;/tt&amp;gt; for short):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdefoo/*fooapp*.po&lt;br /&gt;
LANG/summit/messages/kdefoo/fooapp.po  (144)&lt;br /&gt;
LANG/summit/messages/kdefoo/libfooapp.po  (25)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified&lt;br /&gt;
translated       169&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; VCS is committing catalogs:&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/libfooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/libfooapp.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1267069.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will add ascription records into ascription catalogs corresponding to summit catalogs to be committed, and commit them all. Like &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt; can take any number of file or directory paths, and can be issued from any working directory (it will always find ascription catalogs). If default commit message has not been set in the ascription configuration, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will ask for it; or it can be given in command line through &amp;lt;tt&amp;gt;-m&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
=== Translators Without Commit Access ===&lt;br /&gt;
&lt;br /&gt;
With the ascription system in place, every regular team member should have commit access. But, there may be some period of time before new translators are given accounts, revision control may be too technical for some, and even those with the account may not be able to commit temporarily for some reason.&lt;br /&gt;
&lt;br /&gt;
These translators may send in their work by email, to ''any'' team member with commit access (not necessarily the coordinator or a reviewer); this team member can commit received files without any review, as review can be conducted at any later time. If Bob sends some files to Alice, she can commit them immediately by stating Bob's user name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -u bob ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, the translator who sent in the files has to be defined in the ascription configuration. There are no hidden costs or security issues to this (as opposed to opening a VCS account), so every new translator should be defined there before any work of that person is committed.&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Reviewers ==&lt;br /&gt;
&lt;br /&gt;
The ascription system opens up all sorts of possibilities for concrete review patterns. Reviewers should keep in mind that for each message the full modification and review history is available, so that the team can think about how to make good use of it. Therefore, what follows are some examples to illustrate the review facilities that &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; provides.&lt;br /&gt;
&lt;br /&gt;
=== Basic Reviewing ===&lt;br /&gt;
&lt;br /&gt;
At the very basic level (which is the only level in classical review by stages), messages can be classified into simply unreviewed and reviewed, without further qualifiers. Alice now wants to review all unreviewed messages in a group of PO files, say &amp;lt;tt&amp;gt;kdetoys&amp;lt;/tt&amp;gt; module. She issues (&amp;lt;tt&amp;gt;di&amp;lt;/tt&amp;gt; is short for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe di LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===== Diffed for review: 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unreviewed messages have now been marked and diffed, inside the listed PO files. What is this about &amp;quot;diffing&amp;quot;? If the files had already been reviewed before, some of the messages modified since then (those marked for review) may have changed very little (e.g. a few words in a paragraph-length message, or even just punctuation). Therefore, for each message marked for review, Alice also wants to see the diff since last review to current version. Here are two messages in typical review states added by &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: charlie:m&lt;br /&gt;
#: gui/mainwindow.cc:372&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;GAME OVER. {-You won-}{+Tie+}!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KRAJ IGRE. {-Pobeda-}{+Nerešeno+}!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: bob:m charlie:m&lt;br /&gt;
#: game-state.cpp:117&lt;br /&gt;
#, ediff-total&lt;br /&gt;
msgid &amp;quot;Click the pause button again to resume the game.&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Kliknite ponovo na dugme pauze da nastavite igru.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the first one in Kate:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_poascribe_diff_01.png|center|Message diffed for review by poascribe in Kate.]]&lt;br /&gt;
&lt;br /&gt;
In the first message, the first to note is the &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment. This comment succinctly lists who did what with the message since the last review; here &amp;lt;tt&amp;gt;charlie:m&amp;lt;/tt&amp;gt; means that Charlie is the one who modified it. Then, there is the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, which alice can use it to jump through messages marked for review. Finally, the original and translation have been diffed; here they show that, since the last review, the message was fuzzied by changing &amp;quot;You won&amp;quot; to &amp;quot;Tie&amp;quot;, and what Charlie did in translation to unfuzzy it. Even on a message as short as this, the diff tells something useful to Alice: the phrase &amp;quot;Game over&amp;quot; likely has a formulaic translation, and the fact that it is not part of the diff means that the earlier reviewer had made sure it is consistent, so Alice does not have to check that.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment of the second message reveals that both Charlie and Bob had been translating it. &amp;lt;tt&amp;gt;ediff-total&amp;lt;/tt&amp;gt; flag instead of plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; means that this message had no review at all up to now, so there are no embedded diffs in text fields.&lt;br /&gt;
&lt;br /&gt;
Alice can now go through marked files and messages, review translations, and possibly make modifications. When making changes in a message with embedded diffs, she can freely edit text outside of difference segments and within &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments (as these are the ones which belong to current version of the text). While reviewing, Alice does ''not'' remove any of the added message elements while reviewing (save for an occasional difference segment, when translation should be modified), as these elements are needed for later. If a message is particularly hard and Alice wants to defer its review for later, she can add the &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; for short) flag to it.&lt;br /&gt;
&lt;br /&gt;
Once the review is complete, Alice simply commits the reviewed files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (0/2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (0/7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (3/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated         3        21&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; VCS is committing catalogs:&lt;br /&gt;
Sending      LANG/summit/messages/kdegames/palapeli.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/bovo.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/kdiamond.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/palapeli.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1284220.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three things have happened here. First, all review states (flags, embedded diffs, etc.) have been removed, restoring the PO file to normal. Then, any modifications that Alice have made during review are ascribed to her (here 3 out of 21 messages). Finally, all marked messages are ascribed as reviewed by Alice (any with &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; flags would have been omitted here). When committing, the only summit catalog that got committed is the one with modifications made during review, and all the ascription catalogs were committed because of the reviews recorded in them.&lt;br /&gt;
&lt;br /&gt;
When many files with few changes in each are to be reviewed, it becomes burdensome to manually open each and every diffed for review, and then to make sure that all are committed with &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt;. To make this easier, &amp;lt;tt&amp;gt;-w torevivew.out&amp;lt;/tt&amp;gt; option can be added to &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;, which requests that paths of all diffed PO files are written into &amp;lt;tt&amp;gt;torevivew.out&amp;lt;/tt&amp;gt; file. This file can then be used to batch open POs for review in the editor, as well as fed back on &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;-f torevivew.out&amp;lt;/tt&amp;gt;. There is also the &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; option which causes &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; to directly open PO files in a PO editor (though this is currently applicable only to Lokalize). Putting it together, to efficiently review a whole bunch of small changes throughout many files, Alice can:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di PATHS... -w toreview.out -o lokalize&lt;br /&gt;
$ # ...only marked messages opened in Lokalize, review them...&lt;br /&gt;
$ poascribe ci -f toreview.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selecting Messages for Review ===&lt;br /&gt;
&lt;br /&gt;
Invocations of &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; without any options, as in the previous section, were actually equivalent to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; is issuing the message ''selector''. &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is the default selector for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt; mode, and stands for MODified-After-Review: it selects the earliest historical modification of the message after the last (or no) review of that message, if there is any such. By selecting a historical modification of the message, the diff from it to current version can be computed and embedded into the PO file, as in previous examples.&lt;br /&gt;
&lt;br /&gt;
There are various specialized selectors, and fall into two groups: ''shallow selectors'' and ''history selectors''. Shallow selectors look only into the current version of the message, and cannot select historical versions, which means that they cannot provide embedded diffs. History selectors (&amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is of this type) can select messages from history and provide diffs. Several selectors can be issued on the command line, and the message is selected only if all selectors select it. Shallow selectors are then normally used as a pre-filter for history selectors. For example, to select messages modified after last reviewed, but only those found in stable branch, &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; selectors are chained:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s branch:stable -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that the history selector is given last, because the last selector determines which historical message is selected. If the ordering had been reversed here, same messages would get selected, but they would not have embedded diffs, because &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; is a shallow selector.&lt;br /&gt;
&lt;br /&gt;
Selectors can take parameters themselves, like &amp;lt;tt&amp;gt;branch:stable&amp;lt;/tt&amp;gt; in the previous example. Parameters are separated from the selector name by any non-alphanumeric character; this is colon by convention, but if a parameter contains a colon, something like slash, tilde, etc. can be used. Number of parameters can be variable, and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; in particular can take from none to three. If Alice wants to review only those messages modified ''by Charlie'' since last review, she states this by first argument to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:charlie PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Alice does not give too much credit to other reviewers, she can request selection of messages modified after last review ''by her'' with second parameter to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar::alice PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the first parameter (&amp;quot;modified by...&amp;quot;), which is not needed, must be explicitly skipped, before going to the second parameter (&amp;quot;reviewed by...&amp;quot;). The third optional parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; will be mentioned in the next section.&lt;br /&gt;
&lt;br /&gt;
When a selector parameter is a user name, normally it can also be a comma-separated list of user names (&amp;lt;tt&amp;gt;modar:bob,charlie&amp;lt;/tt&amp;gt;) or prefixed with tilde to negate, i.e. select all other users (&amp;lt;tt&amp;gt;modar:~alice&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Any selector can be negated by prepending &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; to its name. For example, the history selector &amp;lt;tt&amp;gt;modafter:DATE&amp;lt;/tt&amp;gt; selects first modification after the given date; to select messages modified after last review, but only if modified during June 2010:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modafter:2010-06 -s nmodafter:2010-07 -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Negating a history selector produces a shallow selector: while &amp;lt;tt&amp;gt;modafter&amp;lt;/tt&amp;gt; is history selector, &amp;lt;tt&amp;gt;nmodafter&amp;lt;/tt&amp;gt; is shallow. But the order of the two in the previous command line is not important, as the last selector is the usual &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selectors can be issued in other modes too. If the PO file is big and Alice has reviewed messages up to and including entry 246 when she has to pause until another day, she can commit reviews only up to this entry by issuing the &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; selector:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -s espan::246 PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the first parameter to &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; is the first entry number, given if messages are not to be selected from the first). There is also the counterpart &amp;lt;tt&amp;gt;lspan&amp;lt;/tt&amp;gt; selector, which works with referent line numbers (those of &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; keywords) instead of entry numbers.&lt;br /&gt;
&lt;br /&gt;
=== Fine-Grained Reviews ===&lt;br /&gt;
&lt;br /&gt;
In the introduction, several distinct types of what can go wrong in translation were described. Not all reviewers may be able to check translation against all those problems. Here is a typical scenario of this kind:&lt;br /&gt;
&lt;br /&gt;
Alice is very computer-savvy and knows the translation project inside and out, which means that she can review well for context, terminology, and technical style. But, her language style leaves something to be desired, which shows through longer sentences and passages. Dan, on the other hand, is a very literary person, but not that much into the technical aspects. Dan's style reviews would thus be a perfect complement to Alice's general reviews.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; can support this scenario in the following way. A ''review type'' tag for language style is defined in the ascription configuration, using the &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[global]&lt;br /&gt;
...&lt;br /&gt;
review-tags = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The value to &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; is a space-separated list of identifiers, when more than one special review type is needed.) With this addition to configuration, Alice can continue to review as she did before, without any changes to her workflow.&lt;br /&gt;
&lt;br /&gt;
Dan selects messages for review similarly to Alice, but aditionally giving the &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; tag as ''third'' parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;, and indicating that ascribed reviews should be tagged as &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:::lstyle -t lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After finishing the review, Dan commits as usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Dan is always going to review the language style, in order not to have to issue the selector and tag in the command line all the time, he can make them default per mode in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = dan&lt;br /&gt;
selectors/diff = modar:::lstyle&lt;br /&gt;
tags/diff = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this Dan can use plain &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; just like Alice does.&lt;br /&gt;
&lt;br /&gt;
The important point of review tags is that they make reviews by types independent. For example, Dan may come around to review the language style of the given message after several modifications and general reviews have been ascribed to it -- &amp;lt;tt&amp;gt;modar:::lstyle&amp;lt;/tt&amp;gt; will simply ignore all reviews except for &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews. This is going to be reflected in the &amp;lt;tt&amp;gt;ascto:&amp;lt;/tt&amp;gt; comment to marked messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: charlie:m alice:r bob:m&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here Alice has made one review between Charlie's and Bob's modifications, and that review, being general instead of &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;, did not cause &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; to stop at it. After Dan reviews this message for language style, Alice runs selection for review and gets this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: bob:m dan:r(lstyle)&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, since &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews do not mix with general reviews, Dan's review did not hide Bob's modification that Alice did not check so far.&lt;br /&gt;
&lt;br /&gt;
(General review too has a tag assigned, the empty string, in case the reviewer needs to explicitly issue it in some context.)&lt;br /&gt;
&lt;br /&gt;
== Daily Use for The Coordinator ==&lt;br /&gt;
&lt;br /&gt;
After setting up the ascription system, the team coordinator should have to do very little to maintain it.&lt;br /&gt;
&lt;br /&gt;
=== Ascribing Merges ===&lt;br /&gt;
&lt;br /&gt;
Modifications made to summit catalogs by merging with templates must also be ascribed. Therefore, after merging the summit (&amp;lt;tt&amp;gt;posummit ... merge ...&amp;lt;/tt&amp;gt;) the coordinator substitutes the VCS command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command in &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the user is not explicitly given by &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option, this will ascribe merge modifications to the coordinator (more precisely, to the user set as default in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;), which is just fine. It is also possible to define a special user only for ascribing merge modifications, though there is no known advantage to that.&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option is not issued, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will automatically commit all modified summit and ascription catalogs when done.&lt;br /&gt;
&lt;br /&gt;
=== Shuffling Ascription Catalogs  ===&lt;br /&gt;
&lt;br /&gt;
Sometimes summit catalogs are shuffled in the repository: moved to another module, renamed, one catalog split into two, two catalogs merged into one. Such shuffling should be exactly mirrored in the ascription tree, and this too is done on the repository side, at the same time. This relies on the ascription root being set exactly to &amp;lt;tt&amp;gt;summit-ascript&amp;lt;/tt&amp;gt; in the ascription configuration. So the team coordinator has nothing special to do here.&lt;br /&gt;
&lt;br /&gt;
If instead in the central KDE repository the translation team is working in an external repository, by consequence the ascription system must be set up in that repository. But so long as &amp;lt;tt&amp;gt;process_orphans.sh&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; is used to shuffle catalogs in the external repository as well, the ascription catalogs will be properly handled.&lt;br /&gt;
&lt;br /&gt;
== Filtering for Release ==&lt;br /&gt;
&lt;br /&gt;
The last component of the ascription system is how to prevent insufficiently reviewed messages from leaking into a release. In context of Pology and summit workflow, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; itself is used directly to this end. Instead, in the summit configuration (as opposed to ascription configuration), the team coordinator defines filters which pass messages by applying selectors.&lt;br /&gt;
&lt;br /&gt;
Each top level PO tree has its own summit configuration file, named &amp;lt;tt&amp;gt;MSGTREE.extras.summit&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            messages.extras.summit&lt;br /&gt;
            docmessages/&lt;br /&gt;
            docmessages.extras.summit&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the simple case of all reviews being general reviews, the filter is added to summit configuration like this (anywhere within &amp;lt;tt&amp;gt;*.extras.summit&amp;lt;/tt&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the filter is named &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;, and is defined as application of &amp;lt;tt&amp;gt;nmodar&amp;lt;/tt&amp;gt; selector, the negation of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;. This simply means: pass all messages ''not'' modified after the last review.&lt;br /&gt;
&lt;br /&gt;
When the team coordinator scatters to branches (executes &amp;lt;tt&amp;gt;posummit scatter&amp;lt;/tt&amp;gt;), messages from summit POs which do not pass this filter will not be sent to branch POs. The count of stopped messages by branch PO will be reported in the output as scattering proceeds.&lt;br /&gt;
&lt;br /&gt;
Why did we have to name the filter &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;? (Those knowing some Python will also notice that it is defined as a list element.) Because it is possible to define more than one filter, and select which one is used on each scattering. For example, the coordinator may wish that, when the release is near and time is short to review everything, messages from a few experienced translators can be passed into release without review. If those translators are Alice and Bob, an &amp;quot;emergency&amp;quot; filter can be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; uses the first filter in the list. When the coordinator needs to do emergency scattering, he requests the emergency filter by the &amp;lt;tt&amp;gt;-a&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter -a emergency&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What if several selectors are needed to pass the message? For example, the language style review (the earlier example with Alice and Dan) too may be requested for regular scattering, but omitted from emergency scattering. The filter setup for this scenario looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;, &amp;quot;nmodar:::lstyle&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The regular filter now reads: pass the message if it has not been modified after the last (general) review ''and'' has not been modified after the last style review.&lt;br /&gt;
&lt;br /&gt;
Simple combination of predefined selectors by AND-conditions may not be sufficient for more involved scenarios. When this is the case, the coordinator may write (or ask someone to write) a custom selector in Python, and plug it in as the second element in the filter tuple (instead of the list of predefined selectors).&lt;br /&gt;
&lt;br /&gt;
=== Writing a Selector Function ===&lt;br /&gt;
&lt;br /&gt;
((To be written.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Tools/Pology/PO_Embedded_Diffing</id>
		<title>Localization/Tools/Pology/PO Embedded Diffing</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Tools/Pology/PO_Embedded_Diffing"/>
				<updated>2010-06-13T08:27:44Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Wording.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Tools/Pology/PO_Embedded_Diffing}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Tools|Tools]]|&lt;br /&gt;
name=Embedded Diffing with Pology|&lt;br /&gt;
prereqs=[[Localization/Tools/Pology|Pology]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Diffing of PO So Far ==&lt;br /&gt;
&lt;br /&gt;
'''Line-level''' diffing assumes that the maximal generaly recognizable unit of text file is one line, that each line carries a meaning of significant standalone value, and that the ordering of lines has been deliberately chosen and cannot be arbitrary. For example, this is typical of program code.&lt;br /&gt;
&lt;br /&gt;
Superficially, PO files could also be considered &amp;quot;a programming language of translations&amp;quot;, and amenable to same treatment on diffing. However, some of the above assumptions which make line-level diffing viable are violated with PO format. Firstly, minimal unit of PO file is one message, whereas one line is of negligible semantic value. Secondly, ordering of messages can in principle be arbitrary (e.g. dependent on the order of extraction from source code), such that two line-wise very different PO files are actually equivalent from translator's viewpoint. And thirdly, good number of lines in the PO file are auxiliary, neither original text nor translation, generated either automatically or by the programmer (e.g. source references, extracted comments), all of which are out of translator's scope for modifications.&lt;br /&gt;
&lt;br /&gt;
Thus, a common way to use line-level diffing with PO files so far was only for review, and with some preparations. Due to myriad of equivalent but line-wise different representations of PO content, it is quite useless to send line diffs as patches; translators are instructed to always send full PO files to the reviewer/commiter, no matter the amount of modifications. Then, the reviewer merges the received PO file (new version), and possibly the original (old version), with current template, without wrapping of long lines in text fields. This &amp;quot;normalizes&amp;quot; old and new files with respect to all semantically non-significant elements, and only then can line diff be performed. Additionally, since a long non-wrapped line of translated text may differ only in some segments, a dedicated diff viewer which can highlight '''word-level''' differences has to be used; ordinary diff syntax highlighting (e.g. in shell, or in general text editor) won't cut it.&lt;br /&gt;
&lt;br /&gt;
Even with such preparations and dedicated diff viewer at hand, there is at least one significant case which is still not reasonably covered: when a fuzzy message, which had previous fields (PO was merged with &amp;lt;tt&amp;gt;--previous&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt;), has been updated and unfuzzied. For example:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''diff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code diff&amp;gt;&lt;br /&gt;
⁠  #: main.c:110&lt;br /&gt;
- #, fuzzy&lt;br /&gt;
- #| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
  msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
- msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
+ msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Here, the diff viewer will know to show word-level diff for modified translation, but it cannot know that it should also show word-level diff between the removed previous and current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields, so that reviewer can see what has changed ''in the original'' text (i.e. why the message became fuzzy), and based on that judge the change in translation.&lt;br /&gt;
&lt;br /&gt;
Finally, a dedicated PO editor may be able to show the truly proper, '''message-level''' difference (such as [[Localization/Tools/Lokalize|Lokalize]] can, operating in [http://docs.kde.org/stable/en/kdesdk/lokalize/sync.html merge mode]). Even then, however, there is still the need to send around full PO files, and, to some extent, to normalize them before comparing in the editor. The diff format becomes tied to and defined in terms of the given PO editor (which you may not want to use in general), instead of being intrinsically defined and modularly processable (such as line diffs are).&lt;br /&gt;
&lt;br /&gt;
The rest of this article will therefore propose a format and semantics for self-contained, message-level diffing of PO files -- the '''embedded diff''' -- and present two [[Localization/Tools/Pology|Pology]] scripts which embody it as proof of concept (but are also quite practically applicable).&lt;br /&gt;
&lt;br /&gt;
== The Embedded Diff ==&lt;br /&gt;
&lt;br /&gt;
Difference between two PO messages should be primarily, though not exclusively, composed of differences between its text fields (&amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, etc.) Then, to be easily judged, differences in text should be presented as succinctly and locally as possible -- think of a long paragraph where only some spelling or punctuation has changed. Finally, the format of the complete message diff should be easily comprehendable to translators used to PO format itself, and as far as possible, to existing PO tools too.&lt;br /&gt;
&lt;br /&gt;
Previous considerations lead to the following decision: ''PO message diff will also be a PO message''. Or, in other words, the diff will be ''embedded'' into the regular parts of a PO message. An embedded diff (''ediff'' for short) message should be at least syntactically a valid PO entry, if not always semantically (i.e. if part of PO file, it should pass &amp;lt;tt&amp;gt;msgfmt&amp;lt;/tt&amp;gt;, though not necessarily &amp;lt;tt&amp;gt;msgfmt --check&amp;lt;/tt&amp;gt;). To enable ediffs to be passed around as patches for PO files, the embedding should be automatically resolvable (up to significant message parts) to the old and new messages from which the diff was created.&lt;br /&gt;
&lt;br /&gt;
In this way, if ediff messages are packed into a PO file (an ediff PO), existing PO tools can be used to review and modify the diff. For example, highlighting in a text editor will need only minimal upgrades to show the embedded differences (more on that below), and otherwise it will already highlight ediff message parts as usual.&lt;br /&gt;
&lt;br /&gt;
To complete the definition of ediffs in detail, the following questions should be answered:&lt;br /&gt;
&lt;br /&gt;
* How to represent embedded differences in text?&lt;br /&gt;
&lt;br /&gt;
* Which parts of the message should be diffed?&lt;br /&gt;
&lt;br /&gt;
* How to pair for diffing messages from two files?&lt;br /&gt;
&lt;br /&gt;
* How to present collection of diffed messages?&lt;br /&gt;
&lt;br /&gt;
=== Embedding Differences into Text ===&lt;br /&gt;
&lt;br /&gt;
Once the difference between the old and new strings, the word-level difference, has been determined, it should be decided how to embed it into the new (or, equivalently, old) string. One possibility is that of &amp;lt;tt&amp;gt;wdiff(1)&amp;lt;/tt&amp;gt;, where removed and added text segments are by default wrapped with &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;[-...-]&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{+...+}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;, respectively:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''diff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;[-The Record-]{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
However, search through PO files of several translation projects (KDE, Gnome, OpenOffice, Fedora, Mozilla) reveals the &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;[-&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; character combination to be frequently encountered, e.g. in synopsis of command usage. While there must exist an escaping mechanism for cases when diff wrappers are encountered in the original text, to enable unambiguous resolving of ediffs, it is nevertheless prudent to pick wrappers which reduce frequency of escaping (e.g. syntax highlighting may not be able to discern non-diff wrapper-like segments). Searching through same collection of PO files produces no hits for &amp;lt;tt&amp;gt;{-&amp;lt;/tt&amp;gt;, so this combination is picked instead as wrapper of removed text segments:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the text itself contains a wrapper-like combination, it is escaped by inserting tilde (&amp;lt;tt&amp;gt;~&amp;lt;/tt&amp;gt;) between the brace and plus/minus sign:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Foo {+ bar&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Foo {+ qwyx&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Foo {~+ {-bar-}{+qwyx+}&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the text already contains a substring with brace-tilde-plus/minus, then another tilde is inserted, and so on. Thus the ediff can be unambiguously resolved to old and new versions of the string. Inserting the tilde between the two characters of wrapper combinations also makes it easier on the syntax higlighting, as the difference highlighting trigger is automatically removed.&lt;br /&gt;
&lt;br /&gt;
It may happen that a given string is not merely empty in the old or new PO message, but that it does not exist at all (e.g. &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; field). Thus an ediff can be made between existing and non-existing strings too, in which case a tilde is appended to the very end of the ediff:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;a-context-note&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;{+a-context-note+}~&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Again, escaping is provided for by inserting further tildes if the ediff between two existing strings would result in trailing tilde (old: &amp;lt;tt&amp;gt;&amp;quot;~&amp;quot;&amp;lt;/tt&amp;gt;, new: &amp;lt;tt&amp;gt;&amp;quot;foo~&amp;quot;&amp;lt;/tt&amp;gt;, ediff: &amp;lt;tt&amp;gt;&amp;quot;{+foo+}~~&amp;quot;&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
How exactly the difference between two strings is formed, may be left to implementation. In fact, an implementation may allow translator to select between several diffing algorithms, depending on personal taste and situation. For example, the default algorithm of &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; does the following: words are diffed as whole, all non-word segments (interpunction, markup tags, etc.) character by character, and equal non-word segments between different words are taken into the difference segment. Hence the above ediff&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
instead of smaller&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;{-The -}Record{+s+} of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as the former is (tentatively) easier to comprehend.&lt;br /&gt;
&lt;br /&gt;
Every difference segment in an ediff PO message will be represented like this, thus it is sufficient to upgrade PO syntax highlighting of an editor to indiscriminately highlight &amp;lt;tt&amp;gt;{-...-}&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments everywhere in the message.&lt;br /&gt;
&lt;br /&gt;
=== Message Parts Included in Diffing ===&lt;br /&gt;
&lt;br /&gt;
A PO message consists of several types of parts: text fields, comments, flags, source references, etc. It would not be very constructive to diff all of them; for example, while &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; fields should clearly be included into diffing, source references most probably should not. In order not to consider pros and cons of inclusion for each and every message part, there already exists a clear split of message parts into two groups, one of which will be taken into diffing, and the other ignored. These two groups are:&lt;br /&gt;
&lt;br /&gt;
* ''extraction-invariant'' parts -- those which do not depend on placement (or even presence) of message in the sources, such as &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; fields, manual comments, etc.&lt;br /&gt;
&lt;br /&gt;
* ''extraction-prescribed'' parts -- those which cannot exist independently of the source from which the message is extracted, such as format flags or extracted comments.&lt;br /&gt;
&lt;br /&gt;
Extraction-invariant parts are the ones which will be diffed. Working definition of exactly which parts belong into this group is provided by obsolete messages in PO files. Thus, these parts are:&lt;br /&gt;
&lt;br /&gt;
* current original: &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt; fields&lt;br /&gt;
&lt;br /&gt;
* previous original: commented &amp;lt;tt&amp;gt;#| msgctxt&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;#| msgid&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;#| msgid_plural&amp;lt;/tt&amp;gt; fields&lt;br /&gt;
&lt;br /&gt;
* translation: &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; fields&lt;br /&gt;
&lt;br /&gt;
* translator (manual) comments&lt;br /&gt;
&lt;br /&gt;
* fuzzy state (whether the &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt; flag is present)&lt;br /&gt;
&lt;br /&gt;
* obsolete state (whether the message is obsolete)&lt;br /&gt;
&lt;br /&gt;
All the listed fields and manual comments are presented in ediff message as wrapped word-level differences, as described earlier. Change in states, fuzzy and obsolete, is represented slightly differently. A special &amp;quot;extracted&amp;quot; (automatic) comment is added to the ediff message, starting with &amp;lt;tt&amp;gt;ediff:&amp;lt;/tt&amp;gt; and listing any extra info needed to describe the ediff, including the state changes. Here is an example of two messages and the ediff they would produce (whether two messages such as these would get paired for diffing in the first place, will be discussed later on):&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#~| msgid &amp;quot;Accurate subpolar weather cycles&amp;quot;&lt;br /&gt;
#~ msgid &amp;quot;Accurate subpolar climate cycles&amp;quot;&lt;br /&gt;
#~ msgstr &amp;quot;Tačni ciklusi subpolarnog vremena&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ui: property (text), widget (QCheckBox, accCyclesTrop)&lt;br /&gt;
#: config.ui:180&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;Accurate tropical weather cycles&amp;quot;&lt;br /&gt;
msgctxt &amp;quot;some-superfluous-context&amp;quot;&lt;br /&gt;
msgid &amp;quot;Accurate tropical climate cycles&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Tačni ciklusi tropskog vremena&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-obsolete-}&lt;br /&gt;
#. ui: property (text), widget (QCheckBox, accCyclesTrop)&lt;br /&gt;
#: config.ui:180&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;Accurate {-subpolar-}{+tropical+} weather cycles&amp;quot;&lt;br /&gt;
msgctxt &amp;quot;{+some-superfluous-context+}~&amp;quot;&lt;br /&gt;
msgid &amp;quot;Accurate {-subpolar-}{+tropical+} climate cycles&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Tačni ciklusi {-subpolarnog-}{+tropskog+} vremena&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Here is how this ediff message will look like in KWrite and Kate, starting with KDE 4.2:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_PO_Ediff_Highlighting.png|center|Ediff syntax highlighting in Kate]]&lt;br /&gt;
&lt;br /&gt;
(In fact, ediff-aware [http://websvn.kde.org/*checkout*/trunk/KDE/kdelibs/kate/syntax/data/gettext.xml?content-type=text%2Fplain PO syntax highlighting definition] for Kate can be used with Kate versions as early as KDE 3.4. The definition file should simply be placed as &amp;lt;tt&amp;gt;~/.kde/share/apps/katepart/syntax/gettext.xml&amp;lt;/tt&amp;gt;, and it will override the system definition.)&lt;br /&gt;
&lt;br /&gt;
First thing to note is that the ediff message contains not only extraction-invariant parts, but also copies verbatim extraction-prescribed parts from the new message. Effectively, the ediff is embedded into the copy of new message. Extraction-prescribed parts are not simply discarded in order to provide more context when reviewing the diff. Here, for example, the extracted comment states that the text is a checkbox label, which may be important for the style of translation.&lt;br /&gt;
&lt;br /&gt;
The other important element is the &amp;lt;tt&amp;gt;#. ediff:&amp;lt;/tt&amp;gt; dummy extracted comment, which here indicates that the obsolete state has been &amp;quot;removed&amp;quot;, i.e. the message was unobsoleted going from old to new version. Aside from state changes, few other indicators may rarely be present, as described in API documentation of &amp;lt;tt&amp;gt;pology.misc.diff&amp;lt;/tt&amp;gt; module, function &amp;lt;tt&amp;gt;msg_ediff&amp;lt;/tt&amp;gt;. Some of these indicators will be mentioned later on. The ediff comment will be present only when necessary, if there are any indicators to show.&lt;br /&gt;
&lt;br /&gt;
If diffing of two messages would always be conducted part for part, for all parts which are taken into diffing, then in some cases the resulting ediff would not be very useful. Consider how the first example in the article, the line-level diff of a fuzzy and translated message, would look like as ediff if performed part for part:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#| msgid &amp;quot;{-The Record of The Witch River-}~&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Beleška-}{+Beleške+} o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The same problem as with the line-level diff persists: instead of showing the difference from previous to current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, the current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; is left untouched, and previous &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; is simply shown to have been entirely removed.&lt;br /&gt;
&lt;br /&gt;
Therefore, instead of straightforward, part for part diffing, a special transformation will take place when ''exactly one'' of the two diffed messages is fuzzy and equipped with previous original text fields. This splits into two directions: from fuzzy to non-fuzzy, and from non-fuzzy to fuzzy.&lt;br /&gt;
&lt;br /&gt;
Diffing from fuzzy to non-fuzzy message, such as above, is the more usual of the two directions. It is typical of translation updated after merging with template, where some fuzzied messages will have been resolved. In this case, the original old and new messages are transformed thusly prior to diffing (&amp;lt;tt&amp;gt;*-rest&amp;lt;/tt&amp;gt; denotes all diffed parts that are neither original text nor fuzzy state):&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
fuzzy                   --&amp;gt;     fuzzy&lt;br /&gt;
old-previous-fields     --&amp;gt;     old-previous-fields&lt;br /&gt;
old-current-fields      --&amp;gt;     old-previous-fields&lt;br /&gt;
old-rest                --&amp;gt;     old-rest&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
-                       --&amp;gt;     -&lt;br /&gt;
-                       --&amp;gt;     old-current-fields&lt;br /&gt;
new-current-fields      --&amp;gt;     new-current-fields&lt;br /&gt;
new-rest                --&amp;gt;     new-rest&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In this way, ediff message's current fields will show the important difference, that of previous fields of old fuzzy message and current fields of new non-fuzzy message. Ediff message's previous fields will show the less important difference of old fuzzy messages previous and current fields, but ''only'' if it is not equal to the difference in current fields; otherwise it is eliminated. This may sound confusing, but the final ediff produced in this way is quite intuitive:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Beleška-}{+Beleške+} o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The reviewer here sees that the message was unfuzzied, the change in the original text that caused the message to become fuzzy, and the change made in translation to unfuzzy it. Old version (in removed and equal segments) of original and translation is that of the message before it got fuzzied, and new version (in added and equal segments) is that of the message after it was unfuzzied.&lt;br /&gt;
&lt;br /&gt;
From non-fuzzy to fuzzy message should be the less frequent direction of diffing. It corresponds e.g. to case where the diff is taken from older fully complete translation to the one just after merging with newest template. In this case, the transformation is as follows:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
-                       --&amp;gt;     -&lt;br /&gt;
-                       --&amp;gt;     new-previous-fields&lt;br /&gt;
old-current-fields      --&amp;gt;     old-current-fields&lt;br /&gt;
old-rest                --&amp;gt;     old-rest&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
fuzzy                   --&amp;gt;     fuzzy&lt;br /&gt;
new-previous-fields     --&amp;gt;     new-current-fields&lt;br /&gt;
new-current-fields      --&amp;gt;     new-current-fields&lt;br /&gt;
new-rest                --&amp;gt;     new-rest&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Again, the difference presented by ediff messages's current fields will be the most important one, the difference in previous fields the less important one, and eliminated if equal to the other. Here is what this will do if applied to one step earlier (just after merging) of the running example:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:89&lt;br /&gt;
msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {+fuzzy+}&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
msgid &amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The reviewer here sees that the message became fuzzy from new to old, and the change in original text that caused this. (On a side note, remember that ediff message is constructed by embedding differences into a copy of new message, so the source reference and the fuzzy flag from the new message appear here in the ediff message.)&lt;br /&gt;
&lt;br /&gt;
To be able to use the ediff as patch, it is necessary to reconstruct original old and new messages after resolving ediff into transformed old and new messages. This step is fortunatelly unambiguous; one just needs to check whether the non-fuzzy of the two resolved messages has previous fields, or, if not (due to elimination of equal difference in previous fields, or because template was merged without the &amp;lt;tt&amp;gt;--previous&amp;lt;/tt&amp;gt; option), whether the current fields are equal. Then the back-transformation to original old and new messages can be performed.&lt;br /&gt;
&lt;br /&gt;
=== Pairing Messages From Two Catalogs ===&lt;br /&gt;
&lt;br /&gt;
So far the article has described how to make an embedded diff out of two messages, once it has been decided that those messages should be diffed. However, on the lowest level, the user decides not which messages to diff, but which two PO files to diff. The implementation should then automatically ''pair'' for diffing messages from the two catalogs, and this section described several possible ways to do this.&lt;br /&gt;
&lt;br /&gt;
In the first instance, messages should obviously be '''paired by key''' (primary pairing), the unique combination of &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields. In the most usual case -- reviewing an ediff from incomplete catalog with some fuzzy and untranslated messages, to an updated catalog with some or all of those messages translated -- pairing by key will be fully sufficient, as both catalogs contain exactly the same set of messages by keys. These two messages will be plainly paired by key:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
But what should happen if some messages cannot be paired by key? Consider the earlier example where diff was taken from older fully translated, to newer merged catalog:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:89&lt;br /&gt;
msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The keys, here just current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields, of the two message do not match, so they cannot be paired by key. Yet it would be rather ungainly to represent the old message as fully removed in the ediff, and the new message as fully added:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:89&lt;br /&gt;
msgid &amp;quot;{-The Record of The Witch River-}~&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Beleška o Veštičjoj reci-}~&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. ediff: state {+fuzzy+}&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;{+The Record of The Witch River+}~&amp;quot;&lt;br /&gt;
msgid &amp;quot;{+Records of The Witch River+}~&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{+Beleška o Veštičjoj reci+}~&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
(That the message has been fully added or removed can be seen by trailing tilde in the &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, which indicates that the old or new &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; does not exist at all, and so neither the message with it.)&lt;br /&gt;
&lt;br /&gt;
Instead, messages left unpaired by key should be tested for '''pairing by pivoting''' around previous fields (secondary pairing). The two messages above will thus be paired due to the fact that the current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; of the old message is equal to the previous &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; of the new message, and will produce a single ediff message as shown earlier.&lt;br /&gt;
&lt;br /&gt;
Finally, consider the third related combination, when the old catalog has not yet been merged with the template, while the new catalog has both been merged and its translation updated:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:89&lt;br /&gt;
msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Once again, it would be a waste to present the old message as fully removed and the new message as fully added in the ediff. When a message is left unpaired after both pairing by key and pairing by pivoting, then the two catalogs should be merged in the background -- as if the new is the template for the old, and vice versa -- and then tested for chained pairing by pivoting and by key with merged catalog as intermediary. This '''pairing by merging''', or tertiary pairing, will then produce another natural ediff:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Beleška-}{+Beleške+} o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Implementations can decide which pairing modes beyond the primary, by key, to use. There should not be much reason not to perform secondary pairing, by pivoting, too. If tertiary pairing, by merging, is implemented, it should be provided that the user can disable it (sometimes this pairing may produce strange results, and needs &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; to be available on the system).&lt;br /&gt;
&lt;br /&gt;
=== Collecting Diffed Messages ===&lt;br /&gt;
&lt;br /&gt;
For ediff of two PO files to also be a syntactically valid PO file, constructed ediff messages should be preceded by a PO header on output. At first glance, this PO header could be itself the ediff of PO headers of the catalogs which were diffed. However, there are several issues with this approach:&lt;br /&gt;
&lt;br /&gt;
* Reviewer of the ediff PO file would not be informed at once whereas there was any difference between the headers. Headers tend to be long, and a point change in one of the fields may go visually unnoticed.&lt;br /&gt;
&lt;br /&gt;
* Depending on the amount of changes between the two headers, the resulting ediff message of the header could be too badly formed to represent the header as such (e.g. if header fields in &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; were added or removed, embedded difference wrappers would invalidate MIME-header format of &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt;), and thus confuse the PO tools.&lt;br /&gt;
&lt;br /&gt;
* How would the diff of two ''collections'' of PO files (e.g. directories) be packed into a single ediff PO, such as can normally be done with line-level diffing?&lt;br /&gt;
&lt;br /&gt;
To avert these difficulties, the following is done instead. First, the header of ediff PO is constructed as a minimal valid header (i.e. one that &amp;lt;tt&amp;gt;msgfmt&amp;lt;/tt&amp;gt; would not complain about) independent of the content of original headers. &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; will produce something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
# +- ediff -+&lt;br /&gt;
msgid &amp;quot;&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;Project-Id-Version: ediff\n&amp;quot;&lt;br /&gt;
&amp;quot;PO-Revision-Date: 2009-02-08 01:20+0100\n&amp;quot;&lt;br /&gt;
&amp;quot;Last-Translator: J. Random Translator\n&amp;quot;&lt;br /&gt;
&amp;quot;Language-Team: Differs\n&amp;quot;&lt;br /&gt;
&amp;quot;MIME-Version: 1.0\n&amp;quot;&lt;br /&gt;
&amp;quot;Content-Type: text/plain; charset=UTF-8\n&amp;quot;&lt;br /&gt;
&amp;quot;Content-Transfer-Encoding: 8bit\n&amp;quot;&lt;br /&gt;
&amp;quot;X-Ediff-Header-Context: ~\n&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;PO-Revision-Date&amp;lt;/tt&amp;gt; header field is naturally set to the date when the ediff is made. &amp;lt;tt&amp;gt;Last-Translator&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Language-Team&amp;lt;/tt&amp;gt; can be somehow pulled from environment (&amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; will source them from &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, or set some dummy values as above if not present). Encoding of the ediff PO can be chosen at will by the implementation, so long as all following ediff messages can be encoded with it (&amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; will always use UTF-8). The purpose of the &amp;lt;tt&amp;gt;X-Ediff-Header-Context&amp;lt;/tt&amp;gt; field will be explained shortly.&lt;br /&gt;
&lt;br /&gt;
It is the first next message in the ediff PO that will actually be the ediff of headers of the two diffed PO files. Headers are diffed just like any other message, but the resulting ediff is equiped with few extra decorations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
# =========================================================&lt;br /&gt;
# Translation of The Witch River into Serbian.&lt;br /&gt;
# Koja Kojic &amp;lt;koja.kojic@nedohodnik.net&amp;gt;, 2008.&lt;br /&gt;
# {+Era Eric &amp;lt;era.eric@ledopad.net&amp;gt;, 2008.+}~&lt;br /&gt;
msgctxt &amp;quot;~&amp;quot;&lt;br /&gt;
msgid &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;- l10n-wr/sr/wriver-main.po\n&amp;quot;&lt;br /&gt;
&amp;quot;+ l10n-wr/sr-mod/wriver-main.po\n&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;Project-Id-Version: wriver 0.1\n&amp;quot;&lt;br /&gt;
&amp;quot;POT-Creation-Date: 2008-09-22 09:17+0200\n&amp;quot;&lt;br /&gt;
&amp;quot;PO-Revision-Date: 2008-09-{-25 20:44-}{+28 21:49+}+0100\n&amp;quot;&lt;br /&gt;
&amp;quot;Last-Translator: {-Koja Kojic &amp;lt;koja.kojic@nedohodnik-}&amp;quot;&lt;br /&gt;
&amp;quot;{+Era Eric &amp;lt;era.eric@ledopad+}.net&amp;gt;\n&amp;quot;&lt;br /&gt;
&amp;quot;Language-Team: Serbian\n&amp;quot;&lt;br /&gt;
&amp;quot;MIME-Version: 1.0\n&amp;quot;&lt;br /&gt;
&amp;quot;Content-Type: text/plain; charset=UTF-8\n&amp;quot;&lt;br /&gt;
&amp;quot;Content-Transfer-Encoding: 8bit\n&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First observe the normal ediff segments: translator comment with a new translator who updated the PO file has been added, and &amp;lt;tt&amp;gt;PO-Revision-Date&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Last-Translator&amp;lt;/tt&amp;gt; header fields contain ediffs reflecting the update. These are the only actual differences between the two headers.&lt;br /&gt;
&lt;br /&gt;
More interesting are the extra decorations:&lt;br /&gt;
&lt;br /&gt;
* The very first translator comment (here a long line of equality signs) can be anything, and serves to give good visual distinction to the header ediff. This is more so convenient when the ediff PO contains diffs of several pairs of PO files.&lt;br /&gt;
&lt;br /&gt;
* That a particular message in the ediff PO is a header ediff, is indicated by the &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; set to a special value, here a single tilde. This value is given up front by the &amp;lt;tt&amp;gt;X-Ediff-Header-Context&amp;lt;/tt&amp;gt; of the ediff PO header. It should be computed during diffing such that it does not conflict with &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; of one of the normal message ediffs (e.g. it may simply be a sufficiently long sequence tildes).&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field of the header ediff contains newline-separated paths of the diffed PO files. More precisely, the two lines of the &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field are in form &amp;lt;code text&amp;gt;[+-] file-path[ &amp;lt;&amp;lt;&amp;lt; comment]\n&amp;lt;/code&amp;gt; (The trailing newline of the second file path is elided if the &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; does not end in newline, to prevent &amp;lt;tt&amp;gt;msgfmt&amp;lt;/tt&amp;gt; from complaining.) The optional, &amp;amp;lt;&amp;amp;lt;&amp;amp;lt;-separated comment to the file path can be used for any purpose, one which will be demonstrated when describing functionality of &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Although when a PO file is properly updated there should always be some difference in its header, it may happen that there is none. In such case, the header ediff message is still added, but such that it only contains the extra decorations -- the visual separator comment, special &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; with file paths. All other comments and &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; should be empty, and the empty &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; indicates that there was no difference in headers. Presence of this &amp;quot;empty&amp;quot; header ediff is necessary to provide diffed file paths and, if several POs were diffed, to separate them in the ediff PO.&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_Dir_Ediff_PO.png|right|150x150px|Embedded diff of directory of PO files in Kate.]]&lt;br /&gt;
&lt;br /&gt;
After the header ediff message, ordinary ediff messages follow. As already obvious by now, when several POs were diffed to construct a single ediff PO, each next PO in the ediff simply opens with a new header ediff message. Click on the thumbnail on the right to see how an ediff of two PO files looks like in entirety, with syntax highlighting in Kate.&lt;br /&gt;
&lt;br /&gt;
Especially when diffing several PO files, it may happen that two ediff messages have equal keys (&amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; fields) and thus cannot be both added as such to the ediff PO. In such case, the ediff message which was added after the first with the same key, will have its &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; field ''padded'' by few random alphanumerics, such as to make its key unique. This padding sequence will be recorded in the ediff comment. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
# =========================================================&lt;br /&gt;
msgctxt &amp;quot;~&amp;quot;&lt;br /&gt;
msgid &amp;quot;...(first PO header ediff)...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
msgid &amp;quot;White{+ horizon+}&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Belo{+ obzorje+}&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
# =========================================================&lt;br /&gt;
msgctxt &amp;quot;~&amp;quot;&lt;br /&gt;
msgid &amp;quot;...(second PO header ediff)...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. ediff: state {-fuzzy-}, ctxtpad q9ac3&lt;br /&gt;
msgctxt &amp;quot;|q9ac3~&amp;quot;&lt;br /&gt;
msgid &amp;quot;White{+ horizon+}&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Belo{+ obzorje+}&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The padding sequence is appended to the original &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, separated by the pipe character. If there was no original &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, the padding sequence is further extended by a tilde.&lt;br /&gt;
&lt;br /&gt;
== Producing Ediffs: &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Pology's &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; script implements embedded diffing as outlined in the previous section. To diff two PO files, executing the usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poediff orig/foo.po mod/foo.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will write the ediff PO (if there is any difference) to standard output, with some basic shell highlighting of difference segments. Option &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; can be used to output the ediff PO to file instead. Other options include &amp;lt;tt&amp;gt;--no-merge&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;-n&amp;lt;/tt&amp;gt;) to not perform pairing by merging, and &amp;lt;tt&amp;gt;--strip-headers&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt;) to take a quick look of differences without headers in the way (output with stripped headers is not a valid PO, and cannot be used as patch).&lt;br /&gt;
&lt;br /&gt;
It is equally simple to make ediff of directories:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poediff orig/ mod/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diffing of directories is by default recursive and takes into ediff added and removed catalogs. When a catalog has been added or removed, the &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; of corresponding header ediff will have one of the file paths, new or old, empty.&lt;br /&gt;
&lt;br /&gt;
To have non-dummy translator name and email address added to the header of ediff PO, set them in Pology's configuration file, &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code ini&amp;gt;&lt;br /&gt;
[user]&lt;br /&gt;
name = Koja Kojic&lt;br /&gt;
original-name = Која Којић&lt;br /&gt;
email = koja.kojic@nedohodnik.net&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(These entries cover all contexts in Pology where such information is of use; &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field is used when the name is to be written differently in English and translator's native language.)&lt;br /&gt;
&lt;br /&gt;
This is pretty much where the story about &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; would end, if not for its ability to take into account the underlying VCS, if one is used to control PO files.&lt;br /&gt;
&lt;br /&gt;
=== Diffing With Underlying VCS ===&lt;br /&gt;
&lt;br /&gt;
When PO files are under version control, &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; can operate in VCS mode using the option &amp;lt;tt&amp;gt;-c VCSKEY&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;--vcs&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;VCSKEY&amp;lt;/tt&amp;gt; is the keyword of one of VCS known to &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt;. Then, instead of giving two paths to diff, any number of version-controlled paths (files or directories) is given. Without other options, all modified PO files in these paths are diffed against the last commit known to local repository. For example, if an application uses Subversion repository, PO files in its &amp;lt;tt&amp;gt;po/&amp;lt;/tt&amp;gt; directory can be diffed with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poediff -c svn app/po/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some other set of revisions to diff can be given by the option &amp;lt;tt&amp;gt;-r REV1&amp;lt;nowiki&amp;gt;[:REV2]&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;--revision&amp;lt;/tt&amp;gt;). &amp;lt;tt&amp;gt;REV1&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;REV2&amp;lt;/tt&amp;gt; are not necessarily proper revision IDs, but any strings that the underlying VCS will be able to convert into revision IDs. If &amp;lt;tt&amp;gt;REV2&amp;lt;/tt&amp;gt; is omitted, diffing is preformed from &amp;lt;tt&amp;gt;REV1&amp;lt;/tt&amp;gt; to current working copy.&lt;br /&gt;
&lt;br /&gt;
When ediff is made in VCS mode, &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields of header ediffs will use &amp;amp;lt;&amp;amp;lt;&amp;amp;lt;-separated comments to file paths to indicate revision IDs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
# =========================================================&lt;br /&gt;
# ...&lt;br /&gt;
msgctxt &amp;quot;~&amp;quot;&lt;br /&gt;
msgid &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;- app/po/lang.po &amp;lt;&amp;lt;&amp;lt; 20537\n&amp;quot;&lt;br /&gt;
&amp;quot;+ app/po/lang.po&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As for supported VCS, Pology currently knows about Subversion (&amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt;) and Git (&amp;lt;tt&amp;gt;git&amp;lt;/tt&amp;gt;). To add a new VCS, its functionality should be wrapped for Pology's use in &amp;lt;tt&amp;gt;pology.misc.vcs&amp;lt;/tt&amp;gt;, using the interface defined by &amp;lt;tt&amp;gt;VcsBase&amp;lt;/tt&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
== Ediffs as Patches: &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
For basic functionality, applying an ediff patch is implementationally even easier than applying a line-level patch. Each ediff message in turn is resolved into originating old and new message, and if either the old or new message exists in target PO and is equal by extraction-invariant parts, then the message patch is applied, otherwise rejected.&lt;br /&gt;
&lt;br /&gt;
Applying the patch means overwriting extraction-invariant parts of the target message with those of the new message from the ediff, and leaving other parts untouched. If the target message is already equal to new message by extraction-invariant parts, then the patch is silently ignored. This means that if the same patch is applied twice, second application makes no modifications to the target catalog. Likewise if, by chance, the changes given by the patch were already independently introduced in the target catalog.&lt;br /&gt;
&lt;br /&gt;
Command-line interface of &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; is much like &amp;lt;tt&amp;gt;patch(1)&amp;lt;/tt&amp;gt;, sans the myriad of its more obscure options. There is the &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; option to strip leading elements of file paths in the ediff, and &amp;lt;tt&amp;gt;-d&amp;lt;/tt&amp;gt; option to append to them a directory path where target POs are to be found. If the files were diffed with underlying VCS as in the previous example, then the ediff could be applied in any of the following ways:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd repos/app/po &amp;amp;&amp;amp; poepatch &amp;lt;ediff.po&lt;br /&gt;
$ cd repos/ &amp;amp;&amp;amp; poepatch -p0 &amp;lt;ediff.po&lt;br /&gt;
$ poepatch -d repos/app/po &amp;lt;ediff.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Header patch (coming from the header ediff message) is applied in a slightly more relaxed fashion: some of the header fields are ignored when checking whether the patch is applicable. These are the fields which are known to be volatile as the PO file goes through different translators, and do not influence the processing of the catalog directed by the header (such as encoding or plural forms). Currently, these fields are: &amp;lt;tt&amp;gt;POT-Creation-Date&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;PO-Revision-Date&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Last-Translator&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;X-Generator&amp;lt;/tt&amp;gt;. When a header patch is accepted, these fields in the target header are overwritten with those from the patch (including being added or removed).&lt;br /&gt;
&lt;br /&gt;
=== Handling Rejected Ediffs ===&lt;br /&gt;
&lt;br /&gt;
Any rejected ediff messages will be written out to &amp;lt;tt&amp;gt;stdin.rej.po&amp;lt;/tt&amp;gt; if the patch was read from standard input, or to &amp;lt;tt&amp;gt;&amp;amp;lt;catname&amp;amp;gt;.rej.po&amp;lt;/tt&amp;gt; if it was given as file through &amp;lt;tt&amp;gt;-i&amp;lt;/tt&amp;gt; option (e.g. &amp;lt;tt&amp;gt;ediff.rej.po&amp;lt;/tt&amp;gt; for input &amp;lt;tt&amp;gt;ediff.po&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
File with rejected ediff messages will again be an ediff PO file. It will have the header as before, except that its title comment will mention, in free prose, that this particular ediff PO contains rejects of some patching operation. Afterwards, ediff messages rejected as patch will follow. Header ediff messages will be present whether rejected or not, for the same purpose of separation and provision of file paths, but they will be stripped of comments and &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; when the header patch itself was not rejected.&lt;br /&gt;
&lt;br /&gt;
Furthermore, to every straigh-out rejected ediff message an &amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; flag will be added. This is done, naturally, because some ediff messages may not be rejected straight-out, but go through some post-processing instead. Consider the following scenario. A catalog has been merged to produce the fuzzy message:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: tools/power.c:348&lt;br /&gt;
msgid &amp;quot;Active sonar low frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Niska frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;Active sonar low frequency&amp;quot;&lt;br /&gt;
msgid &amp;quot;Active sonar high frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Niska frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Translator updates the translation, which produces the usual ediff message on update from fuzzy to translated:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
msgid &amp;quot;Active sonar {-low-}{+high+} frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Niska-}{+Visoka+} frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
However, ''before'' this patch could have been applied, the programmer adds a trailing colon to the same message, and the catalog is merged again to produce:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new2'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;Active sonar low frequency&amp;quot;&lt;br /&gt;
msgid &amp;quot;Active sonar high frequency:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Niska frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The patch can no longer be cleanly applied, due to the extra colon added in the meantime to the &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt;, so it has to be rejected. If nothing else is done, it would appear in the file of rejects as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, ediff-no-match&lt;br /&gt;
msgid &amp;quot;Active sonar {-low-}{+high+} frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Niska-}{+Visoka+} frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It seems a bit wastefull to reject such a near-match patch without any indication that it could be easily adapted to suit the latest message in the target PO. Therefore, when an ediff message is rejected, the following analysis is performed: by trying out message pairings as described for diffing, could the old message from the patch be paired with a current message from the target PO, and that current message with the new message from the patch? Or, in other words, can an existing message in the target PO be &amp;quot;fitted in between&amp;quot; the old and new messages defined by the patch? If this is the case, instead of the original, two special ediff messages -- ''split rejects'' -- are constructed and written out: one from the old to the current message, and another from the current to the new message. They are flagged as &amp;lt;tt&amp;gt;ediff-to-cur&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt;, respectively:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, fuzzy, ediff-to-cur&lt;br /&gt;
#| msgid &amp;quot;Active sonar low frequency&amp;quot;&lt;br /&gt;
msgid &amp;quot;Active sonar high frequency{+:+}&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Niska frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, ediff-to-new&lt;br /&gt;
#| msgid &amp;quot;Active sonar {-low-}{+high+} frequency{+:+}&amp;quot;&lt;br /&gt;
msgid &amp;quot;Active sonar {-low-}{+high+} frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Niska-}{+Visoka+} frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are more ways to interpret split rejects, depending on the circumstances. In this example, from &amp;lt;tt&amp;gt;ediff-to-cur&amp;lt;/tt&amp;gt; message reviewer can see what had changed in the target message after the translator made the ediff. This can also be seen by comparing difference embedded into previous and current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields in the &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt; message. With slightly more extensive editing, the reviewer can fold these two messages into an applicable patch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;Active sonar {-low-}{+high+} frequency:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Niska-}{+Visoka+} frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Given that the file of rejected ediffs is also an ediff PO, after edits to make some of the rejected patches applicable, it can be ''reapplied'' as patch. If that is done, &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; will silently ignore all ediff messages having &amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt; flag, as these have already been determined inapplicable. That is why in the example above the reviewer has replaced the &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt; with the plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag on the folded ediff.&lt;br /&gt;
&lt;br /&gt;
=== Embedding Patches ===&lt;br /&gt;
&lt;br /&gt;
Depending on the type of text which is being translated, and distance of translation language's grammar, ortography and style from English, it may be difficult to review an ediff in isolation. In general, messages in ediff PO will lack ''positional context'', which is in the full PO provided by messages immediately preceding and following the target message. For example, a long passage from documentation probably needs no positional context. But a short newly added message such as &amp;quot;Crimson&amp;quot; could very well need one, if it has neither &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; nor extracted comment describing it. Is it really a color? What grammatical ending should it have, in a language which matches adjective to noun gender? Several messages around it in the full PO could easily show whether it is just another color in a row, and their grammatical endings (determined by a translator earlier) would show the needed ending for the new color.&lt;br /&gt;
&lt;br /&gt;
Then, if an ediff message needs some editing before being applied, it may not be easy to do this directly in the ediff PO. Everything is fine so long as only added text segments (&amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt;) are edited, but if the sentence needs to be restructured more thoroughly, reviewer would have to make sure to put all additions into existing or new &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments, and to wrap all removals as &amp;lt;tt&amp;gt;{-...-}&amp;lt;/tt&amp;gt; segments. If this is not carefully performed, the patch will not be applicable any more, as old message resolved from it will no longer exactly match a message in the target PO.&lt;br /&gt;
&lt;br /&gt;
For these reasons, &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; can apply the patch such as ''not to resolve the ediff'', but to set all its extraction-invariant fields to the message in the patched PO. In effect, the patched PO becomes an ediff PO by itself, but only in the messages which were actually patched. To mark these messages for lookup, &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag is added to them. If the message in the ediff PO was:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: title.c:274&lt;br /&gt;
msgid &amp;quot;Tutorial&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Tutorijal-}{+Podučavanje+}&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then when the patch is successfully applied with embedding, the patched message in target PO will look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#: title.c:292&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;Tutorial&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Tutorijal-}{+Podučavanje+}&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#: title.c:328&lt;br /&gt;
msgid &amp;quot;Start the Expedition&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Pođi u ekspediciju&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Other than the addition &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, note that the patched message also kept its source reference, rather than it being overwritten by that from ediff PO. Same holds for all extraction-prescribed parts.&lt;br /&gt;
&lt;br /&gt;
Reviewer can now jump from &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;edif&amp;lt;/tt&amp;gt; flag, always having the full positional context for each patched message, and being able to edit it to heart's content, with only minimal care not to invalidate the ediff format. Wrapped difference segments can be entirely removed, non-wrapped segments can be freely edited; it should only not happen that a wrapped segment looses its opening or closing sequence. But this does not mean that the reviewer ''needs'' to remove or touch difference segments at all, that is, to unembed patched messages by hand -- &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; will do that automatically, when run on embedded-patched POs with a particular option.&lt;br /&gt;
&lt;br /&gt;
A patch is applied with embedding by issuing the &amp;lt;tt&amp;gt;-e&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;--embed&amp;lt;/tt&amp;gt;) option (&amp;lt;tt&amp;gt;E&amp;lt;/tt&amp;gt; in parenthesis in progress output indicates that embedding is engaged):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poepatch -e &amp;lt;ediff.po&lt;br /&gt;
patched (E): lang.po&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When the patched PO has been reviewed and patched messages possibly edited, all remaining embedded differences are removed, i.e. resolved to new versions, by running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poepatch -u lang.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only those messages having the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag are resolved, therefore the reviewer should ''never'' remove them (unless manually unembedding the whole patched message).&lt;br /&gt;
&lt;br /&gt;
What happens with rejected patches when embedding is engaged? They are also added into the target PO, with heuristic positioning, and no separate ediff PO with rejects is created. Same as with plain patching, straight-out rejects will have &amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; flag, and split rejects &amp;lt;tt&amp;gt;ediff-to-cur&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt;. If these are not manually resolved during the review (&amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; messages removed, &amp;lt;tt&amp;gt;ediff-to-*&amp;lt;/tt&amp;gt; messages removed or folded), when &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; is run to unembed the patch, it will remove all &amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt; messages, and resolve &amp;lt;tt&amp;gt;ediff-to-cur&amp;lt;/tt&amp;gt; messages to new version (effectively rejecting patches from which split rejects had originated).&lt;br /&gt;
&lt;br /&gt;
== Lightweight Diffing when Updating Translation ==&lt;br /&gt;
&lt;br /&gt;
Rather than for reviewing changes and sending patches, the translator may want to have only a convenient diff between the previous and new original text when updating a catalog merged with &amp;lt;tt&amp;gt;--previous&amp;lt;/tt&amp;gt; option. Repeating the (by now) usual example message:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously, a dedicated PO editor could automatically present appropriate diff for messages like these (e.g. [[Localization/Tools/Lokalize|Lokalize]] can do it since inception), so for translators using such an editor, diffing of fuzzies is either already available or a strong candidate for a feature request. The rest of this section therefore applies only to translators who stick to general text editors (with or without some power-assists for editing PO files).&lt;br /&gt;
&lt;br /&gt;
One ''could'' use &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; for the purpose of diffing of fuzzies, by first diffing from previous complete to new merged catalog, embedding the patch into the merged catalog, updating translation, and then unembedding ediffs. One drawback of this, however, is that two version of the catalog are necessary, when only the merged one contains all the information. More drawbacks are that the catalog has to be cleared of ediffs after updating, or that each diffed message contains more information than necessary (&amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, &amp;lt;tt&amp;gt;#. ediff:&amp;lt;/tt&amp;gt; comment) since all ediffs are of one and the same type.&lt;br /&gt;
&lt;br /&gt;
In short, full embedded diffing is too heavyweight as an assist to updating fuzzy messages. Instead, there is a Pology sieve intended for this particular purpose, &amp;lt;tt&amp;gt;diff-previous&amp;lt;/tt&amp;gt;, which embeds the difference from previous to current original text into previous fields. Executing:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve diff-previous lang.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will modify fuzzy messages in-place in the processed catalog, to the following partial ediff:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The format of embedding is the same as before, so the ediff-aware syntax highlighting works here too. When the message is updated and properly unfuzzied (both &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt; flag and previous fields removed), none of the ediff remains, so there is no need for post-unembedding. In other words, translator updates translation just as used to before, with the free benefit of having the ediff of original text.&lt;br /&gt;
&lt;br /&gt;
Note that no embedding should remain in previous fields by the time the catalog is merged again, as it would throw off &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; when matching to create new fuzzies. This will normally not be an issue, as the translator will have unfuzzied all messages when updating the catalog after last merging. However, if there were a lot of fuzzy messages, and translator didn't have the time to update all of them, &amp;lt;tt&amp;gt;diff-previous&amp;lt;/tt&amp;gt; sieve can also be used to unembed any remaining ediffs, restoring the original values of previous fields. It just needs to be run on the catalog with extra parameter &amp;lt;tt&amp;gt;strip&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve diff-previous -sstrip lang.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Tools/Pology/PO_Embedded_Diffing</id>
		<title>Localization/Tools/Pology/PO Embedded Diffing</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Tools/Pology/PO_Embedded_Diffing"/>
				<updated>2010-06-13T08:26:31Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Example corrected: do not remove, but change ediff-to-new to ediff.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Tools/Pology/PO_Embedded_Diffing}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Tools|Tools]]|&lt;br /&gt;
name=Embedded Diffing with Pology|&lt;br /&gt;
prereqs=[[Localization/Tools/Pology|Pology]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Diffing of PO So Far ==&lt;br /&gt;
&lt;br /&gt;
'''Line-level''' diffing assumes that the maximal generaly recognizable unit of text file is one line, that each line carries a meaning of significant standalone value, and that the ordering of lines has been deliberately chosen and cannot be arbitrary. For example, this is typical of program code.&lt;br /&gt;
&lt;br /&gt;
Superficially, PO files could also be considered &amp;quot;a programming language of translations&amp;quot;, and amenable to same treatment on diffing. However, some of the above assumptions which make line-level diffing viable are violated with PO format. Firstly, minimal unit of PO file is one message, whereas one line is of negligible semantic value. Secondly, ordering of messages can in principle be arbitrary (e.g. dependent on the order of extraction from source code), such that two line-wise very different PO files are actually equivalent from translator's viewpoint. And thirdly, good number of lines in the PO file are auxiliary, neither original text nor translation, generated either automatically or by the programmer (e.g. source references, extracted comments), all of which are out of translator's scope for modifications.&lt;br /&gt;
&lt;br /&gt;
Thus, a common way to use line-level diffing with PO files so far was only for review, and with some preparations. Due to myriad of equivalent but line-wise different representations of PO content, it is quite useless to send line diffs as patches; translators are instructed to always send full PO files to the reviewer/commiter, no matter the amount of modifications. Then, the reviewer merges the received PO file (new version), and possibly the original (old version), with current template, without wrapping of long lines in text fields. This &amp;quot;normalizes&amp;quot; old and new files with respect to all semantically non-significant elements, and only then can line diff be performed. Additionally, since a long non-wrapped line of translated text may differ only in some segments, a dedicated diff viewer which can highlight '''word-level''' differences has to be used; ordinary diff syntax highlighting (e.g. in shell, or in general text editor) won't cut it.&lt;br /&gt;
&lt;br /&gt;
Even with such preparations and dedicated diff viewer at hand, there is at least one significant case which is still not reasonably covered: when a fuzzy message, which had previous fields (PO was merged with &amp;lt;tt&amp;gt;--previous&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt;), has been updated and unfuzzied. For example:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''diff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code diff&amp;gt;&lt;br /&gt;
⁠  #: main.c:110&lt;br /&gt;
- #, fuzzy&lt;br /&gt;
- #| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
  msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
- msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
+ msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Here, the diff viewer will know to show word-level diff for modified translation, but it cannot know that it should also show word-level diff between the removed previous and current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields, so that reviewer can see what has changed ''in the original'' text (i.e. why the message became fuzzy), and based on that judge the change in translation.&lt;br /&gt;
&lt;br /&gt;
Finally, a dedicated PO editor may be able to show the truly proper, '''message-level''' difference (such as [[Localization/Tools/Lokalize|Lokalize]] can, operating in [http://docs.kde.org/stable/en/kdesdk/lokalize/sync.html merge mode]). Even then, however, there is still the need to send around full PO files, and, to some extent, to normalize them before comparing in the editor. The diff format becomes tied to and defined in terms of the given PO editor (which you may not want to use in general), instead of being intrinsically defined and modularly processable (such as line diffs are).&lt;br /&gt;
&lt;br /&gt;
The rest of this article will therefore propose a format and semantics for self-contained, message-level diffing of PO files -- the '''embedded diff''' -- and present two [[Localization/Tools/Pology|Pology]] scripts which embody it as proof of concept (but are also quite practically applicable).&lt;br /&gt;
&lt;br /&gt;
== The Embedded Diff ==&lt;br /&gt;
&lt;br /&gt;
Difference between two PO messages should be primarily, though not exclusively, composed of differences between its text fields (&amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, etc.) Then, to be easily judged, differences in text should be presented as succinctly and locally as possible -- think of a long paragraph where only some spelling or punctuation has changed. Finally, the format of the complete message diff should be easily comprehendable to translators used to PO format itself, and as far as possible, to existing PO tools too.&lt;br /&gt;
&lt;br /&gt;
Previous considerations lead to the following decision: ''PO message diff will also be a PO message''. Or, in other words, the diff will be ''embedded'' into the regular parts of a PO message. An embedded diff (''ediff'' for short) message should be at least syntactically a valid PO entry, if not always semantically (i.e. if part of PO file, it should pass &amp;lt;tt&amp;gt;msgfmt&amp;lt;/tt&amp;gt;, though not necessarily &amp;lt;tt&amp;gt;msgfmt --check&amp;lt;/tt&amp;gt;). To enable ediffs to be passed around as patches for PO files, the embedding should be automatically resolvable (up to significant message parts) to the old and new messages from which the diff was created.&lt;br /&gt;
&lt;br /&gt;
In this way, if ediff messages are packed into a PO file (an ediff PO), existing PO tools can be used to review and modify the diff. For example, highlighting in a text editor will need only minimal upgrades to show the embedded differences (more on that below), and otherwise it will already highlight ediff message parts as usual.&lt;br /&gt;
&lt;br /&gt;
To complete the definition of ediffs in detail, the following questions should be answered:&lt;br /&gt;
&lt;br /&gt;
* How to represent embedded differences in text?&lt;br /&gt;
&lt;br /&gt;
* Which parts of the message should be diffed?&lt;br /&gt;
&lt;br /&gt;
* How to pair for diffing messages from two files?&lt;br /&gt;
&lt;br /&gt;
* How to present collection of diffed messages?&lt;br /&gt;
&lt;br /&gt;
=== Embedding Differences into Text ===&lt;br /&gt;
&lt;br /&gt;
Once the difference between the old and new strings, the word-level difference, has been determined, it should be decided how to embed it into the new (or, equivalently, old) string. One possibility is that of &amp;lt;tt&amp;gt;wdiff(1)&amp;lt;/tt&amp;gt;, where removed and added text segments are by default wrapped with &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;[-...-]&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{+...+}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;, respectively:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''diff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;[-The Record-]{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
However, search through PO files of several translation projects (KDE, Gnome, OpenOffice, Fedora, Mozilla) reveals the &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;[-&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; character combination to be frequently encountered, e.g. in synopsis of command usage. While there must exist an escaping mechanism for cases when diff wrappers are encountered in the original text, to enable unambiguous resolving of ediffs, it is nevertheless prudent to pick wrappers which reduce frequency of escaping (e.g. syntax highlighting may not be able to discern non-diff wrapper-like segments). Searching through same collection of PO files produces no hits for &amp;lt;tt&amp;gt;{-&amp;lt;/tt&amp;gt;, so this combination is picked instead as wrapper of removed text segments:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the text itself contains a wrapper-like combination, it is escaped by inserting tilde (&amp;lt;tt&amp;gt;~&amp;lt;/tt&amp;gt;) between the brace and plus/minus sign:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Foo {+ bar&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Foo {+ qwyx&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;Foo {~+ {-bar-}{+qwyx+}&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the text already contains a substring with brace-tilde-plus/minus, then another tilde is inserted, and so on. Thus the ediff can be unambiguously resolved to old and new versions of the string. Inserting the tilde between the two characters of wrapper combinations also makes it easier on the syntax higlighting, as the difference highlighting trigger is automatically removed.&lt;br /&gt;
&lt;br /&gt;
It may happen that a given string is not merely empty in the old or new PO message, but that it does not exist at all (e.g. &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; field). Thus an ediff can be made between existing and non-existing strings too, in which case a tilde is appended to the very end of the ediff:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;a-context-note&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;{+a-context-note+}~&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Again, escaping is provided for by inserting further tildes if the ediff between two existing strings would result in trailing tilde (old: &amp;lt;tt&amp;gt;&amp;quot;~&amp;quot;&amp;lt;/tt&amp;gt;, new: &amp;lt;tt&amp;gt;&amp;quot;foo~&amp;quot;&amp;lt;/tt&amp;gt;, ediff: &amp;lt;tt&amp;gt;&amp;quot;{+foo+}~~&amp;quot;&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
How exactly the difference between two strings is formed, may be left to implementation. In fact, an implementation may allow translator to select between several diffing algorithms, depending on personal taste and situation. For example, the default algorithm of &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; does the following: words are diffed as whole, all non-word segments (interpunction, markup tags, etc.) character by character, and equal non-word segments between different words are taken into the difference segment. Hence the above ediff&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
instead of smaller&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
&amp;quot;{-The -}Record{+s+} of The Witch River&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as the former is (tentatively) easier to comprehend.&lt;br /&gt;
&lt;br /&gt;
Every difference segment in an ediff PO message will be represented like this, thus it is sufficient to upgrade PO syntax highlighting of an editor to indiscriminately highlight &amp;lt;tt&amp;gt;{-...-}&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments everywhere in the message.&lt;br /&gt;
&lt;br /&gt;
=== Message Parts Included in Diffing ===&lt;br /&gt;
&lt;br /&gt;
A PO message consists of several types of parts: text fields, comments, flags, source references, etc. It would not be very constructive to diff all of them; for example, while &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; fields should clearly be included into diffing, source references most probably should not. In order not to consider pros and cons of inclusion for each and every message part, there already exists a clear split of message parts into two groups, one of which will be taken into diffing, and the other ignored. These two groups are:&lt;br /&gt;
&lt;br /&gt;
* ''extraction-invariant'' parts -- those which do not depend on placement (or even presence) of message in the sources, such as &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; fields, manual comments, etc.&lt;br /&gt;
&lt;br /&gt;
* ''extraction-prescribed'' parts -- those which cannot exist independently of the source from which the message is extracted, such as format flags or extracted comments.&lt;br /&gt;
&lt;br /&gt;
Extraction-invariant parts are the ones which will be diffed. Working definition of exactly which parts belong into this group is provided by obsolete messages in PO files. Thus, these parts are:&lt;br /&gt;
&lt;br /&gt;
* current original: &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt; fields&lt;br /&gt;
&lt;br /&gt;
* previous original: commented &amp;lt;tt&amp;gt;#| msgctxt&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;#| msgid&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;#| msgid_plural&amp;lt;/tt&amp;gt; fields&lt;br /&gt;
&lt;br /&gt;
* translation: &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; fields&lt;br /&gt;
&lt;br /&gt;
* translator (manual) comments&lt;br /&gt;
&lt;br /&gt;
* fuzzy state (whether the &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt; flag is present)&lt;br /&gt;
&lt;br /&gt;
* obsolete state (whether the message is obsolete)&lt;br /&gt;
&lt;br /&gt;
All the listed fields and manual comments are presented in ediff message as wrapped word-level differences, as described earlier. Change in states, fuzzy and obsolete, is represented slightly differently. A special &amp;quot;extracted&amp;quot; (automatic) comment is added to the ediff message, starting with &amp;lt;tt&amp;gt;ediff:&amp;lt;/tt&amp;gt; and listing any extra info needed to describe the ediff, including the state changes. Here is an example of two messages and the ediff they would produce (whether two messages such as these would get paired for diffing in the first place, will be discussed later on):&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#~| msgid &amp;quot;Accurate subpolar weather cycles&amp;quot;&lt;br /&gt;
#~ msgid &amp;quot;Accurate subpolar climate cycles&amp;quot;&lt;br /&gt;
#~ msgstr &amp;quot;Tačni ciklusi subpolarnog vremena&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ui: property (text), widget (QCheckBox, accCyclesTrop)&lt;br /&gt;
#: config.ui:180&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;Accurate tropical weather cycles&amp;quot;&lt;br /&gt;
msgctxt &amp;quot;some-superfluous-context&amp;quot;&lt;br /&gt;
msgid &amp;quot;Accurate tropical climate cycles&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Tačni ciklusi tropskog vremena&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 1em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-obsolete-}&lt;br /&gt;
#. ui: property (text), widget (QCheckBox, accCyclesTrop)&lt;br /&gt;
#: config.ui:180&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;Accurate {-subpolar-}{+tropical+} weather cycles&amp;quot;&lt;br /&gt;
msgctxt &amp;quot;{+some-superfluous-context+}~&amp;quot;&lt;br /&gt;
msgid &amp;quot;Accurate {-subpolar-}{+tropical+} climate cycles&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Tačni ciklusi {-subpolarnog-}{+tropskog+} vremena&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Here is how this ediff message will look like in KWrite and Kate, starting with KDE 4.2:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_PO_Ediff_Highlighting.png|center|Ediff syntax highlighting in Kate]]&lt;br /&gt;
&lt;br /&gt;
(In fact, ediff-aware [http://websvn.kde.org/*checkout*/trunk/KDE/kdelibs/kate/syntax/data/gettext.xml?content-type=text%2Fplain PO syntax highlighting definition] for Kate can be used with Kate versions as early as KDE 3.4. The definition file should simply be placed as &amp;lt;tt&amp;gt;~/.kde/share/apps/katepart/syntax/gettext.xml&amp;lt;/tt&amp;gt;, and it will override the system definition.)&lt;br /&gt;
&lt;br /&gt;
First thing to note is that the ediff message contains not only extraction-invariant parts, but also copies verbatim extraction-prescribed parts from the new message. Effectively, the ediff is embedded into the copy of new message. Extraction-prescribed parts are not simply discarded in order to provide more context when reviewing the diff. Here, for example, the extracted comment states that the text is a checkbox label, which may be important for the style of translation.&lt;br /&gt;
&lt;br /&gt;
The other important element is the &amp;lt;tt&amp;gt;#. ediff:&amp;lt;/tt&amp;gt; dummy extracted comment, which here indicates that the obsolete state has been &amp;quot;removed&amp;quot;, i.e. the message was unobsoleted going from old to new version. Aside from state changes, few other indicators may rarely be present, as described in API documentation of &amp;lt;tt&amp;gt;pology.misc.diff&amp;lt;/tt&amp;gt; module, function &amp;lt;tt&amp;gt;msg_ediff&amp;lt;/tt&amp;gt;. Some of these indicators will be mentioned later on. The ediff comment will be present only when necessary, if there are any indicators to show.&lt;br /&gt;
&lt;br /&gt;
If diffing of two messages would always be conducted part for part, for all parts which are taken into diffing, then in some cases the resulting ediff would not be very useful. Consider how the first example in the article, the line-level diff of a fuzzy and translated message, would look like as ediff if performed part for part:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#| msgid &amp;quot;{-The Record of The Witch River-}~&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Beleška-}{+Beleške+} o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The same problem as with the line-level diff persists: instead of showing the difference from previous to current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, the current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; is left untouched, and previous &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; is simply shown to have been entirely removed.&lt;br /&gt;
&lt;br /&gt;
Therefore, instead of straightforward, part for part diffing, a special transformation will take place when ''exactly one'' of the two diffed messages is fuzzy and equipped with previous original text fields. This splits into two directions: from fuzzy to non-fuzzy, and from non-fuzzy to fuzzy.&lt;br /&gt;
&lt;br /&gt;
Diffing from fuzzy to non-fuzzy message, such as above, is the more usual of the two directions. It is typical of translation updated after merging with template, where some fuzzied messages will have been resolved. In this case, the original old and new messages are transformed thusly prior to diffing (&amp;lt;tt&amp;gt;*-rest&amp;lt;/tt&amp;gt; denotes all diffed parts that are neither original text nor fuzzy state):&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
fuzzy                   --&amp;gt;     fuzzy&lt;br /&gt;
old-previous-fields     --&amp;gt;     old-previous-fields&lt;br /&gt;
old-current-fields      --&amp;gt;     old-previous-fields&lt;br /&gt;
old-rest                --&amp;gt;     old-rest&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
-                       --&amp;gt;     -&lt;br /&gt;
-                       --&amp;gt;     old-current-fields&lt;br /&gt;
new-current-fields      --&amp;gt;     new-current-fields&lt;br /&gt;
new-rest                --&amp;gt;     new-rest&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In this way, ediff message's current fields will show the important difference, that of previous fields of old fuzzy message and current fields of new non-fuzzy message. Ediff message's previous fields will show the less important difference of old fuzzy messages previous and current fields, but ''only'' if it is not equal to the difference in current fields; otherwise it is eliminated. This may sound confusing, but the final ediff produced in this way is quite intuitive:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Beleška-}{+Beleške+} o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The reviewer here sees that the message was unfuzzied, the change in the original text that caused the message to become fuzzy, and the change made in translation to unfuzzy it. Old version (in removed and equal segments) of original and translation is that of the message before it got fuzzied, and new version (in added and equal segments) is that of the message after it was unfuzzied.&lt;br /&gt;
&lt;br /&gt;
From non-fuzzy to fuzzy message should be the less frequent direction of diffing. It corresponds e.g. to case where the diff is taken from older fully complete translation to the one just after merging with newest template. In this case, the transformation is as follows:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
-                       --&amp;gt;     -&lt;br /&gt;
-                       --&amp;gt;     new-previous-fields&lt;br /&gt;
old-current-fields      --&amp;gt;     old-current-fields&lt;br /&gt;
old-rest                --&amp;gt;     old-rest&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
fuzzy                   --&amp;gt;     fuzzy&lt;br /&gt;
new-previous-fields     --&amp;gt;     new-current-fields&lt;br /&gt;
new-current-fields      --&amp;gt;     new-current-fields&lt;br /&gt;
new-rest                --&amp;gt;     new-rest&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Again, the difference presented by ediff messages's current fields will be the most important one, the difference in previous fields the less important one, and eliminated if equal to the other. Here is what this will do if applied to one step earlier (just after merging) of the running example:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:89&lt;br /&gt;
msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {+fuzzy+}&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
msgid &amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The reviewer here sees that the message became fuzzy from new to old, and the change in original text that caused this. (On a side note, remember that ediff message is constructed by embedding differences into a copy of new message, so the source reference and the fuzzy flag from the new message appear here in the ediff message.)&lt;br /&gt;
&lt;br /&gt;
To be able to use the ediff as patch, it is necessary to reconstruct original old and new messages after resolving ediff into transformed old and new messages. This step is fortunatelly unambiguous; one just needs to check whether the non-fuzzy of the two resolved messages has previous fields, or, if not (due to elimination of equal difference in previous fields, or because template was merged without the &amp;lt;tt&amp;gt;--previous&amp;lt;/tt&amp;gt; option), whether the current fields are equal. Then the back-transformation to original old and new messages can be performed.&lt;br /&gt;
&lt;br /&gt;
=== Pairing Messages From Two Catalogs ===&lt;br /&gt;
&lt;br /&gt;
So far the article has described how to make an embedded diff out of two messages, once it has been decided that those messages should be diffed. However, on the lowest level, the user decides not which messages to diff, but which two PO files to diff. The implementation should then automatically ''pair'' for diffing messages from the two catalogs, and this section described several possible ways to do this.&lt;br /&gt;
&lt;br /&gt;
In the first instance, messages should obviously be '''paired by key''' (primary pairing), the unique combination of &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields. In the most usual case -- reviewing an ediff from incomplete catalog with some fuzzy and untranslated messages, to an updated catalog with some or all of those messages translated -- pairing by key will be fully sufficient, as both catalogs contain exactly the same set of messages by keys. These two messages will be plainly paired by key:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
But what should happen if some messages cannot be paired by key? Consider the earlier example where diff was taken from older fully translated, to newer merged catalog:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:89&lt;br /&gt;
msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The keys, here just current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields, of the two message do not match, so they cannot be paired by key. Yet it would be rather ungainly to represent the old message as fully removed in the ediff, and the new message as fully added:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:89&lt;br /&gt;
msgid &amp;quot;{-The Record of The Witch River-}~&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Beleška o Veštičjoj reci-}~&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. ediff: state {+fuzzy+}&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;{+The Record of The Witch River+}~&amp;quot;&lt;br /&gt;
msgid &amp;quot;{+Records of The Witch River+}~&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{+Beleška o Veštičjoj reci+}~&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
(That the message has been fully added or removed can be seen by trailing tilde in the &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, which indicates that the old or new &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; does not exist at all, and so neither the message with it.)&lt;br /&gt;
&lt;br /&gt;
Instead, messages left unpaired by key should be tested for '''pairing by pivoting''' around previous fields (secondary pairing). The two messages above will thus be paired due to the fact that the current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; of the old message is equal to the previous &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; of the new message, and will produce a single ediff message as shown earlier.&lt;br /&gt;
&lt;br /&gt;
Finally, consider the third related combination, when the old catalog has not yet been merged with the template, while the new catalog has both been merged and its translation updated:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:89&lt;br /&gt;
msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Once again, it would be a waste to present the old message as fully removed and the new message as fully added in the ediff. When a message is left unpaired after both pairing by key and pairing by pivoting, then the two catalogs should be merged in the background -- as if the new is the template for the old, and vice versa -- and then tested for chained pairing by pivoting and by key with merged catalog as intermediary. This '''pairing by merging''', or tertiary pairing, will then produce another natural ediff:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Beleška-}{+Beleške+} o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Implementations can decide which pairing modes beyond the primary, by key, to use. There should not be much reason not to perform secondary pairing, by pivoting, too. If tertiary pairing, by merging, is implemented, it should be provided that the user can disable it (sometimes this pairing may produce strange results, and needs &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; to be available on the system).&lt;br /&gt;
&lt;br /&gt;
=== Collecting Diffed Messages ===&lt;br /&gt;
&lt;br /&gt;
For ediff of two PO files to also be a syntactically valid PO file, constructed ediff messages should be preceded by a PO header on output. At first glance, this PO header could be itself the ediff of PO headers of the catalogs which were diffed. However, there are several issues with this approach:&lt;br /&gt;
&lt;br /&gt;
* Reviewer of the ediff PO file would not be informed at once whereas there was any difference between the headers. Headers tend to be long, and a point change in one of the fields may go visually unnoticed.&lt;br /&gt;
&lt;br /&gt;
* Depending on the amount of changes between the two headers, the resulting ediff message of the header could be too badly formed to represent the header as such (e.g. if header fields in &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; were added or removed, embedded difference wrappers would invalidate MIME-header format of &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt;), and thus confuse the PO tools.&lt;br /&gt;
&lt;br /&gt;
* How would the diff of two ''collections'' of PO files (e.g. directories) be packed into a single ediff PO, such as can normally be done with line-level diffing?&lt;br /&gt;
&lt;br /&gt;
To avert these difficulties, the following is done instead. First, the header of ediff PO is constructed as a minimal valid header (i.e. one that &amp;lt;tt&amp;gt;msgfmt&amp;lt;/tt&amp;gt; would not complain about) independent of the content of original headers. &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; will produce something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
# +- ediff -+&lt;br /&gt;
msgid &amp;quot;&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;Project-Id-Version: ediff\n&amp;quot;&lt;br /&gt;
&amp;quot;PO-Revision-Date: 2009-02-08 01:20+0100\n&amp;quot;&lt;br /&gt;
&amp;quot;Last-Translator: J. Random Translator\n&amp;quot;&lt;br /&gt;
&amp;quot;Language-Team: Differs\n&amp;quot;&lt;br /&gt;
&amp;quot;MIME-Version: 1.0\n&amp;quot;&lt;br /&gt;
&amp;quot;Content-Type: text/plain; charset=UTF-8\n&amp;quot;&lt;br /&gt;
&amp;quot;Content-Transfer-Encoding: 8bit\n&amp;quot;&lt;br /&gt;
&amp;quot;X-Ediff-Header-Context: ~\n&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;PO-Revision-Date&amp;lt;/tt&amp;gt; header field is naturally set to the date when the ediff is made. &amp;lt;tt&amp;gt;Last-Translator&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Language-Team&amp;lt;/tt&amp;gt; can be somehow pulled from environment (&amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; will source them from &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, or set some dummy values as above if not present). Encoding of the ediff PO can be chosen at will by the implementation, so long as all following ediff messages can be encoded with it (&amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; will always use UTF-8). The purpose of the &amp;lt;tt&amp;gt;X-Ediff-Header-Context&amp;lt;/tt&amp;gt; field will be explained shortly.&lt;br /&gt;
&lt;br /&gt;
It is the first next message in the ediff PO that will actually be the ediff of headers of the two diffed PO files. Headers are diffed just like any other message, but the resulting ediff is equiped with few extra decorations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
# =========================================================&lt;br /&gt;
# Translation of The Witch River into Serbian.&lt;br /&gt;
# Koja Kojic &amp;lt;koja.kojic@nedohodnik.net&amp;gt;, 2008.&lt;br /&gt;
# {+Era Eric &amp;lt;era.eric@ledopad.net&amp;gt;, 2008.+}~&lt;br /&gt;
msgctxt &amp;quot;~&amp;quot;&lt;br /&gt;
msgid &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;- l10n-wr/sr/wriver-main.po\n&amp;quot;&lt;br /&gt;
&amp;quot;+ l10n-wr/sr-mod/wriver-main.po\n&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;Project-Id-Version: wriver 0.1\n&amp;quot;&lt;br /&gt;
&amp;quot;POT-Creation-Date: 2008-09-22 09:17+0200\n&amp;quot;&lt;br /&gt;
&amp;quot;PO-Revision-Date: 2008-09-{-25 20:44-}{+28 21:49+}+0100\n&amp;quot;&lt;br /&gt;
&amp;quot;Last-Translator: {-Koja Kojic &amp;lt;koja.kojic@nedohodnik-}&amp;quot;&lt;br /&gt;
&amp;quot;{+Era Eric &amp;lt;era.eric@ledopad+}.net&amp;gt;\n&amp;quot;&lt;br /&gt;
&amp;quot;Language-Team: Serbian\n&amp;quot;&lt;br /&gt;
&amp;quot;MIME-Version: 1.0\n&amp;quot;&lt;br /&gt;
&amp;quot;Content-Type: text/plain; charset=UTF-8\n&amp;quot;&lt;br /&gt;
&amp;quot;Content-Transfer-Encoding: 8bit\n&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First observe the normal ediff segments: translator comment with a new translator who updated the PO file has been added, and &amp;lt;tt&amp;gt;PO-Revision-Date&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Last-Translator&amp;lt;/tt&amp;gt; header fields contain ediffs reflecting the update. These are the only actual differences between the two headers.&lt;br /&gt;
&lt;br /&gt;
More interesting are the extra decorations:&lt;br /&gt;
&lt;br /&gt;
* The very first translator comment (here a long line of equality signs) can be anything, and serves to give good visual distinction to the header ediff. This is more so convenient when the ediff PO contains diffs of several pairs of PO files.&lt;br /&gt;
&lt;br /&gt;
* That a particular message in the ediff PO is a header ediff, is indicated by the &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; set to a special value, here a single tilde. This value is given up front by the &amp;lt;tt&amp;gt;X-Ediff-Header-Context&amp;lt;/tt&amp;gt; of the ediff PO header. It should be computed during diffing such that it does not conflict with &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; of one of the normal message ediffs (e.g. it may simply be a sufficiently long sequence tildes).&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field of the header ediff contains newline-separated paths of the diffed PO files. More precisely, the two lines of the &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field are in form &amp;lt;code text&amp;gt;[+-] file-path[ &amp;lt;&amp;lt;&amp;lt; comment]\n&amp;lt;/code&amp;gt; (The trailing newline of the second file path is elided if the &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; does not end in newline, to prevent &amp;lt;tt&amp;gt;msgfmt&amp;lt;/tt&amp;gt; from complaining.) The optional, &amp;amp;lt;&amp;amp;lt;&amp;amp;lt;-separated comment to the file path can be used for any purpose, one which will be demonstrated when describing functionality of &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Although when a PO file is properly updated there should always be some difference in its header, it may happen that there is none. In such case, the header ediff message is still added, but such that it only contains the extra decorations -- the visual separator comment, special &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; with file paths. All other comments and &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; should be empty, and the empty &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; indicates that there was no difference in headers. Presence of this &amp;quot;empty&amp;quot; header ediff is necessary to provide diffed file paths and, if several POs were diffed, to separate them in the ediff PO.&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_Dir_Ediff_PO.png|right|150x150px|Embedded diff of directory of PO files in Kate.]]&lt;br /&gt;
&lt;br /&gt;
After the header ediff message, ordinary ediff messages follow. As already obvious by now, when several POs were diffed to construct a single ediff PO, each next PO in the ediff simply opens with a new header ediff message. Click on the thumbnail on the right to see how an ediff of two PO files looks like in entirety, with syntax highlighting in Kate.&lt;br /&gt;
&lt;br /&gt;
Especially when diffing several PO files, it may happen that two ediff messages have equal keys (&amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; fields) and thus cannot be both added as such to the ediff PO. In such case, the ediff message which was added after the first with the same key, will have its &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; field ''padded'' by few random alphanumerics, such as to make its key unique. This padding sequence will be recorded in the ediff comment. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
# =========================================================&lt;br /&gt;
msgctxt &amp;quot;~&amp;quot;&lt;br /&gt;
msgid &amp;quot;...(first PO header ediff)...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
msgid &amp;quot;White{+ horizon+}&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Belo{+ obzorje+}&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
# =========================================================&lt;br /&gt;
msgctxt &amp;quot;~&amp;quot;&lt;br /&gt;
msgid &amp;quot;...(second PO header ediff)...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. ediff: state {-fuzzy-}, ctxtpad q9ac3&lt;br /&gt;
msgctxt &amp;quot;|q9ac3~&amp;quot;&lt;br /&gt;
msgid &amp;quot;White{+ horizon+}&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Belo{+ obzorje+}&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The padding sequence is appended to the original &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, separated by the pipe character. If there was no original &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt;, the padding sequence is further extended by a tilde.&lt;br /&gt;
&lt;br /&gt;
== Producing Ediffs: &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Pology's &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; script implements embedded diffing as outlined in the previous section. To diff two PO files, executing the usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poediff orig/foo.po mod/foo.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will write the ediff PO (if there is any difference) to standard output, with some basic shell highlighting of difference segments. Option &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; can be used to output the ediff PO to file instead. Other options include &amp;lt;tt&amp;gt;--no-merge&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;-n&amp;lt;/tt&amp;gt;) to not perform pairing by merging, and &amp;lt;tt&amp;gt;--strip-headers&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt;) to take a quick look of differences without headers in the way (output with stripped headers is not a valid PO, and cannot be used as patch).&lt;br /&gt;
&lt;br /&gt;
It is equally simple to make ediff of directories:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poediff orig/ mod/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diffing of directories is by default recursive and takes into ediff added and removed catalogs. When a catalog has been added or removed, the &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; of corresponding header ediff will have one of the file paths, new or old, empty.&lt;br /&gt;
&lt;br /&gt;
To have non-dummy translator name and email address added to the header of ediff PO, set them in Pology's configuration file, &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code ini&amp;gt;&lt;br /&gt;
[user]&lt;br /&gt;
name = Koja Kojic&lt;br /&gt;
original-name = Која Којић&lt;br /&gt;
email = koja.kojic@nedohodnik.net&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(These entries cover all contexts in Pology where such information is of use; &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field is used when the name is to be written differently in English and translator's native language.)&lt;br /&gt;
&lt;br /&gt;
This is pretty much where the story about &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; would end, if not for its ability to take into account the underlying VCS, if one is used to control PO files.&lt;br /&gt;
&lt;br /&gt;
=== Diffing With Underlying VCS ===&lt;br /&gt;
&lt;br /&gt;
When PO files are under version control, &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; can operate in VCS mode using the option &amp;lt;tt&amp;gt;-c VCSKEY&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;--vcs&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;VCSKEY&amp;lt;/tt&amp;gt; is the keyword of one of VCS known to &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt;. Then, instead of giving two paths to diff, any number of version-controlled paths (files or directories) is given. Without other options, all modified PO files in these paths are diffed against the last commit known to local repository. For example, if an application uses Subversion repository, PO files in its &amp;lt;tt&amp;gt;po/&amp;lt;/tt&amp;gt; directory can be diffed with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poediff -c svn app/po/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some other set of revisions to diff can be given by the option &amp;lt;tt&amp;gt;-r REV1&amp;lt;nowiki&amp;gt;[:REV2]&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;--revision&amp;lt;/tt&amp;gt;). &amp;lt;tt&amp;gt;REV1&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;REV2&amp;lt;/tt&amp;gt; are not necessarily proper revision IDs, but any strings that the underlying VCS will be able to convert into revision IDs. If &amp;lt;tt&amp;gt;REV2&amp;lt;/tt&amp;gt; is omitted, diffing is preformed from &amp;lt;tt&amp;gt;REV1&amp;lt;/tt&amp;gt; to current working copy.&lt;br /&gt;
&lt;br /&gt;
When ediff is made in VCS mode, &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields of header ediffs will use &amp;amp;lt;&amp;amp;lt;&amp;amp;lt;-separated comments to file paths to indicate revision IDs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
# =========================================================&lt;br /&gt;
# ...&lt;br /&gt;
msgctxt &amp;quot;~&amp;quot;&lt;br /&gt;
msgid &amp;quot;&amp;quot;&lt;br /&gt;
&amp;quot;- app/po/lang.po &amp;lt;&amp;lt;&amp;lt; 20537\n&amp;quot;&lt;br /&gt;
&amp;quot;+ app/po/lang.po&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As for supported VCS, Pology currently knows about Subversion (&amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt;) and Git (&amp;lt;tt&amp;gt;git&amp;lt;/tt&amp;gt;). To add a new VCS, its functionality should be wrapped for Pology's use in &amp;lt;tt&amp;gt;pology.misc.vcs&amp;lt;/tt&amp;gt;, using the interface defined by &amp;lt;tt&amp;gt;VcsBase&amp;lt;/tt&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
== Ediffs as Patches: &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
For basic functionality, applying an ediff patch is implementationally even easier than applying a line-level patch. Each ediff message in turn is resolved into originating old and new message, and if either the old or new message exists in target PO and is equal by extraction-invariant parts, then the message patch is applied, otherwise rejected.&lt;br /&gt;
&lt;br /&gt;
Applying the patch means overwriting extraction-invariant parts of the target message with those of the new message from the ediff, and leaving other parts untouched. If the target message is already equal to new message by extraction-invariant parts, then the patch is silently ignored. This means that if the same patch is applied twice, second application makes no modifications to the target catalog. Likewise if, by chance, the changes given by the patch were already independently introduced in the target catalog.&lt;br /&gt;
&lt;br /&gt;
Command-line interface of &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; is much like &amp;lt;tt&amp;gt;patch(1)&amp;lt;/tt&amp;gt;, sans the myriad of its more obscure options. There is the &amp;lt;tt&amp;gt;-p&amp;lt;/tt&amp;gt; option to strip leading elements of file paths in the ediff, and &amp;lt;tt&amp;gt;-d&amp;lt;/tt&amp;gt; option to append to them a directory path where target POs are to be found. If the files were diffed with underlying VCS as in the previous example, then the ediff could be applied in any of the following ways:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd repos/app/po &amp;amp;&amp;amp; poepatch &amp;lt;ediff.po&lt;br /&gt;
$ cd repos/ &amp;amp;&amp;amp; poepatch -p0 &amp;lt;ediff.po&lt;br /&gt;
$ poepatch -d repos/app/po &amp;lt;ediff.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Header patch (coming from the header ediff message) is applied in a slightly more relaxed fashion: some of the header fields are ignored when checking whether the patch is applicable. These are the fields which are known to be volatile as the PO file goes through different translators, and do not influence the processing of the catalog directed by the header (such as encoding or plural forms). Currently, these fields are: &amp;lt;tt&amp;gt;POT-Creation-Date&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;PO-Revision-Date&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Last-Translator&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;X-Generator&amp;lt;/tt&amp;gt;. When a header patch is accepted, these fields in the target header are overwritten with those from the patch (including being added or removed).&lt;br /&gt;
&lt;br /&gt;
=== Handling Rejected Ediffs ===&lt;br /&gt;
&lt;br /&gt;
Any rejected ediff messages will be written out to &amp;lt;tt&amp;gt;stdin.rej.po&amp;lt;/tt&amp;gt; if the patch was read from standard input, or to &amp;lt;tt&amp;gt;&amp;amp;lt;catname&amp;amp;gt;.rej.po&amp;lt;/tt&amp;gt; if it was given as file through &amp;lt;tt&amp;gt;-i&amp;lt;/tt&amp;gt; option (e.g. &amp;lt;tt&amp;gt;ediff.rej.po&amp;lt;/tt&amp;gt; for input &amp;lt;tt&amp;gt;ediff.po&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
File with rejected ediff messages will again be an ediff PO file. It will have the header as before, except that its title comment will mention, in free prose, that this particular ediff PO contains rejects of some patching operation. Afterwards, ediff messages rejected as patch will follow. Header ediff messages will be present whether rejected or not, for the same purpose of separation and provision of file paths, but they will be stripped of comments and &amp;lt;tt&amp;gt;msgstr&amp;lt;/tt&amp;gt; when the header patch itself was not rejected.&lt;br /&gt;
&lt;br /&gt;
Furthermore, to every straigh-out rejected ediff message an &amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; flag will be added. This is done, naturally, because some ediff messages may not be rejected straight-out, but go through some post-processing instead. Consider the following scenario. A catalog has been merged to produce the fuzzy message:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''old'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: tools/power.c:348&lt;br /&gt;
msgid &amp;quot;Active sonar low frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Niska frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;Active sonar low frequency&amp;quot;&lt;br /&gt;
msgid &amp;quot;Active sonar high frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Niska frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Translator updates the translation, which produces the usual ediff message on update from fuzzy to translated:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 0.5em; width: 1%&amp;quot;|'''ediff'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
msgid &amp;quot;Active sonar {-low-}{+high+} frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Niska-}{+Visoka+} frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
However, ''before'' this patch could have been applied, the programmer adds a trailing colon to the same message, and the catalog is merged again to produce:&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;padding-right: 1em; width: 1%&amp;quot;|'''new2'''&lt;br /&gt;
|style=&amp;quot;padding-bottom: 0.5em&amp;quot;|&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;Active sonar low frequency&amp;quot;&lt;br /&gt;
msgid &amp;quot;Active sonar high frequency:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Niska frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The patch can no longer be cleanly applied, due to the extra colon added in the meantime to the &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt;, so it has to be rejected. If nothing else is done, it would appear in the file of rejects as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, ediff-no-match&lt;br /&gt;
msgid &amp;quot;Active sonar {-low-}{+high+} frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Niska-}{+Visoka+} frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It seems a bit wastefull to reject such a near-match patch without any indication that it could be easily adapted to suit the latest message in the target PO. Therefore, when an ediff message is rejected, the following analysis is performed: by trying out message pairings as described for diffing, could the old message from the patch be paired with a current message from the target PO, and that current message with the new message from the patch? Or, in other words, can an existing message in the target PO be &amp;quot;fitted in between&amp;quot; the old and new messages defined by the patch? If this is the case, instead of the original, two special ediff messages -- ''split rejects'' -- are constructed and written out: one from the old to the current message, and another from the current to the new message. They are flagged as &amp;lt;tt&amp;gt;ediff-to-cur&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt;, respectively:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, fuzzy, ediff-to-cur&lt;br /&gt;
#| msgid &amp;quot;Active sonar low frequency&amp;quot;&lt;br /&gt;
msgid &amp;quot;Active sonar high frequency{+:+}&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Niska frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, ediff-to-new&lt;br /&gt;
#| msgid &amp;quot;Active sonar {-low-}{+high+} frequency{+:+}&amp;quot;&lt;br /&gt;
msgid &amp;quot;Active sonar {-low-}{+high+} frequency&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Niska-}{+Visoka+} frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are more ways to interpret split rejects, depending on the circumstances. In this example, from &amp;lt;tt&amp;gt;ediff-to-cur&amp;lt;/tt&amp;gt; message reviewer can see what had changed in the target message after the translator made the ediff. This can also be seen by comparing difference embedded into previous and current &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; fields in the &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt; message. With slightly more extensive editing, the reviewer can fold these two messages into an applicable patch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. ediff: state {-fuzzy-}&lt;br /&gt;
#: tools/power.c:361&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;Active sonar {-low-}{+high+} frequency:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Niska-}{+Visoka+} frekvencija aktivnog sonara&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Given that the file of rejected ediffs is also an ediff PO, after edits to make some of the rejected patches applicable, it can be ''reapplied'' as patch. If that is done, &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; will silently ignore all ediff messages having &amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt; flag, as these have already been determined inapplicable. That is why in the example above the reviewer has replaced the &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt; with the plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag on the folded ediff.&lt;br /&gt;
&lt;br /&gt;
=== Embedding Patches ===&lt;br /&gt;
&lt;br /&gt;
Depending on the type of text which is being translated, and distance of translation language's grammar, ortography and style from English, it may be difficult to review an ediff in isolation. In general, messages in ediff PO will lack ''positional context'', which is in the full PO provided by messages immediately preceding and following the target message. For example, a long passage from documentation probably needs no positional context. But a short newly added message such as &amp;quot;Crimson&amp;quot; could very well need one, if it has neither &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; nor extracted comment describing it. Is it really a color? What grammatical ending should it have, in a language which matches adjective to noun gender? Several messages around it in the full PO could easily show whether it is just another color in a row, and their grammatical endings (determined by a translator earlier) would show the needed ending for the new color.&lt;br /&gt;
&lt;br /&gt;
Then, if an ediff message needs some editing before being applied, it may not be easy to do this directly in the ediff PO. Everything is fine so long as only added text segments (&amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt;) are edited, but if the sentence needs to be restructured more thoroughly, reviewer would have to make sure to put all additions into existing or new &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments, and to wrap all removals as &amp;lt;tt&amp;gt;{-...-}&amp;lt;/tt&amp;gt; segments. If this is not carefully performed, the patch will not be applicable any more, as old message resolved from it will no longer exactly match a message in the target PO.&lt;br /&gt;
&lt;br /&gt;
For these reasons, &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; can apply the patch such as ''not to resolve the ediff'', but to set all its extraction-invariant fields to the message in the patched PO. In effect, the patched PO becomes an ediff PO by itself, but only in the messages which were actually patched. To mark these messages for lookup, &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag is added to them. If the message in the ediff PO was:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: title.c:274&lt;br /&gt;
msgid &amp;quot;Tutorial&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Tutorijal-}{+Podučavanje+}&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then when the patch is successfully applied with embedding, the patched message in target PO will look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleške o Veštičjoj reci&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#: title.c:292&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;Tutorial&amp;quot;&lt;br /&gt;
msgstr &amp;quot;{-Tutorijal-}{+Podučavanje+}&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#: title.c:328&lt;br /&gt;
msgid &amp;quot;Start the Expedition&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Pođi u ekspediciju&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Other than the addition &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, note that the patched message also kept its source reference, rather than it being overwritten by that from ediff PO. Same holds for all extraction-prescribed parts.&lt;br /&gt;
&lt;br /&gt;
Reviewer can now jump from &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;edif&amp;lt;/tt&amp;gt; flag, always having the full positional context for each patched message, and being able to edit it to heart's content, with only minimal care not to invalidate the ediff format. Wrapped difference segments can be entirely removed, non-wrapped segments can be freely edited; it should only not happen that a wrapped segment looses its opening or closing sequence. But this does not mean that the reviewer ''needs'' to remove or touch difference segments at all, that is, to unembed patched messages by hand -- &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; will do that automatically, when run on embedded-patched POs with a particular option.&lt;br /&gt;
&lt;br /&gt;
A patch is applied with embedding by issuing the &amp;lt;tt&amp;gt;-e&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;--embed&amp;lt;/tt&amp;gt;) option (&amp;lt;tt&amp;gt;E&amp;lt;/tt&amp;gt; in parenthesis in progress output indicates that embedding is engaged):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poepatch -e &amp;lt;ediff.po&lt;br /&gt;
patched (E): lang.po&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When the patched PO has been reviewed and patched messages possibly edited, all remaining embedded differences are removed, i.e. resolved to new versions, by running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poepatch -u lang.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only those messages having the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag are resolved, therefore the reviewer should ''never'' remove them (unless manually unembedding the whole patched message).&lt;br /&gt;
&lt;br /&gt;
What happens with rejected patches when embedding is engaged? They are also added into the target PO, with heuristic positioning, and no separate ediff PO with rejects is created. Same as with plain patching, straight-out rejects will have &amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; flag, and split rejects &amp;lt;tt&amp;gt;ediff-to-cur&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt;. If these are not manually resolved during the review (&amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; messages removed, &amp;lt;tt&amp;gt;ediff-to-*&amp;lt;/tt&amp;gt; messages removed or folded), when &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; is run to unembed the patch, it will remove all &amp;lt;tt&amp;gt;ediff-no-match&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ediff-to-new&amp;lt;/tt&amp;gt; messages, and resolve &amp;lt;tt&amp;gt;ediff-to-cur&amp;lt;/tt&amp;gt; messages to new version (effectively rejecting patches from which split rejects had originated).&lt;br /&gt;
&lt;br /&gt;
== Lightweight Diffing when Updating Translation ==&lt;br /&gt;
&lt;br /&gt;
Rather than for reviewing changes and sending patches, the translator may want to have only a convenient diff between the previous and new original text when updating a catalog merged with &amp;lt;tt&amp;gt;--previous&amp;lt;/tt&amp;gt; option. Repeating the (by now) usual example message:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;The Record of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously, a dedicated PO editor could automatically present appropriate diff for messages like these (e.g. [[Localization/Tools/Lokalize|Lokalize]] can do it since introduction), so for translators using such an editor, diffing of fuzzies is either already available or a strong candidate for a feature request. The rest of this section therefore applies only to translators who stick to general text editors (with or without some power-assists for editing PO files).&lt;br /&gt;
&lt;br /&gt;
One ''could'' use &amp;lt;tt&amp;gt;poediff&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;poepatch&amp;lt;/tt&amp;gt; for the purpose of diffing of fuzzies, by first diffing from previous complete to new merged catalog, embedding the patch into the merged catalog, updating translation, and then unembedding ediffs. One drawback of this, however, is that two version of the catalog are necessary, when only the merged one contains all the information. More drawbacks are that the catalog has to be cleared of ediffs after updating, or that each diffed message contains more information than necessary (&amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, &amp;lt;tt&amp;gt;#. ediff:&amp;lt;/tt&amp;gt; comment) since all ediffs are of one and the same type.&lt;br /&gt;
&lt;br /&gt;
In short, full embedded diffing is too heavyweight as an assist to updating fuzzy messages. Instead, there is a Pology sieve intended for this particular purpose, &amp;lt;tt&amp;gt;diff-previous&amp;lt;/tt&amp;gt;, which embeds the difference from previous to current original text into previous fields. Executing:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve diff-previous lang.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will modify fuzzy messages in-place in the processed catalog, to the following partial ediff:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#: main.c:110&lt;br /&gt;
#, fuzzy&lt;br /&gt;
#| msgid &amp;quot;{-The Record-}{+Records+} of The Witch River&amp;quot;&lt;br /&gt;
msgid &amp;quot;Records of The Witch River&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Beleška o Veštičjoj reci&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The format of embedding is the same as before, so the ediff-aware syntax highlighting works here too. When the message is updated and properly unfuzzied (both &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt; flag and previous fields removed), none of the ediff remains, so there is no need for post-unembedding. In other words, translator updates translation just as used to before, with the free benefit of having the ediff of original text.&lt;br /&gt;
&lt;br /&gt;
Note that no embedding should remain in previous fields by the time the catalog is merged again, as it would throw off &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; when matching to create new fuzzies. This will normally not be an issue, as the translator will have unfuzzied all messages when updating the catalog after last merging. However, if there were a lot of fuzzy messages, and translator didn't have the time to update all of them, &amp;lt;tt&amp;gt;diff-previous&amp;lt;/tt&amp;gt; sieve can also be used to unembed any remaining ediffs, restoring the original values of previous fields. It just needs to be run on the catalog with extra parameter &amp;lt;tt&amp;gt;strip&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve diff-previous -sstrip lang.po&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Localization/i18n_Semantics</id>
		<title>Development/Tutorials/Localization/i18n Semantics</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Localization/i18n_Semantics"/>
				<updated>2010-06-12T16:24:21Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Mention new 'row' subcue.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Abstract ==&lt;br /&gt;
&lt;br /&gt;
Typical way of formatting user visible strings in application interfaces, for a long time has been that of plain text or at most visual markup like HTML tags. In most textual content environments, shift to ''semantic'' markup has been recognized as superior to visual (for example, the Docbook XML for documentation). Why not go down the same road for UI strings?&lt;br /&gt;
&lt;br /&gt;
== Semantic Markup by Examples ==&lt;br /&gt;
&lt;br /&gt;
In the semantic model, user interface strings are marked for their ''context'', and text elements within for their ''meaning'' rather than visual appearance. Consider few i18n examples of usual, non-semantic format:&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18n(&amp;quot;Move&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
i18n(&amp;quot;Descending&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
i18n(&amp;quot;&amp;lt;qt&amp;gt;&amp;lt;b&amp;gt;%1&amp;lt;/b&amp;gt; does not exist&amp;lt;/qt&amp;gt;&amp;quot;, fname);&lt;br /&gt;
&lt;br /&gt;
i18n(&amp;quot;&amp;lt;h1&amp;gt;History Sidebar&amp;lt;/h1&amp;gt; You can configure the history sidebar here.&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using KDE UI Text (KUIT for short) semantic markup, these strings would be formated like this:&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@action:button&amp;quot;, &amp;quot;Move&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
i18nc(&amp;quot;@item:inmenu&amp;quot;, &amp;quot;Descending&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;, &amp;quot;&amp;lt;filename&amp;gt;%1&amp;lt;/filename&amp;gt; does not exist&amp;quot;, fname);&lt;br /&gt;
&lt;br /&gt;
i18nc(&amp;quot;@info:whatsthis&amp;quot;,&lt;br /&gt;
      &amp;quot;&amp;lt;title&amp;gt;History Sidebar&amp;lt;/title&amp;gt;&amp;quot;&lt;br /&gt;
      &amp;quot;&amp;lt;para&amp;gt;You can configure the history sidebar here.&amp;lt;/para&amp;gt;&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Two distinct differences between ordinary and KUIT markup can be observed.&lt;br /&gt;
&lt;br /&gt;
The first is the use of context i18n calls, the &amp;lt;tt&amp;gt;i18nc()&amp;lt;/tt&amp;gt;, to convey the usage context of the string by means of the ''context marker''. The first message above, &amp;quot;Move&amp;quot;, has been assigned the &amp;lt;tt&amp;gt;@action:button&amp;lt;/tt&amp;gt; marker, where &amp;lt;tt&amp;gt;@action&amp;lt;/tt&amp;gt; is the ''semantic role'' which describes the text as an action to be taken (e.g. operation on data or opening of a new dialog), and &amp;lt;tt&amp;gt;:button&amp;lt;/tt&amp;gt; is the ''interface subcue'' saying that this text is displayed on a pushbutton widget. The second message, &amp;quot;Descending&amp;quot;, has been marked as semantically a list item (&amp;lt;tt&amp;gt;@item&amp;lt;/tt&amp;gt;), displayed in a menu (&amp;lt;tt&amp;gt;:inmenu&amp;lt;/tt&amp;gt;). The interface subcue can be left out if none is appropriate, as has been done in the third message.&lt;br /&gt;
&lt;br /&gt;
The other difference is the use of the semantic tags, which convey the meaning of a word or phrase within the text. The &amp;lt;tt&amp;gt;&amp;lt;filename&amp;gt;%1&amp;lt;/filename&amp;gt;&amp;lt;/tt&amp;gt; part of the third message tells that the substituted text is the name of a file. The &amp;lt;tt&amp;gt;&amp;lt;title&amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;lt;para&amp;gt;&amp;lt;/tt&amp;gt; tags in the last message clearly lay out structure of a longer informational text.&lt;br /&gt;
&lt;br /&gt;
{{note|The context marker can be added when within some of the standard XML sources too. In Qt Designer forms (&amp;lt;tt&amp;gt;.ui&amp;lt;/tt&amp;gt; files), each text label to a widget has &amp;lt;tt&amp;gt;comment&amp;lt;/tt&amp;gt; attribute (presented as &amp;quot;disambiguation&amp;quot; property within Designer, or &amp;quot;comment&amp;quot; prior to Qt 4.5), which can be used in the same manner as context argument of &amp;lt;tt&amp;gt;i18nc()&amp;lt;/tt&amp;gt; call. Similarly, in the KXmlGui (&amp;lt;tt&amp;gt;.rc&amp;lt;/tt&amp;gt;) and KConfigXT (&amp;lt;tt&amp;gt;.kcfg&amp;lt;/tt&amp;gt;) files, tags &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;whatsthis&amp;lt;/tt&amp;gt; can have a &amp;lt;tt&amp;gt;context&amp;lt;/tt&amp;gt; attribute. For example:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;label context=&amp;quot;@label&amp;quot;&amp;gt;Hide trivial details&amp;lt;/label&amp;gt;&lt;br /&gt;
&amp;lt;whatsthis context=&amp;quot;@info:whatsthis&amp;quot;&amp;gt;Option to hide drivel&amp;lt;/whatsthis&amp;gt;&lt;br /&gt;
&amp;lt;text context=&amp;quot;@item:inmenu&amp;quot;&amp;gt;&amp;amp;amp;New...&amp;lt;/text&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Even when context marker is present, sometimes the programmer may want to provide an additional &amp;quot;free-form&amp;quot; description to translators, in order shed more light on particularly ambiguous strings. The free-form description is just separated by a whitespace from the context marker proper, like this:&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@item:inmenu Sorting order&amp;quot;, &amp;quot;Descending&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One particularly useful and yet general piece of free-form description, is the title under which the message is grouped -- the menu title for actions in menu, the group title of set of radio-buttons, the listbox label for items in list, etc. For example:&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
iconSizeBox = new QGroupBox(i18nc(&amp;quot;@title:group&amp;quot;, &amp;quot;Icon Size&amp;quot;), this);&lt;br /&gt;
//...&lt;br /&gt;
iconSize1 = new QRadioButton(i18nc(&amp;quot;@option:radio Icon Size&amp;quot;, &amp;quot;Small&amp;quot;), this);&lt;br /&gt;
iconSize2 = new QRadioButton(i18nc(&amp;quot;@option:radio Icon Size&amp;quot;, &amp;quot;Medium&amp;quot;), this);&lt;br /&gt;
iconSize3 = new QRadioButton(i18nc(&amp;quot;@option:radio Icon Size&amp;quot;, &amp;quot;Large&amp;quot;), this);&lt;br /&gt;
//...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Advantages of Semantic Markup ==&lt;br /&gt;
&lt;br /&gt;
KUIT markup has advantages both to users and to translators of applications that make use of it.&lt;br /&gt;
&lt;br /&gt;
For the users, the use of semantic tags means consistent formatting of same kinds of text. A notorious example of inconsistent visual formatting are filenames and paths, which are sometimes put in as is, sometimes in quotes (and ordinary quotes at that, rather than proper English fancy quotes), and sometimes in bold tags. Furthermore, the text withing the tag may be modified when semantically marked; for example, the standard &amp;quot;/&amp;quot; path delimiters in a &amp;lt;tt&amp;gt;&amp;lt;filename&amp;gt;&amp;lt;/tt&amp;gt; text will be substituted for platform specific ones.&lt;br /&gt;
&lt;br /&gt;
Translators will benefit from both context markers and tags. For the &amp;lt;tt&amp;gt;@action&amp;lt;/tt&amp;gt; role of the &amp;quot;Move&amp;quot; string in the example above, the translator may use command form of the verb, while gerund form (like &amp;quot;Moving&amp;quot;) may be more appropriate for the &amp;lt;tt&amp;gt;@title&amp;lt;/tt&amp;gt; role, which would be used if the string was title of the menu, window, etc. The interface subcue, like &amp;lt;tt&amp;gt;:button&amp;lt;/tt&amp;gt; above, if present, additionally enables the translator to mentally picture the actual runtime GUI. Tags within the text will also benefit translators, as they may clarify the structure of the sentence, especially in presence of placeholder substitutions.&lt;br /&gt;
&lt;br /&gt;
Context markers also serve a technical purpose: they decide whether what form of visual formatting is used. For example, any &amp;lt;tt&amp;gt;@title&amp;lt;/tt&amp;gt; role will use plain text, whereas &amp;lt;tt&amp;gt;@info&amp;lt;/tt&amp;gt; will frequently produce rich text, depending on the subcue.&lt;br /&gt;
&lt;br /&gt;
None the least, semantic markup removes the burden from programmers of thinking about the visual formatting to apply, like &amp;quot;''Should I put the path in quotes or &amp;amp;lt;b&amp;gt;?''&amp;quot;, or &amp;quot;''Should the title be &amp;amp;lt;h2&amp;gt; or &amp;amp;lt;h3&amp;gt;?''&amp;quot;, and so on.&lt;br /&gt;
&lt;br /&gt;
== Context Markers ==&lt;br /&gt;
&lt;br /&gt;
Context marker consist of the semantic role and the interface subcue, in the form of &amp;lt;tt&amp;gt;@role:subcue&amp;lt;/tt&amp;gt;. Each message should be given a role, but the subcue may be left out. The subcue should be given only when the string clearly maps to the user interface element that it describes.&lt;br /&gt;
&lt;br /&gt;
Every role/subcue combination determines the default visual formatting of resulting string, whether it comes out as plain or rich text. See the section on [[#Limitations to Semantic Markup|limitations]] for a way to override the default formatting when necessary.&lt;br /&gt;
&lt;br /&gt;
{{warning|Roles and subcues in the context marker cannot be specified at will, but must be drawn from the sets defined below. This is important for several reasons, one being that translators have deliberated about and agreed upon the meanings of presented sets, rather than having to second-guess arbitrary combinations.}}&lt;br /&gt;
&lt;br /&gt;
KUIT defines the following roles and subcues (with notes on default visual formatting):&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;@action&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Text to all clickable widgets that cause some action to be performed, like an operation on the data, view restructuring, or opening a dialog. The button texts and menu entries (except submenu titles) all fall into this category.&lt;br /&gt;
:&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:button&amp;lt;/tt&amp;gt; - pushbuttons in windows and dialogs&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:inmenu&amp;lt;/tt&amp;gt; - menu entries that perform an action&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:intoolbar&amp;lt;/tt&amp;gt; - toolbar buttons&lt;br /&gt;
:&lt;br /&gt;
: All &amp;lt;tt&amp;gt;@action&amp;lt;/tt&amp;gt; markers are formatted as '''plain text''' by default.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;@title&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Text that is semantically a title in the interface. These would include window titles, menu titles, tab names, option group names in configuration dialogs, and column and row names in list views.&lt;br /&gt;
:&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:window&amp;lt;/tt&amp;gt; - window title (also dock name)&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:menu&amp;lt;/tt&amp;gt; - menu name&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:tab&amp;lt;/tt&amp;gt; - tab name&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:group&amp;lt;/tt&amp;gt; - option group&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:column&amp;lt;/tt&amp;gt; - column name&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:row&amp;lt;/tt&amp;gt; - row name&lt;br /&gt;
:&lt;br /&gt;
: All &amp;lt;tt&amp;gt;@title&amp;lt;/tt&amp;gt; markers are formatted as '''plain text''' by default.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;@option&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Text to options which user can turn on and off, or choose between. These are the labels to checkboxes (either in dialogs or in menus) and radio buttons.&lt;br /&gt;
:&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:check&amp;lt;/tt&amp;gt; - checkbox label&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:radio&amp;lt;/tt&amp;gt; - radio-button label&lt;br /&gt;
:&lt;br /&gt;
: All &amp;lt;tt&amp;gt;@option&amp;lt;/tt&amp;gt; markers are formatted as '''plain text''' by default.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;@label&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Text labels to various widgets in the interface, which are none of &amp;lt;tt&amp;gt;@action&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;@title&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;@option&amp;lt;/tt&amp;gt;. These include labels to sliders, spinboxes, combo, list and text boxes, font and color choosers.&lt;br /&gt;
:&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:slider&amp;lt;/tt&amp;gt; - slider labels (but end-ranges are @item:inrange!)&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:spinbox&amp;lt;/tt&amp;gt; - spinbox labels&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:listbox&amp;lt;/tt&amp;gt; - list and combo boxes&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:textbox&amp;lt;/tt&amp;gt; - text and edit boxes&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:chooser&amp;lt;/tt&amp;gt; - chooser widgets (fonts, colors, etc.)&lt;br /&gt;
:&lt;br /&gt;
: All &amp;lt;tt&amp;gt;@label&amp;lt;/tt&amp;gt; markers are formatted as '''plain text''' by default.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;@item&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Strings that can be considered one from a range of possibilities or properties. Entries in listings, dropdown and combo boxes are obvious, but also some menu items (e.g. encoding selection, sort orderings), end-labels to ranges (e.g. high/low, more/less), inserts into longer texts, and properites (e.g. file types, permissions) frequently displayed in tabular form (e.g. column views, property dialogs).&lt;br /&gt;
:&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:inmenu&amp;lt;/tt&amp;gt; - items presented as menu entries&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:inlistbox&amp;lt;/tt&amp;gt; - items in list and combo boxes&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:intable&amp;lt;/tt&amp;gt; - items presented in table-like forms&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:inrange&amp;lt;/tt&amp;gt; - range labels to sliders, etc.&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:intext&amp;lt;/tt&amp;gt; - words and phrases inserted into other messages&lt;br /&gt;
:&lt;br /&gt;
: All &amp;lt;tt&amp;gt;@item&amp;lt;/tt&amp;gt; markers are formatted as '''plain text''' by default.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;@info&amp;lt;/tt&amp;gt;&lt;br /&gt;
: General texts for user's information, that do not fall under any of the previous roles. These are for example tooltip and &amp;quot;What's This?&amp;quot; texts, text in message boxes, fields in status bar, and strings in progress dialogs.&lt;br /&gt;
:&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:tooltip&amp;lt;/tt&amp;gt; - hovering tooltips&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:whatsthis&amp;lt;/tt&amp;gt; - &amp;quot;What's This?&amp;quot; explanations of widgets&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:status&amp;lt;/tt&amp;gt; - texts in status displays (e.g. in status bar)&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:progress&amp;lt;/tt&amp;gt; - the current state of ongoing process&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:tipoftheday&amp;lt;/tt&amp;gt; - introductory tips on application startup&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:credit&amp;lt;/tt&amp;gt; - contributor names and their contributions&lt;br /&gt;
:: &amp;lt;tt&amp;gt;:shell&amp;lt;/tt&amp;gt; - info output to the terminal, rather than to GUI&lt;br /&gt;
:&lt;br /&gt;
: Standalone &amp;lt;tt&amp;gt;@info&amp;lt;/tt&amp;gt;, without a subcue, is formatted as '''rich text''' by default; the same holds for &amp;lt;tt&amp;gt;:tooltip&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;:whatsthis&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;:tipoftheday&amp;lt;/tt&amp;gt; subcues. With &amp;lt;tt&amp;gt;:status&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;:progress&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;:credit&amp;lt;/tt&amp;gt;, '''plain text''' is produced. &amp;lt;tt&amp;gt;:shell&amp;lt;/tt&amp;gt; produces '''terminal text''' (like plain, but with possible shell escape sequences).&lt;br /&gt;
&lt;br /&gt;
== Semantic Tags ==&lt;br /&gt;
&lt;br /&gt;
KUIT semantic tags come in several logical groups:&lt;br /&gt;
* ''phrase tags'' - those that ascribe meaning to certain phrases and inserts&lt;br /&gt;
* ''sentence tags'' - which describe the purpose of a complete sentence in text&lt;br /&gt;
* ''structure tags'' - used to order longer text into paragraphs, titles, etc.&lt;br /&gt;
&lt;br /&gt;
=== Phrase tags ===&lt;br /&gt;
&lt;br /&gt;
Phrase tags will by default not admit any subtags; where some subtags can be used, it is so indicated. KUIT defines the folowing phrase tags:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;application&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Name of an application.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@action:inmenu&amp;quot;,&lt;br /&gt;
      &amp;quot;Open with &amp;lt;application&amp;gt;%1&amp;lt;/application&amp;gt;&amp;quot;, appName);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;bcode&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Line-breaking body of code, for short listings.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info:whatsthis&amp;quot;,&lt;br /&gt;
      &amp;quot;You can try the following snippet:&amp;lt;bcode&amp;gt;&amp;quot;&lt;br /&gt;
      &amp;quot;\\begin{equation}&amp;quot;&lt;br /&gt;
      &amp;quot;  C_{x_i} = \\frac{C_z^2}{e \\pi \\lambda}&amp;quot;&lt;br /&gt;
      &amp;quot;\\end{equation}&amp;quot;&lt;br /&gt;
      &amp;quot;&amp;lt;/bcode&amp;gt;&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;command&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Name of shell command or system call. Its man section can be provided via &amp;lt;tt&amp;gt;section&amp;lt;/tt&amp;gt; attribute.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;This will call &amp;lt;command&amp;gt;%1&amp;lt;/command&amp;gt; internally.&amp;quot;, cmdName);&lt;br /&gt;
&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;Consult man entry for &amp;lt;command section='1'&amp;gt;%1&amp;lt;/command&amp;gt;&amp;quot;, cmdName);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;email&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Email address. Without attributes, the tag text is the address. Address can also be given with &amp;lt;tt&amp;gt;address&amp;lt;/tt&amp;gt; attribute, in which case the tag text is the name or description attached to the address.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;Send bug reports to &amp;lt;email&amp;gt;%1&amp;lt;/email&amp;gt;.&amp;quot;, emailNull);&lt;br /&gt;
&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;Send praises to &amp;lt;email address='%1'&amp;gt;the author&amp;lt;/email&amp;gt;.&amp;quot;, emailMy);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
: The construct will be hyperlinked in rich text format.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;emphasis&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Emphasize a word or phrase in the text.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info:progress&amp;quot;,&lt;br /&gt;
      &amp;quot;Checking &amp;lt;emphasis&amp;gt;feedback&amp;lt;/emphasis&amp;gt; circuits...&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
:  For strong emphasis, attribute &amp;lt;tt&amp;gt;strong&amp;lt;/tt&amp;gt; (since KDE 4.3) may be used, with value &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;yes&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;envar&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Environment variable. The $ sign will be prepended automatically in formatted text.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;Assure that your &amp;lt;envar&amp;gt;PATH&amp;lt;/envar&amp;gt; is properly set.&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;filename&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: File or folder name or path. The path separators will be transformed into what is native to the platform.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;, &amp;quot;Cannot read &amp;lt;filename&amp;gt;%1&amp;lt;/filename&amp;gt;.&amp;quot;, filename);&lt;br /&gt;
&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;&amp;lt;filename&amp;gt;&amp;lt;envar&amp;gt;HOME&amp;lt;/envar&amp;gt;/.foorc&amp;lt;/filename&amp;gt; does not exist.&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
: The &amp;lt;tt&amp;gt;&amp;lt;envar&amp;gt;&amp;lt;/tt&amp;gt; can be used as subtag.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;icode&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Inline code, like shell command lines.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info:tooltip&amp;quot;,&lt;br /&gt;
      &amp;quot;Execute &amp;lt;icode&amp;gt;svn merge&amp;lt;/icode&amp;gt; on selected revisions.&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
: The &amp;lt;tt&amp;gt;&amp;lt;placeholder&amp;gt;&amp;lt;/tt&amp;gt; can be used as subtag.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;interface&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Path to GUI interface element. If there is more than one element in the path, use &amp;quot;|&amp;quot; or &amp;quot;-&amp;gt;&amp;quot; to delimit elements, which will be converted into canonical delimiter.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info:whatsthis&amp;quot;,&lt;br /&gt;
      &amp;quot;If you make a mistake, click &amp;quot;&lt;br /&gt;
      &amp;quot;&amp;lt;interface&amp;gt;Reset&amp;lt;/interface&amp;gt; to start again.&amp;quot;);&lt;br /&gt;
i18nc(&amp;quot;@info:whatsthis&amp;quot;,&lt;br /&gt;
      &amp;quot;The line colors can be changed under &amp;quot;&lt;br /&gt;
      &amp;quot;&amp;lt;interface&amp;gt;Settings-&amp;gt;Visuals&amp;lt;/interface&amp;gt;.&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;link&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Link to a URL-addressable resource. Without attributes, the tag text is the URL; alternatively, the URL can be given by &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; attribute, and then the tag text serves as description.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info:tooltip&amp;quot;,&lt;br /&gt;
      &amp;quot;Go to &amp;lt;link&amp;gt;%1&amp;lt;/link&amp;gt; website.&amp;quot;, urlKDE);&lt;br /&gt;
&lt;br /&gt;
i18nc(&amp;quot;@info:tooltip&amp;quot;,&lt;br /&gt;
      &amp;quot;Go to &amp;lt;link url='%1'&amp;gt;the KDE website&amp;lt;/link&amp;gt;.&amp;quot;, urlKDE);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
: The variant with URL/description separation is preferred when applicable. The construct will be hyperlinked in rich text format.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;message&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: An external message to be reported to the user.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;The fortune cookie says: &amp;lt;message&amp;gt;%1&amp;lt;/message&amp;gt;&amp;quot;, trouble);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;nl&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Line break, counterpart to HTML's &amp;lt;tt&amp;gt;&amp;amp;lt;br/&amp;amp;gt;&amp;lt;/tt&amp;gt;. In plain text it will format as a newline character, and in rich text as &amp;lt;tt&amp;gt;&amp;amp;lt;br/&amp;amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;Do you really want to delete:&amp;lt;nl/&amp;gt;&amp;quot;&lt;br /&gt;
      &amp;quot;&amp;lt;filename&amp;gt;%1&amp;lt;/filename&amp;gt;&amp;quot;, fileName);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;numid&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: By default, numbers supplied as arguments to i18n calls are formatted into localized form. If the number is supposed to be a numeric identifier instead, like a port number, use this tag to signal numeric-id environment.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info:progress&amp;quot;,&lt;br /&gt;
      &amp;quot;Connecting to &amp;lt;numid&amp;gt;%1&amp;lt;/numid&amp;gt;...&amp;quot;, portNo);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;placeholder&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A placeholder text, either something to be replaced by the user, or a generic item in a list.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;Replace &amp;lt;placeholder&amp;gt;name&amp;lt;/placeholder&amp;gt; with your name.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
i18nc(&amp;quot;@item:inlistbox&amp;quot;,&lt;br /&gt;
      &amp;quot;&amp;lt;placeholder&amp;gt;All images&amp;lt;/placeholder&amp;gt;&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;resource&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: General named resource. Names of documents, sessions, projects, toolbars, plugins, schemes and themes, accounts, etc.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;, &amp;quot;Apply color scheme &amp;lt;resource&amp;gt;%1&amp;lt;/resource&amp;gt;?&amp;quot;, colScheme);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;shortcut&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Combination of keys to press. Separate the keys by &amp;quot;+&amp;quot; or &amp;quot;-&amp;quot;, and the shortcut will be converted into canonical form.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info:whatsthis&amp;quot;,&lt;br /&gt;
      &amp;quot;Cycle through layouts using &amp;lt;shortcut&amp;gt;Alt+Space&amp;lt;/shortcut&amp;gt;.&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sentence tags ===&lt;br /&gt;
&lt;br /&gt;
Sentence tags mark complete sentences in text, and will admit any phrase tags as subtags. The following are defined:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;note&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The sentence is a side note of significance to the topic.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;Probably the best known of all duck species is the Mallard. &amp;quot;&lt;br /&gt;
      &amp;quot;It breeds throughout the temperate areas around the world. &amp;quot;&lt;br /&gt;
      &amp;quot;&amp;lt;note&amp;gt;Most domestic ducks are derived from Mallard.&amp;lt;/note&amp;gt;&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
: Do not explicitly add &amp;quot;Note:&amp;quot;, it will be added automatically. If you really need other label than &amp;quot;Note&amp;quot;, use attribute &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;, e.g. &amp;lt;tt&amp;gt;&amp;quot;&amp;lt;note label='Trivia'&amp;gt;...&amp;lt;/note&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;warning&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The sentence is a warning.&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;Really delete this key?&amp;quot;&lt;br /&gt;
      &amp;quot;&amp;lt;warning&amp;gt;This cannot be undone.&amp;lt;/warning&amp;gt;&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
: Do not explicitly add &amp;quot;Warning:&amp;quot;, it will be added automatically. If you really need other label than &amp;quot;Warning&amp;quot;, use attribute &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;, e.g. &amp;lt;tt&amp;gt;&amp;quot;&amp;lt;warning label='Danger'&amp;gt;...&amp;lt;/warning&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Structure tags ===&lt;br /&gt;
&lt;br /&gt;
Structure tags are used to split longer texts into titles, paragraphs, and lists. By default they can contain any phrase or sentence tags, unless indicated otherwise.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;para&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Text paragraph.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;title&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The title of the text. Must be the first tag if present, but can be omitted.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;subtitle&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Subtitle in the text. Must be followed by at least one &amp;lt;tt&amp;gt;&amp;amp;lt;para&amp;amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;list&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: List of items. Can contain only &amp;lt;tt&amp;gt;&amp;amp;lt;item&amp;amp;gt;&amp;lt;/tt&amp;gt; as subtags. List is considered an element of the paragraph, so the &amp;lt;tt&amp;gt;&amp;amp;lt;list&amp;amp;gt;&amp;lt;/tt&amp;gt; must be found inside &amp;lt;tt&amp;gt;&amp;amp;lt;para&amp;amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;tt&amp;gt;&amp;amp;lt;item&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: List item.&lt;br /&gt;
&lt;br /&gt;
If any of the structure tags is present, then there must be no text outside of structure tags. The following is not valid KUIT markup:&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
// invalid markup&lt;br /&gt;
i18nc(&amp;quot;@info&amp;quot;,&lt;br /&gt;
      &amp;quot;&amp;lt;title&amp;gt;History Sidebar&amp;lt;/title&amp;gt;&amp;quot;&lt;br /&gt;
      &amp;quot;You can configure the history sidebar here.&amp;quot;); // &amp;lt;para&amp;gt; missing&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Limitations to Semantic Markup ==&lt;br /&gt;
&lt;br /&gt;
Semantic markup cannot be used in &amp;quot;dumb&amp;quot; strings, which do not pass through KDE's i18n subsystem. These would be, for example, strings in &amp;lt;tt&amp;gt;.desktop&amp;lt;/tt&amp;gt; format files. But ''not'' the strings in UI files, as in Qt Designer they can be equipped with both context markers (via comment field to text properties) and semantic tags.&lt;br /&gt;
&lt;br /&gt;
Qt's rich text HTML tags can be used concurrently with KUIT tags, but this is not advised unless necessary. They may be needed, for example, to create tables or insert images, as KUIT does not implement this functionality at the moment.&lt;br /&gt;
&lt;br /&gt;
Sometimes, the visual formatting may not be quite appropriate for the output device; every role/subcue combination has a preset default formatting. For example, if the &amp;lt;tt&amp;gt;@info&amp;lt;/tt&amp;gt; role is applied to a string which is used in a widget that does not handle rich text, it will come out with HTML tags displayed verbatim. To handle this, visual formatting can be explicitly signaled by &amp;lt;tt&amp;gt;/''format''&amp;lt;/tt&amp;gt; modifier appended to context marker:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code cpp&amp;gt;&lt;br /&gt;
i18nc(&amp;quot;@info/plain&amp;quot;,&lt;br /&gt;
      &amp;quot;&amp;lt;filename&amp;gt;%1&amp;lt;/filename&amp;gt; does not exist&amp;quot;, fname);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Presently, the possible format modifiers are &amp;lt;tt&amp;gt;/plain&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/rich&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;/term&amp;lt;/tt&amp;gt; (for terminal format, possible use of escape sequences).&lt;br /&gt;
&lt;br /&gt;
To specify context in kpartgui rc file use context attribute (&amp;lt;text context=&amp;quot;@title:menu&amp;quot;&amp;gt;File&amp;lt;/text&amp;gt;). A context-aware version of I18N_NOOP is I18N_NOOP2.&lt;br /&gt;
&lt;br /&gt;
== Should I Go For Semantic Markup? ==&lt;br /&gt;
&lt;br /&gt;
Admittedly, KUIT markup is an additional thing to be learned and applied throughout the course of development. By now you may be wondering if it is worthwile to invest time into that, particularly in view of two cases:&lt;br /&gt;
* starting work on a new application, and&lt;br /&gt;
* porting messages in existing applications.&lt;br /&gt;
&lt;br /&gt;
You are strongly advised to use KUIT for new code. Compared to the total time spent on code, writing UI messages is only a small fraction. Context markers will help translators a lot, and message tags will provide consistent visual text formatting to your application.&lt;br /&gt;
&lt;br /&gt;
When modifying existing code, there are two issues. First, obviously it is a daunting task to go through hundreds (or worse) of messages and equip them with semantic markup. Second, by changing the messages, the translators too will have to review their existing translations; however, it is not expected that the porting will take so &amp;quot;epic&amp;quot; proportions that the translators cannot keep up. Sumarily, feel free to do as you see fit.&lt;br /&gt;
&lt;br /&gt;
Additionally, for porting, keep in mind that it is not all-or-nothing proposal. Any amount of semantic messages are useful to translators, and users can only see the difference for the better. Thus, for example, deciding to make all ''new'' messages semantic and slowly over time fix old messages, is a perfectly fine strategy.&lt;br /&gt;
&lt;br /&gt;
To make your job easier, there is an i18n-checker script that will report the problems in KUIT markup, as well as check some other i18n nuances. It is run daily on KDE code repository-wide as part Krazy-framework, but you can also run it locally on your code. It can be found in {{path|trunk/quality/krazy2/plugins/general/i18ncheckarg}}. Furthermore, as of this moment Krazy checks only C++ sources, while when you run the script locally, some of the XML sources containing translatable strings will be checked as well. &amp;lt;tt&amp;gt;i18ncheckarg&amp;lt;/tt&amp;gt; requires Perl libxml bindings, which are probably already packaged for your distribution (Debian package is libxml-libxml-perl).&lt;br /&gt;
&lt;br /&gt;
{{note|By default &amp;lt;tt&amp;gt;i18ncheckarg&amp;lt;/tt&amp;gt; takes a single filename to check, but using &amp;lt;tt&amp;gt;--allsources&amp;lt;/tt&amp;gt; option you can provide as many file or directory paths as you wish; typically you would give top directory path to your sources. Also, to report all missing context markers use &amp;lt;tt&amp;gt;--ctxmark&amp;lt;/tt&amp;gt; option, or otherwise missing markers will be reported only if some threshold of marked-to-total number of messages in a file is reached.}}&lt;br /&gt;
&lt;br /&gt;
Last but not the least, there is also a chic-effect to the KUIT. Its wide use, together with some under-the-hood elements on translators' disposal, will make KDE4's i18n layer without peer in free or proprietary software world. Insofar as you consider localization excellence an important part of the overall KDE excellence, this is something that may also tip your decision :) -- Your Friendly Translator.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-05-29T10:51:18Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Corrected note on -C option. Mentioned removal of previous fields.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading'', ''approving''), each of which may return the translation to a previous stage, or forward it to some special stage. The process can also be more finer grained, where each message in the file goes through stages separately.&lt;br /&gt;
&lt;br /&gt;
Regardless of the particularities, workflows of this kind all have the following in common. Members of the translation team are assigned ''roles'' -- such as ''translator'', ''reviewer'', ''approver'', ''committer'' -- by which they enter into the workflow (single person can have more roles). The later review stages must wait for the earlier stages to complete, and the translation cannot be updated again before the current version clears the pipeline (or the pipeline is aborted). Most importantly, once the translation is committed, it becomes part of simply &amp;quot;admitted&amp;quot; translations, with no further qualifiers.&lt;br /&gt;
&lt;br /&gt;
The system of prescribed roles requires that team members assign them between themselves, stick to them, and shuffle them along the way. The prescribed review pipeline requires a tool to enforce and keep track of the stages in which translations are. This makes the review workflow complex and rigid, most probably with choke points for efficiency. Distribution of roles may become disbalanced by people coming and going, or the workflow tool may be prohibitive to some scenarios (e.g. single translator making small adjustments in dozens of files across the project, but having to upload each manually through a web interface).&lt;br /&gt;
&lt;br /&gt;
Of course, &amp;quot;rigid&amp;quot;, &amp;quot;complex&amp;quot;, &amp;quot;inefficient&amp;quot;, are comparative qualifications, so what is it that the classical review by stages can be compared to in this way?&lt;br /&gt;
&lt;br /&gt;
== Reviewing by Ascriptions ==&lt;br /&gt;
&lt;br /&gt;
Reviewing by ascriptions is even simpler conceptually, and yet less rigid, less complex, and much more efficient than the review by stages. It works on the message-level, rather than file-level. Anyone can simply translate some messages and directly commit modified files, without any review, but with ''ascribing'' modifications to own name. Anyone can review any committed messages at any moment, commit the modifications-on-review and ascribe reviews to own name and (possibly) to certain class -- full review, review of context, of terminology, of style, etc. Only when the translation is to be shipped to end users, the ''insufficiently'' reviewed messages are automatically omitted from the package, by evaluating the ''ascription history'' of each message.&lt;br /&gt;
&lt;br /&gt;
Most importantly, based on the ascription history, the reviewer can select only some particular messages, and review only the difference between their historical and current versions. For example, Alice can select to review only messages modified since she or Bob had last reviewed them for style; she could see the difference from that last review to current version, e.g. if in the whole paragraph only a single word has changed by Charlie when he reviewed the terminology. In terms of PO workflow, the ascription history propagates through merges, so the reviewer can compare the change in original and the change in translation since the last review, to judge if one fits the other.&lt;br /&gt;
&lt;br /&gt;
Since everyone just commits, translations can be efficiently kept in a version control repository, with the ascription system added on top. After having done some translating, the team member simply substitutes commit command of the version control system (VCS) with ascribe-modifications command of the ascription system (AS, which calls the underlying VCS internally). After reviewing, the team member uses ascribe-reviews command of the AS to commit reviews to ascription history (as well as modifications made during the review). To select messages for review, the team member issues diff-for-review command of the AS (with suitable parameters to narrow the set) and selected messages are marked in-place in PO files and [[Localization/Tools/Pology/PO_Embedded_Diffing|embedded with differences]], and possibly popped open in a PO editor.&lt;br /&gt;
&lt;br /&gt;
When the translations are to be released, the team coordinator issues filter-for-release command of the AS, which takes the working PO files and creates final PO files with insufficiently reviewed messages removed. &amp;quot;Release time&amp;quot; is used here only figuratively: this should be a fully automatic process, so it can be performed at any interval of convenience.&lt;br /&gt;
&lt;br /&gt;
What constitutes &amp;quot;sufficient review&amp;quot; can be defined in fine detail. It could be specified that messages modified by Alice need to have only review for terminology, but not necessarily for style; Charlie may belong to the group which needs to be reviewed on style, but not necessarily on context; Bob's reviews for style may be nice to have, but never blocking if missing. These decisions do not preclude released messages to be reviewed later on missing points, after higher priority reviews have been completed. The definition of sufficiency may be changed at any point, e.g. as team members get more experienced and require less review, without interfering with direct translation and review work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- (Here is one unorthodox possibility of using reviews by ascriptions. A random translator may want to keep an eye on what the reviewers change in the files he maintains. For example, to learn what are typical small errors that he makes while translating. Therefore, he himself reviews any modifications not made by him after his last review, and commits them. This will in no way interfere with &amp;quot;canonical&amp;quot; reviews, those considered at release time.) //--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In summary, with reviewing by ascriptions the lean efficiency of raw VCS operation is preserved while providing for great flexibility of review. All team members can be given commit access, no web or email detours are needed. There are no prescribed roles, but an equivalent of role assignment happens automatically at last possible moment, and can take into account both translators' and reviewers' abilities. There is no staging between completing and committing the translation, which enables translator to keep on polishing the translation undisturbed until the reviewer comes around. There is no inefficiency in handling small changes throughout many files, since single AS command commits all changes just as single VCS command would. AS in effect abstracts VCS, so general team members do not have to know the particularities of the underlying VCS. On commit operations, AS can also apply checks (e.g. decline to commit syntactically invalid PO files) and modifications (e.g. update translator's data in the PO header).&lt;br /&gt;
&lt;br /&gt;
== Ascription System in Pology ==&lt;br /&gt;
&lt;br /&gt;
[[Localization/Tools/Pology|Pology]] is a collection of various modular tools for supporting translation based on PO files. Among them is the script &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which implements an ascription system (AS); at present, it can use Subversion or Git as the underlying VCS. &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is still in experimental stage, so what follows is a brief description of how to use it in context of the KDE translation project. However, very little is truly specific to KDE; the only major assumption is that there exists a VCS repository with PO files of a given language grouped together, and that the translation team can use it without special restrictions.&lt;br /&gt;
&lt;br /&gt;
Very important for the AS is how branches are handled (in KDE, the rolling trunk and stable branches). AS can in principle be deployed by branch, but then there is the added complexity of porting translations between branches, which ascriptions should follow. Therefore, the AS implemented by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is currently limited to assumption that there is a single branch of translations at all times. The article [[Localization/Workflows/PO_Summit|&amp;quot;Translating in Summit&amp;quot;]] explains how a KDE translation team can set up and operate such a single branch, the summit, and this is the prerequisite for the following instructions. (Note that the summit system is useful on its own, and should be conductive to any kind of review workflow.)&lt;br /&gt;
&lt;br /&gt;
== Setting Up ==&lt;br /&gt;
&lt;br /&gt;
The summit branch for the language &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt; is positioned like this in the KDE repository:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            LANG/&lt;br /&gt;
                summit/&lt;br /&gt;
                    messages/&lt;br /&gt;
                    docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The team coordinator already has this part of the repository tree locally due to regular summit operations. For the same reason Pology is already set up. Setting up the ascription system is now simple. The file &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; is created in the root of the summit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# ---------------------------&lt;br /&gt;
# Global ascription settings.&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
&lt;br /&gt;
# The root of the ascription catalog tree.&lt;br /&gt;
ascript-root = ../summit-ascript&lt;br /&gt;
&lt;br /&gt;
# The underlying version control system.&lt;br /&gt;
version-control = svn&lt;br /&gt;
&lt;br /&gt;
# Data for updating catalog headers.&lt;br /&gt;
# - language code&lt;br /&gt;
language = LANG&lt;br /&gt;
# - full language name&lt;br /&gt;
language-team = LANGUAGE&lt;br /&gt;
# - email address of the team&lt;br /&gt;
team-email = kde-i18n-LANG@kde.org&lt;br /&gt;
&lt;br /&gt;
# Default commit message.&lt;br /&gt;
commit-message = Translation updates.&lt;br /&gt;
&lt;br /&gt;
# -----------------------&lt;br /&gt;
# Registered translators.&lt;br /&gt;
&lt;br /&gt;
[user-alice]&lt;br /&gt;
name = Alice Akmalryn&lt;br /&gt;
original-name = Алиса Акмалрин&lt;br /&gt;
email = alice.akmalryn@someplacenice.org&lt;br /&gt;
&lt;br /&gt;
[user-bob]&lt;br /&gt;
name = Bob Byomkin&lt;br /&gt;
original-name = Бобан Бјомкин&lt;br /&gt;
email = bob.byomkin@otherplacenice.org&lt;br /&gt;
&lt;br /&gt;
# ...and so on.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;ascript-root&amp;lt;/tt&amp;gt; setting should be exactly &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt;, for the reason mentioned later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit-message&amp;lt;/tt&amp;gt; field, if defined, allows team members to commit without providing a commit message. The value given by this field will be used by default, with translator's user name appended to the end in special syntax. For example: &amp;lt;tt&amp;gt;Translation updates. [&amp;gt;alice]&amp;lt;/tt&amp;gt;. (Translator's user name is also appended to manually supplied commit messages.) Translators can still supply a commit message when they wish, as shown later. If this field is not set, the commit message is supplied as usual on committing.&lt;br /&gt;
&lt;br /&gt;
* Team members are defined by &amp;lt;tt&amp;gt;[user-USERNAME]&amp;lt;/tt&amp;gt; sections. Ascription user names can be any valid ASCII identifier: ASCII letters, digits and underscores only, digit cannot be the first character. Ascription user names have no technical relation to the underlying VCS accounts, though it is mnemonically convenient if they are the same (in case of SVN). This means that a translator who does not have a VCS account (yet) can and should be added here, with assigned user name (best one suitable as SVN account name later); why this should be done will be explained later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field in user sections is there in case the preferred renderings of the name in English and in target language are not the same. When this is not the case, &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; can be omitted.&lt;br /&gt;
&lt;br /&gt;
As soon as the &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; file is committed, the ascription system is ready for operation. Only regular modifications to this file are those of adding new team members. (On the other hand, team members should never be removed, because even after they no longer contribute, their ascription records remain in the system.)&lt;br /&gt;
&lt;br /&gt;
=== Initial Ascription ===&lt;br /&gt;
&lt;br /&gt;
The most common situation at start of ascription workflow is that there already exists a body of translations, contributed to by many different people over time. The coordinator should ascribe all existing translations as initial modifications, but to whom? It cannot be said precisely who translated what. The solution is to introduce a generic user in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;, suitably known as &amp;quot;Unknown Hero&amp;quot; (or &amp;quot;Lost Translator&amp;quot;, you can be inventive):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[user-uhero]&lt;br /&gt;
name = Unknown Hero&lt;br /&gt;
original-name = Незнани јунак&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ascribe all existing translations as modified and reviewed by this user. The coordinator does this with the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe commit -u uhero --all-reviewed -C LANG/summit/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; is the ascription mode, and the &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option provides the user name to which ascriptions are made. This is an important point: ascriptions are made to a user defined in ascription configuration, and have nothing to do with VCS accounts; someone who has the account can commit in the name of someone who does not. It is the &amp;lt;tt&amp;gt;--all-reviewed&amp;lt;/tt&amp;gt; option that declares all messages to be reviewed as well (note that it is normally used only this once, and not for normal day to day reviewing). The &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option prevents automatic adding and committing to version control, which is useful for this initial step. Finally the paths which contain all summit catalogs are given.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command is issued, a progress bar will appear, and the following output will start to unfold:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
LANG/summit/messages/extragear-base/rellinks.po  (50/50)&lt;br /&gt;
LANG/summit/messages/extragear-base/autorefresh.po  (13/13)&lt;br /&gt;
LANG/summit/messages/extragear-base/babelfish.po  (38/38)&lt;br /&gt;
...&lt;br /&gt;
LANG/summit/messages/qt/libphonon.po  (13/13)&lt;br /&gt;
LANG/summit/messages/qt/phonon-xine.po  (24/24)&lt;br /&gt;
LANG/summit/messages/qt/phonon_gstreamer.po  (12/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated    111775    111775&lt;br /&gt;
fuzzy          26943     26943&lt;br /&gt;
obsolete/t      2965      2965&lt;br /&gt;
obsolete/f      1626      1626&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number in parenthesis indicates how many messages have been ascribed in the given PO file (modified/reviewed), and at the end the totals are given. Ascribing the complete summit for the first time will take quite some time (on the order of 10-20 minutes).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--If, on the contrary, it is known who translated and reviewed what, ascription can be performed piece-wise with user names of real translators:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support/LANG/summit&lt;br /&gt;
$ poascribe commit -u alice --all-reviewed -C kdelibs/ kdepimlibs/ kdebase/&lt;br /&gt;
$ poascribe commit -u bob --all-reviewed -C kdemultimedia/ kdeutils/&lt;br /&gt;
$ ...&lt;br /&gt;
&amp;lt;/code&amp;gt;//--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the initial ascription has been made, the ascription tree will appear next to the summit tree. This tree will contain one ascription PO file for each summit PO file, with the same name and relative location within the tree:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
        summit-ascript/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During the ascription some summit PO files may have been modified as well, in that any previous fields (&amp;lt;tt&amp;gt;#| ...&amp;lt;/tt&amp;gt;) on translated messages have been removed. (These fields are sometimes erroneously left in by older PO editors.)&lt;br /&gt;
&lt;br /&gt;
The newly created ascription tree (and any modifications to summit tree) can now be committed as usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn add LANG/summit-ascript&lt;br /&gt;
$ svn commit LANG/summit LANG/summit-ascript -m &amp;quot;Initial ascription.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Translators ==&lt;br /&gt;
&lt;br /&gt;
Team members other than the coordinator, whether translators or reviewers, need to keep around only the &amp;lt;tt&amp;gt;trunk/l10n-support/LANG/&amp;lt;/tt&amp;gt; directory. But they always need to update this directory fully (rather than just one particular module or file under &amp;lt;tt&amp;gt;.../*messages/&amp;lt;/tt&amp;gt;), so that the summit tree and the ascription tree (and configuration) are kept in sync.&lt;br /&gt;
&lt;br /&gt;
In order not to have to issue their own user name (&amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;) all the time, translators can set it in Pology user configuration &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, in &amp;lt;tt&amp;gt;[poascribe]&amp;lt;/tt&amp;gt; section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = alice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translators can then submit updated PO files simply by substituting &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt; (or whatever the VCS commit command is) with &amp;lt;tt&amp;gt;poascribe commit&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;co&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;ci&amp;lt;/tt&amp;gt; for short):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdefoo/*fooapp*.po&lt;br /&gt;
LANG/summit/messages/kdefoo/fooapp.po  (144)&lt;br /&gt;
LANG/summit/messages/kdefoo/libfooapp.po  (25)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified&lt;br /&gt;
translated       169&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; VCS is committing catalogs:&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/libfooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/libfooapp.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1267069.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will add ascription records into ascription catalogs corresponding to summit catalogs to be committed, and commit them all. Like &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt; can take any number of file or directory paths, and can be issued from any working directory (it will always find ascription catalogs). If default commit message has not been set in the ascription configuration, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will ask for it; or it can be given in command line through &amp;lt;tt&amp;gt;-m&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
=== Translators Without Commit Access ===&lt;br /&gt;
&lt;br /&gt;
With the ascription system in place, every regular team member should have commit access. But, there may be some period of time before new translators are given accounts, revision control may be too technical for some, and even those with the account may not be able to commit temporarily for some reason.&lt;br /&gt;
&lt;br /&gt;
These translators may send in their work by email, to ''any'' team member with commit access (not necessarily the coordinator or a reviewer); this team member can commit received files without any review, as review can be conducted at any later time. If Bob sends some files to Alice, she can commit them immediately by stating Bob's user name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -u bob ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, the translator who sent in the files has to be defined in the ascription configuration. There are no hidden costs or security issues to this (as opposed to opening a VCS account), so every new translator should be defined there before any work of that person is committed.&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Reviewers ==&lt;br /&gt;
&lt;br /&gt;
The ascription system opens up all sorts of possibilities for concrete review patterns. Reviewers should keep in mind that for each message the full modification and review history is available, so that the team can think about how to make good use of it. Therefore, what follows are some examples to illustrate the review facilities that &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; provides.&lt;br /&gt;
&lt;br /&gt;
=== Basic Reviewing ===&lt;br /&gt;
&lt;br /&gt;
At the very basic level (which is the only level in classical review by stages), messages can be classified into simply unreviewed and reviewed, without further qualifiers. Alice now wants to review all unreviewed messages in a group of PO files, say &amp;lt;tt&amp;gt;kdetoys&amp;lt;/tt&amp;gt; module. She issues (&amp;lt;tt&amp;gt;di&amp;lt;/tt&amp;gt; is short for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe di LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===== Diffed for review: 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unreviewed messages have now been marked and diffed, inside the listed PO files. What is this about &amp;quot;diffing&amp;quot;? If the files had already been reviewed before, some of the messages modified since then (those marked for review) may have changed very little (e.g. a few words in a paragraph-length message, or even just punctuation). Therefore, for each message marked for review, Alice also wants to see the diff since last review to current version. Here are two messages in typical review states added by &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: charlie:m&lt;br /&gt;
#: gui/mainwindow.cc:372&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;GAME OVER. {-You won-}{+Tie+}!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KRAJ IGRE. {-Pobeda-}{+Nerešeno+}!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: bob:m charlie:m&lt;br /&gt;
#: game-state.cpp:117&lt;br /&gt;
#, ediff-total&lt;br /&gt;
msgid &amp;quot;Click the pause button again to resume the game.&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Kliknite ponovo na dugme pauze da nastavite igru.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the first one in Kate:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_poascribe_diff_01.png|center|Message diffed for review by poascribe in Kate.]]&lt;br /&gt;
&lt;br /&gt;
In the first message, the first to note is the &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment. This comment succinctly lists who did what with the message since the last review; here &amp;lt;tt&amp;gt;charlie:m&amp;lt;/tt&amp;gt; means that Charlie is the one who modified it. Then, there is the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, which alice can use it to jump through messages marked for review. Finally, the original and translation have been diffed; here they show that, since the last review, the message was fuzzied by changing &amp;quot;You won&amp;quot; to &amp;quot;Tie&amp;quot;, and what Charlie did in translation to unfuzzy it. Even on a message as short as this, the diff tells something useful to Alice: the phrase &amp;quot;Game over&amp;quot; likely has a formulaic translation, and the fact that it is not part of the diff means that the earlier reviewer had made sure it is consistent, so Alice does not have to check that.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment of the second message reveals that both Charlie and Bob had been translating it. &amp;lt;tt&amp;gt;ediff-total&amp;lt;/tt&amp;gt; flag instead of plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; means that this message had no review at all up to now, so there are no embedded diffs in text fields.&lt;br /&gt;
&lt;br /&gt;
Alice can now go through marked files and messages, review translations, and possibly make modifications. When making changes in a message with embedded diffs, she can freely edit text outside of difference segments and within &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments (as these are the ones which belong to current version of the text). While reviewing, Alice does ''not'' remove any of the added message elements while reviewing (save for an occasional difference segment, when translation should be modified), as these elements are needed for later. If a message is particularly hard and Alice wants to defer its review for later, she can add the &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; for short) flag to it.&lt;br /&gt;
&lt;br /&gt;
Once the review is complete, Alice simply commits the reviewed files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (0/2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (0/7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (3/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated         3        21&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; VCS is committing catalogs:&lt;br /&gt;
Sending      LANG/summit/messages/kdegames/palapeli.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/bovo.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/kdiamond.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/palapeli.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1284220.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three things have happened here. First, all review states (flags, embedded diffs, etc.) have been removed, restoring the PO file to normal. Then, any modifications that Alice have made during review are ascribed to her (here 3 out of 21 messages). Finally, all marked messages are ascribed as reviewed by Alice (any with &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; flags would have been omitted here). When committing, the only summit catalog that got committed is the one with modifications made during review, and all the ascription catalogs were committed because of the reviews recorded in them.&lt;br /&gt;
&lt;br /&gt;
When many files with few changes in each are to be reviewed, it becomes burdensome to manually open each and every diffed for review, and then to make sure that all are committed with &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt;. To make this easier, &amp;lt;tt&amp;gt;-w torevivew.out&amp;lt;/tt&amp;gt; option can be added to &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;, which requests that paths of all diffed PO files are written into &amp;lt;tt&amp;gt;torevivew.out&amp;lt;/tt&amp;gt; file. This file can then be used to batch open POs for review in the editor, as well as fed back on &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;-f torevivew.out&amp;lt;/tt&amp;gt;. There is also the &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; option which causes &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; to directly open PO files in a PO editor (though this is currently applicable only to Lokalize). Putting it together, to efficiently review a whole bunch of small changes throughout many files, Alice can:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di PATHS... -w toreview.out -o lokalize&lt;br /&gt;
$ # ...only marked messages opened in Lokalize, review them...&lt;br /&gt;
$ poascribe ci -f toreview.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selecting Messages for Review ===&lt;br /&gt;
&lt;br /&gt;
Invocations of &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; without any options, as in the previous section, were actually equivalent to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; is issuing the message ''selector''. &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is the default selector for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt; mode, and stands for MODified-After-Review: it selects the earliest historical modification of the message after the last (or no) review of that message, if there is any such. By selecting a historical modification of the message, the diff from it to current version can be computed and embedded into the PO file, as in previous examples.&lt;br /&gt;
&lt;br /&gt;
There are various specialized selectors, and fall into two groups: ''shallow selectors'' and ''history selectors''. Shallow selectors look only into the current version of the message, and cannot select historical versions, which means that they cannot provide embedded diffs. History selectors (&amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is of this type) can select messages from history and provide diffs. Several selectors can be issued on the command line, and the message is selected only if all selectors select it. Shallow selectors are then normally used as a pre-filter for history selectors. For example, to select messages modified after last reviewed, but only those found in stable branch, &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; selectors are chained:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s branch:stable -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that the history selector is given last, because the last selector determines which historical message is selected. If the ordering had been reversed here, same messages would get selected, but they would not have embedded diffs, because &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; is a shallow selector.&lt;br /&gt;
&lt;br /&gt;
Selectors can take parameters themselves, like &amp;lt;tt&amp;gt;branch:stable&amp;lt;/tt&amp;gt; in the previous example. Parameters are separated from the selector name by any non-alphanumeric character; this is colon by convention, but if a parameter contains a colon, something like slash, tilde, etc. can be used. Number of parameters can be variable, and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; in particular can take from none to three. If Alice wants to review only those messages modified ''by Charlie'' since last review, she states this by first argument to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:charlie PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Alice does not give too much credit to other reviewers, she can request selection of messages modified after last review ''by her'' with second parameter to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar::alice PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the first parameter (&amp;quot;modified by...&amp;quot;), which is not needed, must be explicitly skipped, before going to the second parameter (&amp;quot;reviewed by...&amp;quot;). The third optional parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; will be mentioned in the next section.&lt;br /&gt;
&lt;br /&gt;
When a selector parameter is a user name, normally it can also be a comma-separated list of user names (&amp;lt;tt&amp;gt;modar:bob,charlie&amp;lt;/tt&amp;gt;) or prefixed with tilde to negate, i.e. select all other users (&amp;lt;tt&amp;gt;modar:~alice&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Any selector can be negated by prepending &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; to its name. For example, the history selector &amp;lt;tt&amp;gt;modafter:DATE&amp;lt;/tt&amp;gt; selects first modification after the given date; to select messages modified after last review, but only if modified during June 2010:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modafter:2010-06 -s nmodafter:2010-07 -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Negating a history selector produces a shallow selector: while &amp;lt;tt&amp;gt;modafter&amp;lt;/tt&amp;gt; is history selector, &amp;lt;tt&amp;gt;nmodafter&amp;lt;/tt&amp;gt; is shallow. But the order of the two in the previous command line is not important, as the last selector is the usual &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selectors can be issued in other modes too. If the PO file is big and Alice has reviewed messages up to and including entry 246 when she has to pause until another day, she can commit reviews only up to this entry by issuing the &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; selector:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -s espan::246 PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the first parameter to &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; is the first entry number, given if messages are not to be selected from the first). There is also the counterpart &amp;lt;tt&amp;gt;lspan&amp;lt;/tt&amp;gt; selector, which works with referent line numbers (those of &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; keywords) instead of entry numbers.&lt;br /&gt;
&lt;br /&gt;
=== Fine-Grained Reviews ===&lt;br /&gt;
&lt;br /&gt;
In the introduction, several distinct types of what can go wrong in translation were described. Not all reviewers may be able to check translation against all those problems. Here is a typical scenario of this kind:&lt;br /&gt;
&lt;br /&gt;
Alice is very computer-savvy and knows the translation project inside and out, which means that she can review well for context, terminology, and technical style. But, her language style leaves something to be desired, which shows through longer sentences and passages. Dan, on the other hand, is a very literary person, but not that much into the technical aspects. Dan's style reviews would thus be a perfect complement to Alice's general reviews.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; can support this scenario in the following way. A ''review type'' tag for language style is defined in the ascription configuration, using the &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[global]&lt;br /&gt;
...&lt;br /&gt;
review-tags = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The value to &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; is a space-separated list of identifiers, when more than one special review type is needed.) With this addition to configuration, Alice can continue to review as she did before, without any changes to her workflow.&lt;br /&gt;
&lt;br /&gt;
Dan selects messages for review similarly to Alice, but aditionally giving the &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; tag as ''third'' parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;, and indicating that ascribed reviews should be tagged as &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:::lstyle -t lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After finishing the review, Dan commits as usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Dan is always going to review the language style, in order not to have to issue the selector and tag in the command line all the time, he can make them default per mode in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = dan&lt;br /&gt;
selectors/diff = modar:::lstyle&lt;br /&gt;
tags/diff = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this Dan can use plain &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; just like Alice does.&lt;br /&gt;
&lt;br /&gt;
The important point of review tags is that they make reviews by types independent. For example, Dan may come around to review the language style of the given message after several modifications and general reviews have been ascribed to it -- &amp;lt;tt&amp;gt;modar:::lstyle&amp;lt;/tt&amp;gt; will simply ignore all reviews except for &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews. This is going to be reflected in the &amp;lt;tt&amp;gt;ascto:&amp;lt;/tt&amp;gt; comment to marked messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: charlie:m alice:r bob:m&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here Alice has made one review between Charlie's and Bob's modifications, and that review, being general instead of &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;, did not cause &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; to stop at it. After Dan reviews this message for language style, Alice runs selection for review and gets this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: bob:m dan:r(lstyle)&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, since &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews do not mix with general reviews, Dan's review did not hide Bob's modification that Alice did not check so far.&lt;br /&gt;
&lt;br /&gt;
(General review too has a tag assigned, the empty string, in case the reviewer needs to explicitly issue it in some context.)&lt;br /&gt;
&lt;br /&gt;
== Daily Use for The Coordinator ==&lt;br /&gt;
&lt;br /&gt;
After setting up the ascription system, the team coordinator should have to do very little to maintain it.&lt;br /&gt;
&lt;br /&gt;
=== Ascribing Merges ===&lt;br /&gt;
&lt;br /&gt;
Modifications made to summit catalogs by merging with templates must also be ascribed. Therefore, after merging the summit (&amp;lt;tt&amp;gt;posummit ... merge ...&amp;lt;/tt&amp;gt;) the coordinator substitutes the VCS command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command in &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the user is not explicitly given by &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option, this will ascribe merge modifications to the coordinator (more precisely, to the user set as default in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;), which is just fine. It is also possible to define a special user only for ascribing merge modifications, though there is no known advantage to that.&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option is not issued, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will automatically commit all modified summit and ascription catalogs when done.&lt;br /&gt;
&lt;br /&gt;
=== Shuffling Ascription Catalogs  ===&lt;br /&gt;
&lt;br /&gt;
Sometimes summit catalogs are shuffled in the repository: moved to another module, renamed, one catalog split into two, two catalogs merged into one. Such shuffling should be exactly mirrored in the ascription tree, and this too is done on the repository side, at the same time. This relies on the ascription root being set exactly to &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt; in the ascription configuration. So the team coordinator has nothing special to do here.&lt;br /&gt;
&lt;br /&gt;
If instead in the central KDE repository the translation team is working in an external repository, by consequence the ascription system must be set up in that repository. But so long as &amp;lt;tt&amp;gt;process_orphans.sh&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; is used to shuffle catalogs in the external repository as well, the ascription catalogs will be properly handled.&lt;br /&gt;
&lt;br /&gt;
== Filtering for Release ==&lt;br /&gt;
&lt;br /&gt;
The last component of the ascription system is how to prevent insufficiently reviewed messages from leaking into a release. In context of Pology and summit workflow, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; itself is used directly to this end. Instead, in the summit configuration (as opposed to ascription configuration), the team coordinator defines filters which pass messages by applying selectors.&lt;br /&gt;
&lt;br /&gt;
Each top level PO tree has its own summit configuration file, named &amp;lt;tt&amp;gt;MSGTREE.extras.summit&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            messages.extras.summit&lt;br /&gt;
            docmessages/&lt;br /&gt;
            docmessages.extras.summit&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the simple case of all reviews being general reviews, the filter is added to summit configuration like this (anywhere within &amp;lt;tt&amp;gt;*.extras.summit&amp;lt;/tt&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the filter is named &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;, and is defined as application of &amp;lt;tt&amp;gt;nmodar&amp;lt;/tt&amp;gt; selector, the negation of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;. This simply means: pass all messages ''not'' modified after the last review.&lt;br /&gt;
&lt;br /&gt;
When the team coordinator scatters to branches (executes &amp;lt;tt&amp;gt;posummit scatter&amp;lt;/tt&amp;gt;), messages from summit POs which do not pass this filter will not be sent to branch POs. The count of stopped messages by branch PO will be reported in the output as scattering proceeds.&lt;br /&gt;
&lt;br /&gt;
Why did we have to name the filter &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;? (Those knowing some Python will also notice that it is defined as a list element.) Because it is possible to define more than one filter, and select which one is used on each scattering. For example, the coordinator may wish that, when the release is near and time is short to review everything, messages from a few experienced translators can be passed into release without review. If those translators are Alice and Bob, an &amp;quot;emergency&amp;quot; filter can be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; uses the first filter in the list. When the coordinator needs to do emergency scattering, he requests the emergency filter by the &amp;lt;tt&amp;gt;-a&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter -a emergency&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What if several selectors are needed to pass the message? For example, the language style review (the earlier example with Alice and Dan) too may be requested for regular scattering, but omitted from emergency scattering. The filter setup for this scenario looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;, &amp;quot;nmodar:::lstyle&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The regular filter now reads: pass the message if it has not been modified after the last (general) review ''and'' has not been modified after the last style review.&lt;br /&gt;
&lt;br /&gt;
Simple combination of predefined selectors by AND-conditions may not be sufficient for more involved scenarios. When this is the case, the coordinator may write (or ask someone to write) a custom selector in Python, and plug it in as the second element in the filter tuple (instead of the list of predefined selectors).&lt;br /&gt;
&lt;br /&gt;
=== Writing a Selector Function ===&lt;br /&gt;
&lt;br /&gt;
((To be written.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-05-29T09:55:04Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Updated output in examples.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading'', ''approving''), each of which may return the translation to a previous stage, or forward it to some special stage. The process can also be more finer grained, where each message in the file goes through stages separately.&lt;br /&gt;
&lt;br /&gt;
Regardless of the particularities, workflows of this kind all have the following in common. Members of the translation team are assigned ''roles'' -- such as ''translator'', ''reviewer'', ''approver'', ''committer'' -- by which they enter into the workflow (single person can have more roles). The later review stages must wait for the earlier stages to complete, and the translation cannot be updated again before the current version clears the pipeline (or the pipeline is aborted). Most importantly, once the translation is committed, it becomes part of simply &amp;quot;admitted&amp;quot; translations, with no further qualifiers.&lt;br /&gt;
&lt;br /&gt;
The system of prescribed roles requires that team members assign them between themselves, stick to them, and shuffle them along the way. The prescribed review pipeline requires a tool to enforce and keep track of the stages in which translations are. This makes the review workflow complex and rigid, most probably with choke points for efficiency. Distribution of roles may become disbalanced by people coming and going, or the workflow tool may be prohibitive to some scenarios (e.g. single translator making small adjustments in dozens of files across the project, but having to upload each manually through a web interface).&lt;br /&gt;
&lt;br /&gt;
Of course, &amp;quot;rigid&amp;quot;, &amp;quot;complex&amp;quot;, &amp;quot;inefficient&amp;quot;, are comparative qualifications, so what is it that the classical review by stages can be compared to in this way?&lt;br /&gt;
&lt;br /&gt;
== Reviewing by Ascriptions ==&lt;br /&gt;
&lt;br /&gt;
Reviewing by ascriptions is even simpler conceptually, and yet less rigid, less complex, and much more efficient than the review by stages. It works on the message-level, rather than file-level. Anyone can simply translate some messages and directly commit modified files, without any review, but with ''ascribing'' modifications to own name. Anyone can review any committed messages at any moment, commit the modifications-on-review and ascribe reviews to own name and (possibly) to certain class -- full review, review of context, of terminology, of style, etc. Only when the translation is to be shipped to end users, the ''insufficiently'' reviewed messages are automatically omitted from the package, by evaluating the ''ascription history'' of each message.&lt;br /&gt;
&lt;br /&gt;
Most importantly, based on the ascription history, the reviewer can select only some particular messages, and review only the difference between their historical and current versions. For example, Alice can select to review only messages modified since she or Bob had last reviewed them for style; she could see the difference from that last review to current version, e.g. if in the whole paragraph only a single word has changed by Charlie when he reviewed the terminology. In terms of PO workflow, the ascription history propagates through merges, so the reviewer can compare the change in original and the change in translation since the last review, to judge if one fits the other.&lt;br /&gt;
&lt;br /&gt;
Since everyone just commits, translations can be efficiently kept in a version control repository, with the ascription system added on top. After having done some translating, the team member simply substitutes commit command of the version control system (VCS) with ascribe-modifications command of the ascription system (AS, which calls the underlying VCS internally). After reviewing, the team member uses ascribe-reviews command of the AS to commit reviews to ascription history (as well as modifications made during the review). To select messages for review, the team member issues diff-for-review command of the AS (with suitable parameters to narrow the set) and selected messages are marked in-place in PO files and [[Localization/Tools/Pology/PO_Embedded_Diffing|embedded with differences]], and possibly popped open in a PO editor.&lt;br /&gt;
&lt;br /&gt;
When the translations are to be released, the team coordinator issues filter-for-release command of the AS, which takes the working PO files and creates final PO files with insufficiently reviewed messages removed. &amp;quot;Release time&amp;quot; is used here only figuratively: this should be a fully automatic process, so it can be performed at any interval of convenience.&lt;br /&gt;
&lt;br /&gt;
What constitutes &amp;quot;sufficient review&amp;quot; can be defined in fine detail. It could be specified that messages modified by Alice need to have only review for terminology, but not necessarily for style; Charlie may belong to the group which needs to be reviewed on style, but not necessarily on context; Bob's reviews for style may be nice to have, but never blocking if missing. These decisions do not preclude released messages to be reviewed later on missing points, after higher priority reviews have been completed. The definition of sufficiency may be changed at any point, e.g. as team members get more experienced and require less review, without interfering with direct translation and review work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- (Here is one unorthodox possibility of using reviews by ascriptions. A random translator may want to keep an eye on what the reviewers change in the files he maintains. For example, to learn what are typical small errors that he makes while translating. Therefore, he himself reviews any modifications not made by him after his last review, and commits them. This will in no way interfere with &amp;quot;canonical&amp;quot; reviews, those considered at release time.) //--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In summary, with reviewing by ascriptions the lean efficiency of raw VCS operation is preserved while providing for great flexibility of review. All team members can be given commit access, no web or email detours are needed. There are no prescribed roles, but an equivalent of role assignment happens automatically at last possible moment, and can take into account both translators' and reviewers' abilities. There is no staging between completing and committing the translation, which enables translator to keep on polishing the translation undisturbed until the reviewer comes around. There is no inefficiency in handling small changes throughout many files, since single AS command commits all changes just as single VCS command would. AS in effect abstracts VCS, so general team members do not have to know the particularities of the underlying VCS. On commit operations, AS can also apply checks (e.g. decline to commit syntactically invalid PO files) and modifications (e.g. update translator's data in the PO header).&lt;br /&gt;
&lt;br /&gt;
== Ascription System in Pology ==&lt;br /&gt;
&lt;br /&gt;
[[Localization/Tools/Pology|Pology]] is a collection of various modular tools for supporting translation based on PO files. Among them is the script &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which implements an ascription system (AS); at present, it can use Subversion or Git as the underlying VCS. &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is still in experimental stage, so what follows is a brief description of how to use it in context of the KDE translation project. However, very little is truly specific to KDE; the only major assumption is that there exists a VCS repository with PO files of a given language grouped together, and that the translation team can use it without special restrictions.&lt;br /&gt;
&lt;br /&gt;
Very important for the AS is how branches are handled (in KDE, the rolling trunk and stable branches). AS can in principle be deployed by branch, but then there is the added complexity of porting translations between branches, which ascriptions should follow. Therefore, the AS implemented by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is currently limited to assumption that there is a single branch of translations at all times. The article [[Localization/Workflows/PO_Summit|&amp;quot;Translating in Summit&amp;quot;]] explains how a KDE translation team can set up and operate such a single branch, the summit, and this is the prerequisite for the following instructions. (Note that the summit system is useful on its own, and should be conductive to any kind of review workflow.)&lt;br /&gt;
&lt;br /&gt;
== Setting Up ==&lt;br /&gt;
&lt;br /&gt;
The summit branch for the language &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt; is positioned like this in the KDE repository:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            LANG/&lt;br /&gt;
                summit/&lt;br /&gt;
                    messages/&lt;br /&gt;
                    docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The team coordinator already has this part of the repository tree locally due to regular summit operations. For the same reason Pology is already set up. Setting up the ascription system is now simple. The file &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; is created in the root of the summit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# ---------------------------&lt;br /&gt;
# Global ascription settings.&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
&lt;br /&gt;
# The root of the ascription catalog tree.&lt;br /&gt;
ascript-root = ../summit-ascript&lt;br /&gt;
&lt;br /&gt;
# The underlying version control system.&lt;br /&gt;
version-control = svn&lt;br /&gt;
&lt;br /&gt;
# Data for updating catalog headers.&lt;br /&gt;
# - language code&lt;br /&gt;
language = LANG&lt;br /&gt;
# - full language name&lt;br /&gt;
language-team = LANGUAGE&lt;br /&gt;
# - email address of the team&lt;br /&gt;
team-email = kde-i18n-LANG@kde.org&lt;br /&gt;
&lt;br /&gt;
# Default commit message.&lt;br /&gt;
commit-message = Translation updates.&lt;br /&gt;
&lt;br /&gt;
# -----------------------&lt;br /&gt;
# Registered translators.&lt;br /&gt;
&lt;br /&gt;
[user-alice]&lt;br /&gt;
name = Alice Akmalryn&lt;br /&gt;
original-name = Алиса Акмалрин&lt;br /&gt;
email = alice.akmalryn@someplacenice.org&lt;br /&gt;
&lt;br /&gt;
[user-bob]&lt;br /&gt;
name = Bob Byomkin&lt;br /&gt;
original-name = Бобан Бјомкин&lt;br /&gt;
email = bob.byomkin@otherplacenice.org&lt;br /&gt;
&lt;br /&gt;
# ...and so on.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;ascript-root&amp;lt;/tt&amp;gt; setting should be exactly &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt;, for the reason mentioned later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit-message&amp;lt;/tt&amp;gt; field, if defined, allows team members to commit without providing a commit message. The value given by this field will be used by default, with translator's user name appended to the end in special syntax. For example: &amp;lt;tt&amp;gt;Translation updates. [&amp;gt;alice]&amp;lt;/tt&amp;gt;. (Translator's user name is also appended to manually supplied commit messages.) Translators can still supply a commit message when they wish, as shown later. If this field is not set, the commit message is supplied as usual on committing.&lt;br /&gt;
&lt;br /&gt;
* Team members are defined by &amp;lt;tt&amp;gt;[user-USERNAME]&amp;lt;/tt&amp;gt; sections. Ascription user names can be any valid ASCII identifier: ASCII letters, digits and underscores only, digit cannot be the first character. Ascription user names have no technical relation to the underlying VCS accounts, though it is mnemonically convenient if they are the same (in case of SVN). This means that a translator who does not have a VCS account (yet) can and should be added here, with assigned user name (best one suitable as SVN account name later); why this should be done will be explained later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field in user sections is there in case the preferred renderings of the name in English and in target language are not the same. When this is not the case, &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; can be omitted.&lt;br /&gt;
&lt;br /&gt;
As soon as the &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; file is committed, the ascription system is ready for operation. Only regular modifications to this file are those of adding new team members. (On the other hand, team members should never be removed, because even after they no longer contribute, their ascription records remain in the system.)&lt;br /&gt;
&lt;br /&gt;
=== Initial Ascription ===&lt;br /&gt;
&lt;br /&gt;
The most common situation at start of ascription workflow is that there already exists a body of translations, contributed to by many different people over time. The coordinator should ascribe all existing translations as initial modifications, but to whom? It cannot be said precisely who translated what. The solution is to introduce a generic user in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;, suitably known as &amp;quot;Unknown Hero&amp;quot; (or &amp;quot;Lost Translator&amp;quot;, you can be inventive):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[user-uhero]&lt;br /&gt;
name = Unknown Hero&lt;br /&gt;
original-name = Незнани јунак&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ascribe all existing translations as modified and reviewed by this user. The coordinator does this with the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe commit -u uhero --all-reviewed -C LANG/summit/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; is the ascription mode, and the &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option provides the user name to which ascriptions are made. This is an important point: ascriptions are made to a user defined in ascription configuration, and have nothing to do with VCS accounts; someone who has the account can commit in the name of someone who does not. It is the &amp;lt;tt&amp;gt;--all-reviewed&amp;lt;/tt&amp;gt; option that declares all messages to be reviewed as well (note that it is normally used only this once, and not for normal day to day reviewing). The &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option prevent automatic committing by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which is useful for this initial step. Finally the paths which contain all summit catalogs are given.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command is issued, a progress bar will appear, and the following output will start to unfold:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
LANG/summit/messages/extragear-base/rellinks.po  (50/50)&lt;br /&gt;
LANG/summit/messages/extragear-base/autorefresh.po  (13/13)&lt;br /&gt;
LANG/summit/messages/extragear-base/babelfish.po  (38/38)&lt;br /&gt;
...&lt;br /&gt;
LANG/summit/messages/qt/libphonon.po  (13/13)&lt;br /&gt;
LANG/summit/messages/qt/phonon-xine.po  (24/24)&lt;br /&gt;
LANG/summit/messages/qt/phonon_gstreamer.po  (12/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated    111775    111775&lt;br /&gt;
fuzzy          26943     26943&lt;br /&gt;
obsolete/t      2965      2965&lt;br /&gt;
obsolete/f      1626      1626&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number in parenthesis indicates how many messages have been ascribed in the given PO file (modified/reviewed), and at the end the totals are given. Ascribing the complete summit for the first time will take quite some time (on the order of 10-20 minutes).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--If, on the contrary, it is known who translated and reviewed what, ascription can be performed piece-wise with user names of real translators:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support/LANG/summit&lt;br /&gt;
$ poascribe commit -u alice --all-reviewed -C kdelibs/ kdepimlibs/ kdebase/&lt;br /&gt;
$ poascribe commit -u bob --all-reviewed -C kdemultimedia/ kdeutils/&lt;br /&gt;
$ ...&lt;br /&gt;
&amp;lt;/code&amp;gt;//--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the initial ascription has been made, the ascription tree will appear next to the summit tree. This tree will contain one ascription PO file for each summit PO file, with the same name and relative location within the tree:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
        summit-ascript/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ascription tree can now be committed as usual (&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will have already added it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit-ascript/ -m &amp;quot;Initial ascription.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Translators ==&lt;br /&gt;
&lt;br /&gt;
Team members other than the coordinator, whether translators or reviewers, need to keep around only the &amp;lt;tt&amp;gt;trunk/l10n-support/LANG/&amp;lt;/tt&amp;gt; directory. But they always need to update this directory fully (rather than just one particular module or file under &amp;lt;tt&amp;gt;.../*messages/&amp;lt;/tt&amp;gt;), so that the summit tree and the ascription tree (and configuration) are kept in sync.&lt;br /&gt;
&lt;br /&gt;
In order not to have to issue their own user name (&amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;) all the time, translators can set it in Pology user configuration &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, in &amp;lt;tt&amp;gt;[poascribe]&amp;lt;/tt&amp;gt; section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = alice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translators can then submit updated PO files simply by substituting &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt; (or whatever the VCS commit command is) with &amp;lt;tt&amp;gt;poascribe commit&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;co&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;ci&amp;lt;/tt&amp;gt; for short):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdefoo/*fooapp*.po&lt;br /&gt;
LANG/summit/messages/kdefoo/fooapp.po  (144)&lt;br /&gt;
LANG/summit/messages/kdefoo/libfooapp.po  (25)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified&lt;br /&gt;
translated       169&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; VCS is committing catalogs:&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/libfooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/libfooapp.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1267069.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will add ascription records into ascription catalogs corresponding to summit catalogs to be committed, and commit them all. Like &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt; can take any number of file or directory paths, and can be issued from any working directory (it will always find ascription catalogs). If default commit message has not been set in the ascription configuration, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will ask for it; or it can be given in command line through &amp;lt;tt&amp;gt;-m&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
=== Translators Without Commit Access ===&lt;br /&gt;
&lt;br /&gt;
With the ascription system in place, every regular team member should have commit access. But, there may be some period of time before new translators are given accounts, revision control may be too technical for some, and even those with the account may not be able to commit temporarily for some reason.&lt;br /&gt;
&lt;br /&gt;
These translators may send in their work by email, to ''any'' team member with commit access (not necessarily the coordinator or a reviewer); this team member can commit received files without any review, as review can be conducted at any later time. If Bob sends some files to Alice, she can commit them immediately by stating Bob's user name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -u bob ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, the translator who sent in the files has to be defined in the ascription configuration. There are no hidden costs or security issues to this (as opposed to opening a VCS account), so every new translator should be defined there before any work of that person is committed.&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Reviewers ==&lt;br /&gt;
&lt;br /&gt;
The ascription system opens up all sorts of possibilities for concrete review patterns. Reviewers should keep in mind that for each message the full modification and review history is available, so that the team can think about how to make good use of it. Therefore, what follows are some examples to illustrate the review facilities that &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; provides.&lt;br /&gt;
&lt;br /&gt;
=== Basic Reviewing ===&lt;br /&gt;
&lt;br /&gt;
At the very basic level (which is the only level in classical review by stages), messages can be classified into simply unreviewed and reviewed, without further qualifiers. Alice now wants to review all unreviewed messages in a group of PO files, say &amp;lt;tt&amp;gt;kdetoys&amp;lt;/tt&amp;gt; module. She issues (&amp;lt;tt&amp;gt;di&amp;lt;/tt&amp;gt; is short for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe di LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===== Diffed for review: 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unreviewed messages have now been marked and diffed, inside the listed PO files. What is this about &amp;quot;diffing&amp;quot;? If the files had already been reviewed before, some of the messages modified since then (those marked for review) may have changed very little (e.g. a few words in a paragraph-length message, or even just punctuation). Therefore, for each message marked for review, Alice also wants to see the diff since last review to current version. Here are two messages in typical review states added by &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: charlie:m&lt;br /&gt;
#: gui/mainwindow.cc:372&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;GAME OVER. {-You won-}{+Tie+}!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KRAJ IGRE. {-Pobeda-}{+Nerešeno+}!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: bob:m charlie:m&lt;br /&gt;
#: game-state.cpp:117&lt;br /&gt;
#, ediff-total&lt;br /&gt;
msgid &amp;quot;Click the pause button again to resume the game.&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Kliknite ponovo na dugme pauze da nastavite igru.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the first one in Kate:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_poascribe_diff_01.png|center|Message diffed for review by poascribe in Kate.]]&lt;br /&gt;
&lt;br /&gt;
In the first message, the first to note is the &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment. This comment succinctly lists who did what with the message since the last review; here &amp;lt;tt&amp;gt;charlie:m&amp;lt;/tt&amp;gt; means that Charlie is the one who modified it. Then, there is the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, which alice can use it to jump through messages marked for review. Finally, the original and translation have been diffed; here they show that, since the last review, the message was fuzzied by changing &amp;quot;You won&amp;quot; to &amp;quot;Tie&amp;quot;, and what Charlie did in translation to unfuzzy it. Even on a message as short as this, the diff tells something useful to Alice: the phrase &amp;quot;Game over&amp;quot; likely has a formulaic translation, and the fact that it is not part of the diff means that the earlier reviewer had made sure it is consistent, so Alice does not have to check that.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment of the second message reveals that both Charlie and Bob had been translating it. &amp;lt;tt&amp;gt;ediff-total&amp;lt;/tt&amp;gt; flag instead of plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; means that this message had no review at all up to now, so there are no embedded diffs in text fields.&lt;br /&gt;
&lt;br /&gt;
Alice can now go through marked files and messages, review translations, and possibly make modifications. When making changes in a message with embedded diffs, she can freely edit text outside of difference segments and within &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments (as these are the ones which belong to current version of the text). While reviewing, Alice does ''not'' remove any of the added message elements while reviewing (save for an occasional difference segment, when translation should be modified), as these elements are needed for later. If a message is particularly hard and Alice wants to defer its review for later, she can add the &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; for short) flag to it.&lt;br /&gt;
&lt;br /&gt;
Once the review is complete, Alice simply commits the reviewed files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (0/2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (0/7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (3/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated         3        21&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; VCS is committing catalogs:&lt;br /&gt;
Sending      LANG/summit/messages/kdegames/palapeli.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/bovo.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/kdiamond.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/palapeli.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1284220.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three things have happened here. First, all review states (flags, embedded diffs, etc.) have been removed, restoring the PO file to normal. Then, any modifications that Alice have made during review are ascribed to her (here 3 out of 21 messages). Finally, all marked messages are ascribed as reviewed by Alice (any with &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; flags would have been omitted here). When committing, the only summit catalog that got committed is the one with modifications made during review, and all the ascription catalogs were committed because of the reviews recorded in them.&lt;br /&gt;
&lt;br /&gt;
When many files with few changes in each are to be reviewed, it becomes burdensome to manually open each and every diffed for review, and then to make sure that all are committed with &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt;. To make this easier, &amp;lt;tt&amp;gt;-w torevivew.out&amp;lt;/tt&amp;gt; option can be added to &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;, which requests that paths of all diffed PO files are written into &amp;lt;tt&amp;gt;torevivew.out&amp;lt;/tt&amp;gt; file. This file can then be used to batch open POs for review in the editor, as well as fed back on &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;-f torevivew.out&amp;lt;/tt&amp;gt;. There is also the &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; option which causes &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; to directly open PO files in a PO editor (though this is currently applicable only to Lokalize). Putting it together, to efficiently review a whole bunch of small changes throughout many files, Alice can:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di PATHS... -w toreview.out -o lokalize&lt;br /&gt;
$ # ...only marked messages opened in Lokalize, review them...&lt;br /&gt;
$ poascribe ci -f toreview.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selecting Messages for Review ===&lt;br /&gt;
&lt;br /&gt;
Invocations of &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; without any options, as in the previous section, were actually equivalent to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; is issuing the message ''selector''. &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is the default selector for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt; mode, and stands for MODified-After-Review: it selects the earliest historical modification of the message after the last (or no) review of that message, if there is any such. By selecting a historical modification of the message, the diff from it to current version can be computed and embedded into the PO file, as in previous examples.&lt;br /&gt;
&lt;br /&gt;
There are various specialized selectors, and fall into two groups: ''shallow selectors'' and ''history selectors''. Shallow selectors look only into the current version of the message, and cannot select historical versions, which means that they cannot provide embedded diffs. History selectors (&amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is of this type) can select messages from history and provide diffs. Several selectors can be issued on the command line, and the message is selected only if all selectors select it. Shallow selectors are then normally used as a pre-filter for history selectors. For example, to select messages modified after last reviewed, but only those found in stable branch, &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; selectors are chained:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s branch:stable -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that the history selector is given last, because the last selector determines which historical message is selected. If the ordering had been reversed here, same messages would get selected, but they would not have embedded diffs, because &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; is a shallow selector.&lt;br /&gt;
&lt;br /&gt;
Selectors can take parameters themselves, like &amp;lt;tt&amp;gt;branch:stable&amp;lt;/tt&amp;gt; in the previous example. Parameters are separated from the selector name by any non-alphanumeric character; this is colon by convention, but if a parameter contains a colon, something like slash, tilde, etc. can be used. Number of parameters can be variable, and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; in particular can take from none to three. If Alice wants to review only those messages modified ''by Charlie'' since last review, she states this by first argument to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:charlie PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Alice does not give too much credit to other reviewers, she can request selection of messages modified after last review ''by her'' with second parameter to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar::alice PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the first parameter (&amp;quot;modified by...&amp;quot;), which is not needed, must be explicitly skipped, before going to the second parameter (&amp;quot;reviewed by...&amp;quot;). The third optional parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; will be mentioned in the next section.&lt;br /&gt;
&lt;br /&gt;
When a selector parameter is a user name, normally it can also be a comma-separated list of user names (&amp;lt;tt&amp;gt;modar:bob,charlie&amp;lt;/tt&amp;gt;) or prefixed with tilde to negate, i.e. select all other users (&amp;lt;tt&amp;gt;modar:~alice&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Any selector can be negated by prepending &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; to its name. For example, the history selector &amp;lt;tt&amp;gt;modafter:DATE&amp;lt;/tt&amp;gt; selects first modification after the given date; to select messages modified after last review, but only if modified during June 2010:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modafter:2010-06 -s nmodafter:2010-07 -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Negating a history selector produces a shallow selector: while &amp;lt;tt&amp;gt;modafter&amp;lt;/tt&amp;gt; is history selector, &amp;lt;tt&amp;gt;nmodafter&amp;lt;/tt&amp;gt; is shallow. But the order of the two in the previous command line is not important, as the last selector is the usual &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selectors can be issued in other modes too. If the PO file is big and Alice has reviewed messages up to and including entry 246 when she has to pause until another day, she can commit reviews only up to this entry by issuing the &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; selector:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -s espan::246 PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the first parameter to &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; is the first entry number, given if messages are not to be selected from the first). There is also the counterpart &amp;lt;tt&amp;gt;lspan&amp;lt;/tt&amp;gt; selector, which works with referent line numbers (those of &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; keywords) instead of entry numbers.&lt;br /&gt;
&lt;br /&gt;
=== Fine-Grained Reviews ===&lt;br /&gt;
&lt;br /&gt;
In the introduction, several distinct types of what can go wrong in translation were described. Not all reviewers may be able to check translation against all those problems. Here is a typical scenario of this kind:&lt;br /&gt;
&lt;br /&gt;
Alice is very computer-savvy and knows the translation project inside and out, which means that she can review well for context, terminology, and technical style. But, her language style leaves something to be desired, which shows through longer sentences and passages. Dan, on the other hand, is a very literary person, but not that much into the technical aspects. Dan's style reviews would thus be a perfect complement to Alice's general reviews.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; can support this scenario in the following way. A ''review type'' tag for language style is defined in the ascription configuration, using the &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[global]&lt;br /&gt;
...&lt;br /&gt;
review-tags = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The value to &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; is a space-separated list of identifiers, when more than one special review type is needed.) With this addition to configuration, Alice can continue to review as she did before, without any changes to her workflow.&lt;br /&gt;
&lt;br /&gt;
Dan selects messages for review similarly to Alice, but aditionally giving the &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; tag as ''third'' parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;, and indicating that ascribed reviews should be tagged as &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:::lstyle -t lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After finishing the review, Dan commits as usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Dan is always going to review the language style, in order not to have to issue the selector and tag in the command line all the time, he can make them default per mode in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = dan&lt;br /&gt;
selectors/diff = modar:::lstyle&lt;br /&gt;
tags/diff = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this Dan can use plain &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; just like Alice does.&lt;br /&gt;
&lt;br /&gt;
The important point of review tags is that they make reviews by types independent. For example, Dan may come around to review the language style of the given message after several modifications and general reviews have been ascribed to it -- &amp;lt;tt&amp;gt;modar:::lstyle&amp;lt;/tt&amp;gt; will simply ignore all reviews except for &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews. This is going to be reflected in the &amp;lt;tt&amp;gt;ascto:&amp;lt;/tt&amp;gt; comment to marked messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: charlie:m alice:r bob:m&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here Alice has made one review between Charlie's and Bob's modifications, and that review, being general instead of &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;, did not cause &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; to stop at it. After Dan reviews this message for language style, Alice runs selection for review and gets this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: bob:m dan:r(lstyle)&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, since &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews do not mix with general reviews, Dan's review did not hide Bob's modification that Alice did not check so far.&lt;br /&gt;
&lt;br /&gt;
(General review too has a tag assigned, the empty string, in case the reviewer needs to explicitly issue it in some context.)&lt;br /&gt;
&lt;br /&gt;
== Daily Use for The Coordinator ==&lt;br /&gt;
&lt;br /&gt;
After setting up the ascription system, the team coordinator should have to do very little to maintain it.&lt;br /&gt;
&lt;br /&gt;
=== Ascribing Merges ===&lt;br /&gt;
&lt;br /&gt;
Modifications made to summit catalogs by merging with templates must also be ascribed. Therefore, after merging the summit (&amp;lt;tt&amp;gt;posummit ... merge ...&amp;lt;/tt&amp;gt;) the coordinator substitutes the VCS command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command in &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the user is not explicitly given by &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option, this will ascribe merge modifications to the coordinator (more precisely, to the user set as default in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;), which is just fine. It is also possible to define a special user only for ascribing merge modifications, though there is no known advantage to that.&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option is not issued, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will automatically commit all modified summit and ascription catalogs when done.&lt;br /&gt;
&lt;br /&gt;
=== Shuffling Ascription Catalogs  ===&lt;br /&gt;
&lt;br /&gt;
Sometimes summit catalogs are shuffled in the repository: moved to another module, renamed, one catalog split into two, two catalogs merged into one. Such shuffling should be exactly mirrored in the ascription tree, and this too is done on the repository side, at the same time. This relies on the ascription root being set exactly to &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt; in the ascription configuration. So the team coordinator has nothing special to do here.&lt;br /&gt;
&lt;br /&gt;
If instead in the central KDE repository the translation team is working in an external repository, by consequence the ascription system must be set up in that repository. But so long as &amp;lt;tt&amp;gt;process_orphans.sh&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; is used to shuffle catalogs in the external repository as well, the ascription catalogs will be properly handled.&lt;br /&gt;
&lt;br /&gt;
== Filtering for Release ==&lt;br /&gt;
&lt;br /&gt;
The last component of the ascription system is how to prevent insufficiently reviewed messages from leaking into a release. In context of Pology and summit workflow, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; itself is used directly to this end. Instead, in the summit configuration (as opposed to ascription configuration), the team coordinator defines filters which pass messages by applying selectors.&lt;br /&gt;
&lt;br /&gt;
Each top level PO tree has its own summit configuration file, named &amp;lt;tt&amp;gt;MSGTREE.extras.summit&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            messages.extras.summit&lt;br /&gt;
            docmessages/&lt;br /&gt;
            docmessages.extras.summit&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the simple case of all reviews being general reviews, the filter is added to summit configuration like this (anywhere within &amp;lt;tt&amp;gt;*.extras.summit&amp;lt;/tt&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the filter is named &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;, and is defined as application of &amp;lt;tt&amp;gt;nmodar&amp;lt;/tt&amp;gt; selector, the negation of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;. This simply means: pass all messages ''not'' modified after the last review.&lt;br /&gt;
&lt;br /&gt;
When the team coordinator scatters to branches (executes &amp;lt;tt&amp;gt;posummit scatter&amp;lt;/tt&amp;gt;), messages from summit POs which do not pass this filter will not be sent to branch POs. The count of stopped messages by branch PO will be reported in the output as scattering proceeds.&lt;br /&gt;
&lt;br /&gt;
Why did we have to name the filter &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;? (Those knowing some Python will also notice that it is defined as a list element.) Because it is possible to define more than one filter, and select which one is used on each scattering. For example, the coordinator may wish that, when the release is near and time is short to review everything, messages from a few experienced translators can be passed into release without review. If those translators are Alice and Bob, an &amp;quot;emergency&amp;quot; filter can be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; uses the first filter in the list. When the coordinator needs to do emergency scattering, he requests the emergency filter by the &amp;lt;tt&amp;gt;-a&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter -a emergency&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What if several selectors are needed to pass the message? For example, the language style review (the earlier example with Alice and Dan) too may be requested for regular scattering, but omitted from emergency scattering. The filter setup for this scenario looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;, &amp;quot;nmodar:::lstyle&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The regular filter now reads: pass the message if it has not been modified after the last (general) review ''and'' has not been modified after the last style review.&lt;br /&gt;
&lt;br /&gt;
Simple combination of predefined selectors by AND-conditions may not be sufficient for more involved scenarios. When this is the case, the coordinator may write (or ask someone to write) a custom selector in Python, and plug it in as the second element in the filter tuple (instead of the list of predefined selectors).&lt;br /&gt;
&lt;br /&gt;
=== Writing a Selector Function ===&lt;br /&gt;
&lt;br /&gt;
((To be written.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-05-29T09:49:54Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Updated to new poascribe mode semantics.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading'', ''approving''), each of which may return the translation to a previous stage, or forward it to some special stage. The process can also be more finer grained, where each message in the file goes through stages separately.&lt;br /&gt;
&lt;br /&gt;
Regardless of the particularities, workflows of this kind all have the following in common. Members of the translation team are assigned ''roles'' -- such as ''translator'', ''reviewer'', ''approver'', ''committer'' -- by which they enter into the workflow (single person can have more roles). The later review stages must wait for the earlier stages to complete, and the translation cannot be updated again before the current version clears the pipeline (or the pipeline is aborted). Most importantly, once the translation is committed, it becomes part of simply &amp;quot;admitted&amp;quot; translations, with no further qualifiers.&lt;br /&gt;
&lt;br /&gt;
The system of prescribed roles requires that team members assign them between themselves, stick to them, and shuffle them along the way. The prescribed review pipeline requires a tool to enforce and keep track of the stages in which translations are. This makes the review workflow complex and rigid, most probably with choke points for efficiency. Distribution of roles may become disbalanced by people coming and going, or the workflow tool may be prohibitive to some scenarios (e.g. single translator making small adjustments in dozens of files across the project, but having to upload each manually through a web interface).&lt;br /&gt;
&lt;br /&gt;
Of course, &amp;quot;rigid&amp;quot;, &amp;quot;complex&amp;quot;, &amp;quot;inefficient&amp;quot;, are comparative qualifications, so what is it that the classical review by stages can be compared to in this way?&lt;br /&gt;
&lt;br /&gt;
== Reviewing by Ascriptions ==&lt;br /&gt;
&lt;br /&gt;
Reviewing by ascriptions is even simpler conceptually, and yet less rigid, less complex, and much more efficient than the review by stages. It works on the message-level, rather than file-level. Anyone can simply translate some messages and directly commit modified files, without any review, but with ''ascribing'' modifications to own name. Anyone can review any committed messages at any moment, commit the modifications-on-review and ascribe reviews to own name and (possibly) to certain class -- full review, review of context, of terminology, of style, etc. Only when the translation is to be shipped to end users, the ''insufficiently'' reviewed messages are automatically omitted from the package, by evaluating the ''ascription history'' of each message.&lt;br /&gt;
&lt;br /&gt;
Most importantly, based on the ascription history, the reviewer can select only some particular messages, and review only the difference between their historical and current versions. For example, Alice can select to review only messages modified since she or Bob had last reviewed them for style; she could see the difference from that last review to current version, e.g. if in the whole paragraph only a single word has changed by Charlie when he reviewed the terminology. In terms of PO workflow, the ascription history propagates through merges, so the reviewer can compare the change in original and the change in translation since the last review, to judge if one fits the other.&lt;br /&gt;
&lt;br /&gt;
Since everyone just commits, translations can be efficiently kept in a version control repository, with the ascription system added on top. After having done some translating, the team member simply substitutes commit command of the version control system (VCS) with ascribe-modifications command of the ascription system (AS, which calls the underlying VCS internally). After reviewing, the team member uses ascribe-reviews command of the AS to commit reviews to ascription history (as well as modifications made during the review). To select messages for review, the team member issues diff-for-review command of the AS (with suitable parameters to narrow the set) and selected messages are marked in-place in PO files and [[Localization/Tools/Pology/PO_Embedded_Diffing|embedded with differences]], and possibly popped open in a PO editor.&lt;br /&gt;
&lt;br /&gt;
When the translations are to be released, the team coordinator issues filter-for-release command of the AS, which takes the working PO files and creates final PO files with insufficiently reviewed messages removed. &amp;quot;Release time&amp;quot; is used here only figuratively: this should be a fully automatic process, so it can be performed at any interval of convenience.&lt;br /&gt;
&lt;br /&gt;
What constitutes &amp;quot;sufficient review&amp;quot; can be defined in fine detail. It could be specified that messages modified by Alice need to have only review for terminology, but not necessarily for style; Charlie may belong to the group which needs to be reviewed on style, but not necessarily on context; Bob's reviews for style may be nice to have, but never blocking if missing. These decisions do not preclude released messages to be reviewed later on missing points, after higher priority reviews have been completed. The definition of sufficiency may be changed at any point, e.g. as team members get more experienced and require less review, without interfering with direct translation and review work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- (Here is one unorthodox possibility of using reviews by ascriptions. A random translator may want to keep an eye on what the reviewers change in the files he maintains. For example, to learn what are typical small errors that he makes while translating. Therefore, he himself reviews any modifications not made by him after his last review, and commits them. This will in no way interfere with &amp;quot;canonical&amp;quot; reviews, those considered at release time.) //--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In summary, with reviewing by ascriptions the lean efficiency of raw VCS operation is preserved while providing for great flexibility of review. All team members can be given commit access, no web or email detours are needed. There are no prescribed roles, but an equivalent of role assignment happens automatically at last possible moment, and can take into account both translators' and reviewers' abilities. There is no staging between completing and committing the translation, which enables translator to keep on polishing the translation undisturbed until the reviewer comes around. There is no inefficiency in handling small changes throughout many files, since single AS command commits all changes just as single VCS command would. AS in effect abstracts VCS, so general team members do not have to know the particularities of the underlying VCS. On commit operations, AS can also apply checks (e.g. decline to commit syntactically invalid PO files) and modifications (e.g. update translator's data in the PO header).&lt;br /&gt;
&lt;br /&gt;
== Ascription System in Pology ==&lt;br /&gt;
&lt;br /&gt;
[[Localization/Tools/Pology|Pology]] is a collection of various modular tools for supporting translation based on PO files. Among them is the script &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which implements an ascription system (AS); at present, it can use Subversion or Git as the underlying VCS. &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is still in experimental stage, so what follows is a brief description of how to use it in context of the KDE translation project. However, very little is truly specific to KDE; the only major assumption is that there exists a VCS repository with PO files of a given language grouped together, and that the translation team can use it without special restrictions.&lt;br /&gt;
&lt;br /&gt;
Very important for the AS is how branches are handled (in KDE, the rolling trunk and stable branches). AS can in principle be deployed by branch, but then there is the added complexity of porting translations between branches, which ascriptions should follow. Therefore, the AS implemented by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is currently limited to assumption that there is a single branch of translations at all times. The article [[Localization/Workflows/PO_Summit|&amp;quot;Translating in Summit&amp;quot;]] explains how a KDE translation team can set up and operate such a single branch, the summit, and this is the prerequisite for the following instructions. (Note that the summit system is useful on its own, and should be conductive to any kind of review workflow.)&lt;br /&gt;
&lt;br /&gt;
== Setting Up ==&lt;br /&gt;
&lt;br /&gt;
The summit branch for the language &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt; is positioned like this in the KDE repository:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            LANG/&lt;br /&gt;
                summit/&lt;br /&gt;
                    messages/&lt;br /&gt;
                    docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The team coordinator already has this part of the repository tree locally due to regular summit operations. For the same reason Pology is already set up. Setting up the ascription system is now simple. The file &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; is created in the root of the summit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# ---------------------------&lt;br /&gt;
# Global ascription settings.&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
&lt;br /&gt;
# The root of the ascription catalog tree.&lt;br /&gt;
ascript-root = ../summit-ascript&lt;br /&gt;
&lt;br /&gt;
# The underlying version control system.&lt;br /&gt;
version-control = svn&lt;br /&gt;
&lt;br /&gt;
# Data for updating catalog headers.&lt;br /&gt;
# - language code&lt;br /&gt;
language = LANG&lt;br /&gt;
# - full language name&lt;br /&gt;
language-team = LANGUAGE&lt;br /&gt;
# - email address of the team&lt;br /&gt;
team-email = kde-i18n-LANG@kde.org&lt;br /&gt;
&lt;br /&gt;
# Default commit message.&lt;br /&gt;
commit-message = Translation updates.&lt;br /&gt;
&lt;br /&gt;
# -----------------------&lt;br /&gt;
# Registered translators.&lt;br /&gt;
&lt;br /&gt;
[user-alice]&lt;br /&gt;
name = Alice Akmalryn&lt;br /&gt;
original-name = Алиса Акмалрин&lt;br /&gt;
email = alice.akmalryn@someplacenice.org&lt;br /&gt;
&lt;br /&gt;
[user-bob]&lt;br /&gt;
name = Bob Byomkin&lt;br /&gt;
original-name = Бобан Бјомкин&lt;br /&gt;
email = bob.byomkin@otherplacenice.org&lt;br /&gt;
&lt;br /&gt;
# ...and so on.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;ascript-root&amp;lt;/tt&amp;gt; setting should be exactly &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt;, for the reason mentioned later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit-message&amp;lt;/tt&amp;gt; field, if defined, allows team members to commit without providing a commit message. The value given by this field will be used by default, with translator's user name appended to the end in special syntax. For example: &amp;lt;tt&amp;gt;Translation updates. [&amp;gt;alice]&amp;lt;/tt&amp;gt;. (Translator's user name is also appended to manually supplied commit messages.) Translators can still supply a commit message when they wish, as shown later. If this field is not set, the commit message is supplied as usual on committing.&lt;br /&gt;
&lt;br /&gt;
* Team members are defined by &amp;lt;tt&amp;gt;[user-USERNAME]&amp;lt;/tt&amp;gt; sections. Ascription user names can be any valid ASCII identifier: ASCII letters, digits and underscores only, digit cannot be the first character. Ascription user names have no technical relation to the underlying VCS accounts, though it is mnemonically convenient if they are the same (in case of SVN). This means that a translator who does not have a VCS account (yet) can and should be added here, with assigned user name (best one suitable as SVN account name later); why this should be done will be explained later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field in user sections is there in case the preferred renderings of the name in English and in target language are not the same. When this is not the case, &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; can be omitted.&lt;br /&gt;
&lt;br /&gt;
As soon as the &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; file is committed, the ascription system is ready for operation. Only regular modifications to this file are those of adding new team members. (On the other hand, team members should never be removed, because even after they no longer contribute, their ascription records remain in the system.)&lt;br /&gt;
&lt;br /&gt;
=== Initial Ascription ===&lt;br /&gt;
&lt;br /&gt;
The most common situation at start of ascription workflow is that there already exists a body of translations, contributed to by many different people over time. The coordinator should ascribe all existing translations as initial modifications, but to whom? It cannot be said precisely who translated what. The solution is to introduce a generic user in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;, suitably known as &amp;quot;Unknown Hero&amp;quot; (or &amp;quot;Lost Translator&amp;quot;, you can be inventive):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[user-uhero]&lt;br /&gt;
name = Unknown Hero&lt;br /&gt;
original-name = Незнани јунак&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ascribe all existing translations as modified and reviewed by this user. The coordinator does this with the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe commit -u uhero --all-reviewed -C LANG/summit/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; is the ascription mode, and the &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option provides the user name to which ascriptions are made. This is an important point: ascriptions are made to a user defined in ascription configuration, and have nothing to do with VCS accounts; someone who has the account can commit in the name of someone who does not. It is the &amp;lt;tt&amp;gt;--all-reviewed&amp;lt;/tt&amp;gt; option that declares all messages to be reviewed as well (note that it is normally used only this once, and not for normal day to day reviewing). The &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option prevent automatic committing by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which is useful for this initial step. Finally the paths which contain all summit catalogs are given.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command is issued, a progress bar will appear, and the following output will start to unfold:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
LANG/summit/messages/extragear-base/rellinks.po  (50/50)&lt;br /&gt;
LANG/summit/messages/extragear-base/autorefresh.po  (13/13)&lt;br /&gt;
LANG/summit/messages/extragear-base/babelfish.po  (38/38)&lt;br /&gt;
...&lt;br /&gt;
LANG/summit/messages/qt/libphonon.po  (13/13)&lt;br /&gt;
LANG/summit/messages/qt/phonon-xine.po  (24/24)&lt;br /&gt;
LANG/summit/messages/qt/phonon_gstreamer.po  (12/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated    111775    111775&lt;br /&gt;
fuzzy          26943     26943&lt;br /&gt;
obsolete/t      2965      2965&lt;br /&gt;
obsolete/f      1626      1626&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number in parenthesis indicates how many messages have been ascribed in the given PO file (modified/reviewed), and at the end the totals are given. Ascribing the complete summit for the first time will take quite some time (on the order of 10-20 minutes).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--If, on the contrary, it is known who translated and reviewed what, ascription can be performed piece-wise with user names of real translators:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support/LANG/summit&lt;br /&gt;
$ poascribe commit -u alice --all-reviewed -C kdelibs/ kdepimlibs/ kdebase/&lt;br /&gt;
$ poascribe commit -u bob --all-reviewed -C kdemultimedia/ kdeutils/&lt;br /&gt;
$ ...&lt;br /&gt;
&amp;lt;/code&amp;gt;//--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the initial ascription has been made, the ascription tree will appear next to the summit tree. This tree will contain one ascription PO file for each summit PO file, with the same name and relative location within the tree:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
        summit-ascript/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ascription tree can now be committed as usual (&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will have already added it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit-ascript/ -m &amp;quot;Initial ascription.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Translators ==&lt;br /&gt;
&lt;br /&gt;
Team members other than the coordinator, whether translators or reviewers, need to keep around only the &amp;lt;tt&amp;gt;trunk/l10n-support/LANG/&amp;lt;/tt&amp;gt; directory. But they always need to update this directory fully (rather than just one particular module or file under &amp;lt;tt&amp;gt;.../*messages/&amp;lt;/tt&amp;gt;), so that the summit tree and the ascription tree (and configuration) are kept in sync.&lt;br /&gt;
&lt;br /&gt;
In order not to have to issue their own user name (&amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;) all the time, translators can set it in Pology user configuration &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, in &amp;lt;tt&amp;gt;[poascribe]&amp;lt;/tt&amp;gt; section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = alice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translators can then submit updated PO files simply by substituting &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt; (or whatever the VCS commit command is) with &amp;lt;tt&amp;gt;poascribe commit&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;co&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;ci&amp;lt;/tt&amp;gt; for short):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdefoo/*fooapp*.po&lt;br /&gt;
LANG/summit/messages/kdefoo/fooapp.po  (144)&lt;br /&gt;
LANG/summit/messages/kdefoo/libfooapp.po  (25)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified&lt;br /&gt;
translated       169&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/libfooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/libfooapp.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1267069.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will add ascription records into ascription catalogs corresponding to summit catalogs to be committed, and commit them all. Like &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt; can take any number of file or directory paths, and can be issued from any working directory (it will always find ascription catalogs). If default commit message has not been set in the ascription configuration, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will ask for it; or it can be given in command line through &amp;lt;tt&amp;gt;-m&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
=== Translators Without Commit Access ===&lt;br /&gt;
&lt;br /&gt;
With the ascription system in place, every regular team member should have commit access. But, there may be some period of time before new translators are given accounts, revision control may be too technical for some, and even those with the account may not be able to commit temporarily for some reason.&lt;br /&gt;
&lt;br /&gt;
These translators may send in their work by email, to ''any'' team member with commit access (not necessarily the coordinator or a reviewer); this team member can commit received files without any review, as review can be conducted at any later time. If Bob sends some files to Alice, she can commit them immediately by stating Bob's user name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -u bob ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, the translator who sent in the files has to be defined in the ascription configuration. There are no hidden costs or security issues to this (as opposed to opening a VCS account), so every new translator should be defined there before any work of that person is committed.&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Reviewers ==&lt;br /&gt;
&lt;br /&gt;
The ascription system opens up all sorts of possibilities for concrete review patterns. Reviewers should keep in mind that for each message the full modification and review history is available, so that the team can think about how to make good use of it. Therefore, what follows are some examples to illustrate the review facilities that &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; provides.&lt;br /&gt;
&lt;br /&gt;
=== Basic Reviewing ===&lt;br /&gt;
&lt;br /&gt;
At the very basic level (which is the only level in classical review by stages), messages can be classified into simply unreviewed and reviewed, without further qualifiers. Alice now wants to review all unreviewed messages in a group of PO files, say &amp;lt;tt&amp;gt;kdetoys&amp;lt;/tt&amp;gt; module. She issues (&amp;lt;tt&amp;gt;di&amp;lt;/tt&amp;gt; is short for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe di LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===== Diffed for review: 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unreviewed messages have now been marked and diffed, inside the listed PO files. What is this about &amp;quot;diffing&amp;quot;? If the files had already been reviewed before, some of the messages modified since then (those marked for review) may have changed very little (e.g. a few words in a paragraph-length message, or even just punctuation). Therefore, for each message marked for review, Alice also wants to see the diff since last review to current version. Here are two messages in typical review states added by &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: charlie:m&lt;br /&gt;
#: gui/mainwindow.cc:372&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;GAME OVER. {-You won-}{+Tie+}!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KRAJ IGRE. {-Pobeda-}{+Nerešeno+}!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: bob:m charlie:m&lt;br /&gt;
#: game-state.cpp:117&lt;br /&gt;
#, ediff-total&lt;br /&gt;
msgid &amp;quot;Click the pause button again to resume the game.&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Kliknite ponovo na dugme pauze da nastavite igru.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the first one in Kate:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_poascribe_diff_01.png|center|Message diffed for review by poascribe in Kate.]]&lt;br /&gt;
&lt;br /&gt;
In the first message, the first to note is the &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment. This comment succinctly lists who did what with the message since the last review; here &amp;lt;tt&amp;gt;charlie:m&amp;lt;/tt&amp;gt; means that Charlie is the one who modified it. Then, there is the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, which alice can use it to jump through messages marked for review. Finally, the original and translation have been diffed; here they show that, since the last review, the message was fuzzied by changing &amp;quot;You won&amp;quot; to &amp;quot;Tie&amp;quot;, and what Charlie did in translation to unfuzzy it. Even on a message as short as this, the diff tells something useful to Alice: the phrase &amp;quot;Game over&amp;quot; likely has a formulaic translation, and the fact that it is not part of the diff means that the earlier reviewer had made sure it is consistent, so Alice does not have to check that.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment of the second message reveals that both Charlie and Bob had been translating it. &amp;lt;tt&amp;gt;ediff-total&amp;lt;/tt&amp;gt; flag instead of plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; means that this message had no review at all up to now, so there are no embedded diffs in text fields.&lt;br /&gt;
&lt;br /&gt;
Alice can now go through marked files and messages, review translations, and possibly make modifications. When making changes in a message with embedded diffs, she can freely edit text outside of difference segments and within &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments (as these are the ones which belong to current version of the text). While reviewing, Alice does ''not'' remove any of the added message elements while reviewing (save for an occasional difference segment, when translation should be modified), as these elements are needed for later. If a message is particularly hard and Alice wants to defer its review for later, she can add the &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; for short) flag to it.&lt;br /&gt;
&lt;br /&gt;
Once the review is complete, Alice simply commits the reviewed files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/kdetoys/&lt;br /&gt;
LANG/summit/messages/kdegames/bovo.po  (0/2)&lt;br /&gt;
LANG/summit/messages/kdegames/kdiamond.po  (0/7)&lt;br /&gt;
LANG/summit/messages/kdegames/palapeli.po  (3/12)&lt;br /&gt;
===== Ascription summary:&lt;br /&gt;
-           modified  reviewed&lt;br /&gt;
translated         3        21&lt;br /&gt;
Sending      LANG/summit/messages/kdegames/palapeli.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/bovo.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/kdiamond.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/palapeli.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1284220.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three things have happened here. First, all review states (flags, embedded diffs, etc.) have been removed, restoring the PO file to normal. Then, any modifications that Alice have made during review are ascribed to her (here 3 out of 21 messages). Finally, all marked messages are ascribed as reviewed by Alice (any with &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; flags would have been omitted here). When committing, the only summit catalog that got committed is the one with modifications made during review, and all the ascription catalogs were committed because of the reviews recorded in them.&lt;br /&gt;
&lt;br /&gt;
When many files with few changes in each are to be reviewed, it becomes burdensome to manually open each and every diffed for review, and then to make sure that all are committed with &amp;lt;tt&amp;gt;poascribe ci&amp;lt;/tt&amp;gt;. To make this easier, &amp;lt;tt&amp;gt;-w torevivew.out&amp;lt;/tt&amp;gt; option can be added to &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;, which requests that paths of all diffed PO files are written into &amp;lt;tt&amp;gt;torevivew.out&amp;lt;/tt&amp;gt; file. This file can then be used to batch open POs for review in the editor, as well as fed back on &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;-f torevivew.out&amp;lt;/tt&amp;gt;. There is also the &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; option which causes &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; to directly open PO files in a PO editor (though this is currently applicable only to Lokalize). Putting it together, to efficiently review a whole bunch of small changes throughout many files, Alice can:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di PATHS... -w toreview.out -o lokalize&lt;br /&gt;
$ # ...only marked messages opened in Lokalize, review them...&lt;br /&gt;
$ poascribe ci -f toreview.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selecting Messages for Review ===&lt;br /&gt;
&lt;br /&gt;
Invocations of &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; without any options, as in the previous section, were actually equivalent to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; is issuing the message ''selector''. &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is the default selector for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt; mode, and stands for MODified-After-Review: it selects the earliest historical modification of the message after the last (or no) review of that message, if there is any such. By selecting a historical modification of the message, the diff from it to current version can be computed and embedded into the PO file, as in previous examples.&lt;br /&gt;
&lt;br /&gt;
There are various specialized selectors, and fall into two groups: ''shallow selectors'' and ''history selectors''. Shallow selectors look only into the current version of the message, and cannot select historical versions, which means that they cannot provide embedded diffs. History selectors (&amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is of this type) can select messages from history and provide diffs. Several selectors can be issued on the command line, and the message is selected only if all selectors select it. Shallow selectors are then normally used as a pre-filter for history selectors. For example, to select messages modified after last reviewed, but only those found in stable branch, &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; selectors are chained:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s branch:stable -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that the history selector is given last, because the last selector determines which historical message is selected. If the ordering had been reversed here, same messages would get selected, but they would not have embedded diffs, because &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; is a shallow selector.&lt;br /&gt;
&lt;br /&gt;
Selectors can take parameters themselves, like &amp;lt;tt&amp;gt;branch:stable&amp;lt;/tt&amp;gt; in the previous example. Parameters are separated from the selector name by any non-alphanumeric character; this is colon by convention, but if a parameter contains a colon, something like slash, tilde, etc. can be used. Number of parameters can be variable, and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; in particular can take from none to three. If Alice wants to review only those messages modified ''by Charlie'' since last review, she states this by first argument to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:charlie PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Alice does not give too much credit to other reviewers, she can request selection of messages modified after last review ''by her'' with second parameter to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar::alice PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the first parameter (&amp;quot;modified by...&amp;quot;), which is not needed, must be explicitly skipped, before going to the second parameter (&amp;quot;reviewed by...&amp;quot;). The third optional parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; will be mentioned in the next section.&lt;br /&gt;
&lt;br /&gt;
When a selector parameter is a user name, normally it can also be a comma-separated list of user names (&amp;lt;tt&amp;gt;modar:bob,charlie&amp;lt;/tt&amp;gt;) or prefixed with tilde to negate, i.e. select all other users (&amp;lt;tt&amp;gt;modar:~alice&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Any selector can be negated by prepending &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; to its name. For example, the history selector &amp;lt;tt&amp;gt;modafter:DATE&amp;lt;/tt&amp;gt; selects first modification after the given date; to select messages modified after last review, but only if modified during June 2010:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modafter:2010-06 -s nmodafter:2010-07 -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Negating a history selector produces a shallow selector: while &amp;lt;tt&amp;gt;modafter&amp;lt;/tt&amp;gt; is history selector, &amp;lt;tt&amp;gt;nmodafter&amp;lt;/tt&amp;gt; is shallow. But the order of the two in the previous command line is not important, as the last selector is the usual &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selectors can be issued in other modes too. If the PO file is big and Alice has reviewed messages up to and including entry 246 when she has to pause until another day, she can commit reviews only up to this entry by issuing the &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; selector:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci -s espan::246 PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the first parameter to &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; is the first entry number, given if messages are not to be selected from the first). There is also the counterpart &amp;lt;tt&amp;gt;lspan&amp;lt;/tt&amp;gt; selector, which works with referent line numbers (those of &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; keywords) instead of entry numbers.&lt;br /&gt;
&lt;br /&gt;
=== Fine-Grained Reviews ===&lt;br /&gt;
&lt;br /&gt;
In the introduction, several distinct types of what can go wrong in translation were described. Not all reviewers may be able to check translation against all those problems. Here is a typical scenario of this kind:&lt;br /&gt;
&lt;br /&gt;
Alice is very computer-savvy and knows the translation project inside and out, which means that she can review well for context, terminology, and technical style. But, her language style leaves something to be desired, which shows through longer sentences and passages. Dan, on the other hand, is a very literary person, but not that much into the technical aspects. Dan's style reviews would thus be a perfect complement to Alice's general reviews.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; can support this scenario in the following way. A ''review type'' tag for language style is defined in the ascription configuration, using the &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[global]&lt;br /&gt;
...&lt;br /&gt;
review-tags = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The value to &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; is a space-separated list of identifiers, when more than one special review type is needed.) With this addition to configuration, Alice can continue to review as she did before, without any changes to her workflow.&lt;br /&gt;
&lt;br /&gt;
Dan selects messages for review similarly to Alice, but aditionally giving the &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; tag as ''third'' parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;, and indicating that ascribed reviews should be tagged as &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:::lstyle -t lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After finishing the review, Dan commits as usual:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Dan is always going to review the language style, in order not to have to issue the selector and tag in the command line all the time, he can make them default per mode in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = dan&lt;br /&gt;
selectors/diff = modar:::lstyle&lt;br /&gt;
tags/diff = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this Dan can use plain &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; just like Alice does.&lt;br /&gt;
&lt;br /&gt;
The important point of review tags is that they make reviews by types independent. For example, Dan may come around to review the language style of the given message after several modifications and general reviews have been ascribed to it -- &amp;lt;tt&amp;gt;modar:::lstyle&amp;lt;/tt&amp;gt; will simply ignore all reviews except for &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews. This is going to be reflected in the &amp;lt;tt&amp;gt;ascto:&amp;lt;/tt&amp;gt; comment to marked messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: charlie:m alice:r bob:m&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here Alice has made one review between Charlie's and Bob's modifications, and that review, being general instead of &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;, did not cause &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; to stop at it. After Dan reviews this message for language style, Alice runs selection for review and gets this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: bob:m dan:r(lstyle)&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, since &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews do not mix with general reviews, Dan's review did not hide Bob's modification that Alice did not check so far.&lt;br /&gt;
&lt;br /&gt;
(General review too has a tag assigned, the empty string, in case the reviewer needs to explicitly issue it in some context.)&lt;br /&gt;
&lt;br /&gt;
== Daily Use for The Coordinator ==&lt;br /&gt;
&lt;br /&gt;
After setting up the ascription system, the team coordinator should have to do very little to maintain it.&lt;br /&gt;
&lt;br /&gt;
=== Ascribing Merges ===&lt;br /&gt;
&lt;br /&gt;
Modifications made to summit catalogs by merging with templates must also be ascribed. Therefore, after merging the summit (&amp;lt;tt&amp;gt;posummit ... merge ...&amp;lt;/tt&amp;gt;) the coordinator substitutes the VCS command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command in &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe ci LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the user is not explicitly given by &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option, this will ascribe merge modifications to the coordinator (more precisely, to the user set as default in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;), which is just fine. It is also possible to define a special user only for ascribing merge modifications, though there is no known advantage to that.&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option is not issued, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will automatically commit all modified summit and ascription catalogs when done.&lt;br /&gt;
&lt;br /&gt;
=== Shuffling Ascription Catalogs  ===&lt;br /&gt;
&lt;br /&gt;
Sometimes summit catalogs are shuffled in the repository: moved to another module, renamed, one catalog split into two, two catalogs merged into one. Such shuffling should be exactly mirrored in the ascription tree, and this too is done on the repository side, at the same time. This relies on the ascription root being set exactly to &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt; in the ascription configuration. So the team coordinator has nothing special to do here.&lt;br /&gt;
&lt;br /&gt;
If instead in the central KDE repository the translation team is working in an external repository, by consequence the ascription system must be set up in that repository. But so long as &amp;lt;tt&amp;gt;process_orphans.sh&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; is used to shuffle catalogs in the external repository as well, the ascription catalogs will be properly handled.&lt;br /&gt;
&lt;br /&gt;
== Filtering for Release ==&lt;br /&gt;
&lt;br /&gt;
The last component of the ascription system is how to prevent insufficiently reviewed messages from leaking into a release. In context of Pology and summit workflow, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; itself is used directly to this end. Instead, in the summit configuration (as opposed to ascription configuration), the team coordinator defines filters which pass messages by applying selectors.&lt;br /&gt;
&lt;br /&gt;
Each top level PO tree has its own summit configuration file, named &amp;lt;tt&amp;gt;MSGTREE.extras.summit&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            messages.extras.summit&lt;br /&gt;
            docmessages/&lt;br /&gt;
            docmessages.extras.summit&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the simple case of all reviews being general reviews, the filter is added to summit configuration like this (anywhere within &amp;lt;tt&amp;gt;*.extras.summit&amp;lt;/tt&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the filter is named &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;, and is defined as application of &amp;lt;tt&amp;gt;nmodar&amp;lt;/tt&amp;gt; selector, the negation of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;. This simply means: pass all messages ''not'' modified after the last review.&lt;br /&gt;
&lt;br /&gt;
When the team coordinator scatters to branches (executes &amp;lt;tt&amp;gt;posummit scatter&amp;lt;/tt&amp;gt;), messages from summit POs which do not pass this filter will not be sent to branch POs. The count of stopped messages by branch PO will be reported in the output as scattering proceeds.&lt;br /&gt;
&lt;br /&gt;
Why did we have to name the filter &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;? (Those knowing some Python will also notice that it is defined as a list element.) Because it is possible to define more than one filter, and select which one is used on each scattering. For example, the coordinator may wish that, when the release is near and time is short to review everything, messages from a few experienced translators can be passed into release without review. If those translators are Alice and Bob, an &amp;quot;emergency&amp;quot; filter can be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; uses the first filter in the list. When the coordinator needs to do emergency scattering, he requests the emergency filter by the &amp;lt;tt&amp;gt;-a&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter -a emergency&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What if several selectors are needed to pass the message? For example, the language style review (the earlier example with Alice and Dan) too may be requested for regular scattering, but omitted from emergency scattering. The filter setup for this scenario looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;, &amp;quot;nmodar:::lstyle&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The regular filter now reads: pass the message if it has not been modified after the last (general) review ''and'' has not been modified after the last style review.&lt;br /&gt;
&lt;br /&gt;
Simple combination of predefined selectors by AND-conditions may not be sufficient for more involved scenarios. When this is the case, the coordinator may write (or ask someone to write) a custom selector in Python, and plug it in as the second element in the filter tuple (instead of the list of predefined selectors).&lt;br /&gt;
&lt;br /&gt;
=== Writing a Selector Function ===&lt;br /&gt;
&lt;br /&gt;
((To be written.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-05-13T10:15:18Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Stray Cyrillic text in the example.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading'', ''approving''), each of which may return the translation to a previous stage, or forward it to some special stage. The process can also be more finer grained, where each message in the file goes through stages separately.&lt;br /&gt;
&lt;br /&gt;
Regardless of the particularities, workflows of this kind all have the following in common. Members of the translation team are assigned ''roles'' -- such as ''translator'', ''reviewer'', ''approver'', ''committer'' -- by which they enter into the workflow (single person can have more roles). The later review stages must wait for the earlier stages to complete, and the translation cannot be updated again before the current version clears the pipeline (or the pipeline is aborted). Most importantly, once the translation is committed, it becomes part of simply &amp;quot;admitted&amp;quot; translations, with no further qualifiers.&lt;br /&gt;
&lt;br /&gt;
The system of prescribed roles requires that team members assign them between themselves, stick to them, and shuffle them along the way. The prescribed review pipeline requires a tool to enforce and keep track of the stages in which translations are. This makes the review workflow complex and rigid, most probably with choke points for efficiency. Distribution of roles may become disbalanced by people coming and going, or the workflow tool may be prohibitive to some scenarios (e.g. single translator making small adjustments in dozens of files across the project, but having to upload each manually through a web interface).&lt;br /&gt;
&lt;br /&gt;
Of course, &amp;quot;rigid&amp;quot;, &amp;quot;complex&amp;quot;, &amp;quot;inefficient&amp;quot;, are comparative qualifications, so what is it that the classical review by stages can be compared to in this way?&lt;br /&gt;
&lt;br /&gt;
== Reviewing by Ascriptions ==&lt;br /&gt;
&lt;br /&gt;
Reviewing by ascriptions is even simpler conceptually, and yet less rigid, less complex, and much more efficient than the review by stages. It works on the message-level, rather than file-level. Anyone can simply translate some messages and directly commit modified files, without any review, but with ''ascribing'' modifications to own name. Anyone can review any committed messages at any moment, commit the modifications-on-review and ascribe reviews to own name and (possibly) to certain class -- full review, review of context, of terminology, of style, etc. Only when the translation is to be shipped to end users, the ''insufficiently'' reviewed messages are automatically omitted from the package, by evaluating the ''ascription history'' of each message.&lt;br /&gt;
&lt;br /&gt;
Most importantly, based on the ascription history, the reviewer can select only some particular messages, and review only the difference between their historical and current versions. For example, Alice can select to review only messages modified since she or Bob had last reviewed them for style; she could see the difference from that last review to current version, e.g. if in the whole paragraph only a single word has changed by Charlie when he reviewed the terminology. In terms of PO workflow, the ascription history propagates through merges, so the reviewer can compare the change in original and the change in translation since the last review, to judge if one fits the other.&lt;br /&gt;
&lt;br /&gt;
Since everyone just commits, translations can be efficiently kept in a version control repository, with the ascription system added on top. After having done some translating, the team member simply substitutes commit command of the version control system (VCS) with ascribe-modifications command of the ascription system (AS, which calls the underlying VCS internally). After reviewing, the team member uses ascribe-reviews command of the AS to commit reviews to ascription history (as well as modifications made during the review). To select messages for review, the team member issues diff-for-review command of the AS (with suitable parameters to narrow the set) and selected messages are marked in-place in PO files and [[Localization/Tools/Pology/PO_Embedded_Diffing|embedded with differences]], and possibly popped open in a PO editor.&lt;br /&gt;
&lt;br /&gt;
When the translations are to be released, the team coordinator issues filter-for-release command of the AS, which takes the working PO files and creates final PO files with insufficiently reviewed messages removed. &amp;quot;Release time&amp;quot; is used here only figuratively: this should be a fully automatic process, so it can be performed at any interval of convenience.&lt;br /&gt;
&lt;br /&gt;
What constitutes &amp;quot;sufficient review&amp;quot; can be defined in fine detail. It could be specified that messages modified by Alice need to have only review for terminology, but not necessarily for style; Charlie may belong to the group which needs to be reviewed on style, but not necessarily on context; Bob's reviews for style may be nice to have, but never blocking if missing. These decisions do not preclude released messages to be reviewed later on missing points, after higher priority reviews have been completed. The definition of sufficiency may be changed at any point, e.g. as team members get more experienced and require less review, without interfering with direct translation and review work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- (Here is one unorthodox possibility of using reviews by ascriptions. A random translator may want to keep an eye on what the reviewers change in the files he maintains. For example, to learn what are typical small errors that he makes while translating. Therefore, he himself reviews any modifications not made by him after his last review, and commits them. This will in no way interfere with &amp;quot;canonical&amp;quot; reviews, those considered at release time.) //--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In summary, with reviewing by ascriptions the lean efficiency of raw VCS operation is preserved while providing for great flexibility of review. All team members can be given commit access, no web or email detours are needed. There are no prescribed roles, but an equivalent of role assignment happens automatically at last possible moment, and can take into account both translators' and reviewers' abilities. There is no staging between completing and committing the translation, which enables translator to keep on polishing the translation undisturbed until the reviewer comes around. There is no inefficiency in handling small changes throughout many files, since single AS command commits all changes just as single VCS command would. AS in effect abstracts VCS, so general team members do not have to know the particularities of the underlying VCS. On commit operations, AS can also apply checks (e.g. decline to commit syntactically invalid PO files) and modifications (e.g. update translator's data in the PO header).&lt;br /&gt;
&lt;br /&gt;
== Ascription System in Pology ==&lt;br /&gt;
&lt;br /&gt;
[[Localization/Tools/Pology|Pology]] is a collection of various modular tools for supporting translation based on PO files. Among them is the script &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which implements an ascription system (AS); at present, it can use Subversion or Git as the underlying VCS. &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is still in experimental stage, so what follows is a brief description of how to use it in context of the KDE translation project. However, very little is truly specific to KDE; the only major assumption is that there exists a VCS repository with PO files of a given language grouped together, and that the translation team can use it without special restrictions.&lt;br /&gt;
&lt;br /&gt;
Very important for the AS is how branches are handled (in KDE, the rolling trunk and stable branches). AS can in principle be deployed by branch, but then there is the added complexity of porting translations between branches, which ascriptions should follow. Therefore, the AS implemented by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is currently limited to assumption that there is a single branch of translations at all times. The article [[Localization/Workflows/PO_Summit|&amp;quot;Translating in Summit&amp;quot;]] explains how a KDE translation team can set up and operate such a single branch, the summit, and this is the prerequisite for the following instructions. (Note that the summit system is useful on its own, and should be conductive to any kind of review workflow.)&lt;br /&gt;
&lt;br /&gt;
== Setting Up ==&lt;br /&gt;
&lt;br /&gt;
The summit branch for the language &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt; is positioned like this in the KDE repository:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            LANG/&lt;br /&gt;
                summit/&lt;br /&gt;
                    messages/&lt;br /&gt;
                    docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The team coordinator already has this part of the repository tree locally due to regular summit operations. For the same reason Pology is already set up. Setting up the ascription system is now simple. The file &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; is created in the root of the summit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# ---------------------------&lt;br /&gt;
# Global ascription settings.&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
&lt;br /&gt;
# The root of the ascription catalog tree.&lt;br /&gt;
ascript-root = ../summit-ascript&lt;br /&gt;
&lt;br /&gt;
# The underlying version control system.&lt;br /&gt;
version-control = svn&lt;br /&gt;
&lt;br /&gt;
# Data for updating catalog headers.&lt;br /&gt;
# - language code&lt;br /&gt;
language = LANG&lt;br /&gt;
# - full language name&lt;br /&gt;
language-team = LANGUAGE&lt;br /&gt;
# - email address of the team&lt;br /&gt;
team-email = kde-i18n-LANG@kde.org&lt;br /&gt;
&lt;br /&gt;
# Default commit message.&lt;br /&gt;
commit-message = Translation updates.&lt;br /&gt;
&lt;br /&gt;
# -----------------------&lt;br /&gt;
# Registered translators.&lt;br /&gt;
&lt;br /&gt;
[user-alice]&lt;br /&gt;
name = Alice Akmalryn&lt;br /&gt;
original-name = Алиса Акмалрин&lt;br /&gt;
email = alice.akmalryn@someplacenice.org&lt;br /&gt;
&lt;br /&gt;
[user-bob]&lt;br /&gt;
name = Bob Byomkin&lt;br /&gt;
original-name = Бобан Бјомкин&lt;br /&gt;
email = bob.byomkin@otherplacenice.org&lt;br /&gt;
&lt;br /&gt;
# ...and so on.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;ascript-root&amp;lt;/tt&amp;gt; setting should be exactly &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt;, for the reason mentioned later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit-message&amp;lt;/tt&amp;gt; field, if defined, allows team members to commit without providing a commit message. The value given by this field will be used by default, with translator's user name appended to the end in special syntax. For example: &amp;lt;tt&amp;gt;Translation updates. [&amp;gt;alice]&amp;lt;/tt&amp;gt;. (Translator's user name is also appended to manually supplied commit messages.) Translators can still supply a commit message when they wish, as shown later. If this field is not set, the commit message is supplied as usual on committing.&lt;br /&gt;
&lt;br /&gt;
* Team members are defined by &amp;lt;tt&amp;gt;[user-USERNAME]&amp;lt;/tt&amp;gt; sections. Ascription user names can be any valid ASCII identifier: ASCII letters, digits and underscores only, digit cannot be the first character. Ascription user names have no technical relation to the underlying VCS accounts, though it is mnemonically convenient if they are the same (in case of SVN). This means that a translator who does not have a VCS account (yet) can and should be added here, with assigned user name (best one suitable as SVN account name later); why this should be done will be explained later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field in user sections is there in case the preferred renderings of the name in English and in target language are not the same. When this is not the case, &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; can be omitted.&lt;br /&gt;
&lt;br /&gt;
As soon as the &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; file is committed, the ascription system is ready for operation. Only regular modifications to this file are those of adding new team members. (On the other hand, team members should never be removed, because even after they no longer contribute, their ascription records remain in the system.)&lt;br /&gt;
&lt;br /&gt;
=== Initial Ascription ===&lt;br /&gt;
&lt;br /&gt;
The most common situation at start of ascription workflow is that there already exists a body of translations, contributed to by many different people over time. The coordinator should ascribe all existing translations as initial modifications, but to whom? It cannot be said precisely who translated what. The solution is to introduce a generic user in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;, suitably known as &amp;quot;Unknown Hero&amp;quot; (or &amp;quot;Lost Translator&amp;quot;, you can be inventive):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[user-uhero]&lt;br /&gt;
name = Unknown Hero&lt;br /&gt;
original-name = Незнани јунак&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ascribe all existing translations as modified and reviewed by this user. The coordinator does this with the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe reviewed -u uhero -C LANG/summit/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;tt&amp;gt;reviewed&amp;lt;/tt&amp;gt; is the ascription mode, and the &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option provides the user name to which ascriptions are made. This is an important point: ascriptions are made to a user defined in ascription configuration, and have nothing to do with VCS accounts; someone who has the account can commit in the name of someone who does not. The &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option prevent automatic committing by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which is useful for this initial step. Finally the paths which contain all summit catalogs are given.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command is issued, a progress bar will appear, and the following output will start to unfold:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/rellinks.po  (50)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/autorefresh.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/babelfish.po  (38)&lt;br /&gt;
...&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/libphonon.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon-xine.po  (24)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon_gstreamer.po  (12)&lt;br /&gt;
===! Translated: 111775&lt;br /&gt;
===! Fuzzy: 26943&lt;br /&gt;
===! Obsolete translated: 2965&lt;br /&gt;
===! Obsolete fuzzy: 1626&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/rellinks.po  (50)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/autorefresh.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/babelfish.po  (38)&lt;br /&gt;
...&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/libphonon.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon-xine.po  (24)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon_gstreamer.po  (12)&lt;br /&gt;
===! Reviewed: 143309&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number in parenthesis indicates how many messages have been ascribed in the given PO file, and at the end the totals are given. Catalogs are processed twice, first to ascribe modifications and then reviews, because a review cannot be ascribed before the modification has been ascribed. Ascribing the complete summit for the first time will take quite some time (say 15-30 minutes).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--If, on the contrary, it is known who translated-reviewed what, ascription can be performed piece-wise with user names of real translators:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support/LANG/summit&lt;br /&gt;
$ poascribe reviewed -u alice -C kdelibs/ kdepimlibs/ kdebase/&lt;br /&gt;
$ poascribe reviewed -u bob -C kdemultimedia/ kdeutils/&lt;br /&gt;
$ ...&lt;br /&gt;
&amp;lt;/code&amp;gt;//--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the initial ascription has been made, the ascription tree will appear next to the summit tree. This tree will contain one ascription PO file for each summit PO file, with the same name and relative location within the tree:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
        summit-ascript/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ascription tree can now be committed as usual (&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will have already added it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit-ascript/ -m &amp;quot;Initial ascription.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Translators ==&lt;br /&gt;
&lt;br /&gt;
Team members other than the coordinator, whether translators or reviewers, need to keep around only the &amp;lt;tt&amp;gt;trunk/l10n-support/LANG/&amp;lt;/tt&amp;gt; directory. But they always need to update this directory fully (rather than just one particular module or file under &amp;lt;tt&amp;gt;.../*messages/&amp;lt;/tt&amp;gt;), so that the summit tree and the ascription tree (and configuration) are kept in sync.&lt;br /&gt;
&lt;br /&gt;
In order not to have to issue their own user name (&amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;) all the time, translators can set it in Pology user configuration &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, in &amp;lt;tt&amp;gt;[poascribe]&amp;lt;/tt&amp;gt; section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = alice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translators can then submit updated PO files simply by substituting &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt; (or whatever the VCS commit command is) with &amp;lt;tt&amp;gt;poascribe modified&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;mo&amp;lt;/tt&amp;gt; for short):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo LANG/summit/messages/kdefoo/*fooapp*.po&lt;br /&gt;
!    LANG/summit-ascript/messages/kdefoo/fooapp.po  (144)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdefoo/libfooapp.po  (25)&lt;br /&gt;
===! Translated: 169&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/libfooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/libfooapp.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1267069.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will add ascription records into ascription catalogs corresponding to summit catalogs to be committed, and commit them all. Like &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;poascribe mo&amp;lt;/tt&amp;gt; can take any number of file or directory paths, and can be issued from any working directory (it will always find ascription catalogs). If default commit message has not been set in the ascription configuration, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will ask for it; or it can be given in command line through &amp;lt;tt&amp;gt;-m&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
=== Translators Without Commit Access ===&lt;br /&gt;
&lt;br /&gt;
With the ascription system in place, every regular team member should have commit access. But, there may be some period of time before new translators are given accounts, revision control may be too technical for some, and even those with the account may not be able to commit temporarily for some reason.&lt;br /&gt;
&lt;br /&gt;
These translators may send in their work by email, to ''any'' team member with commit access (not necessarily the coordinator or a reviewer); this team member can commit received files without any review, as review can be conducted at any later time. If Bob sends some files to Alice, she can commit them immediately by stating Bob's user name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo -u bob ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, the translator who sent in the files has to be defined in the ascription configuration. There are no hidden costs or security issues to this (as opposed to opening a VCS account), so every new translator should be defined there before any work of that person is committed.&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Reviewers ==&lt;br /&gt;
&lt;br /&gt;
The ascription system opens up all sorts of possibilities for concrete review patterns. Reviewers should keep in mind that for each message the full modification and review history is available, so that the team can think about how to make good use of it. Therefore, what follows are some examples to illustrate the review facilities that &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; provides.&lt;br /&gt;
&lt;br /&gt;
=== Basic Reviewing ===&lt;br /&gt;
&lt;br /&gt;
At the very basic level (which is the only level in classical review by stages), messages can be classified into simply unreviewed and reviewed, without further qualifiers. Alice now wants to review all unreviewed messages in a group of PO files, say &amp;lt;tt&amp;gt;kdetoys&amp;lt;/tt&amp;gt; module. She issues (&amp;lt;tt&amp;gt;di&amp;lt;/tt&amp;gt; is short for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe di LANG/summit/messages/kdetoys/&lt;br /&gt;
!    LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Diffed for review: 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unreviewed messages have now been marked and diffed, inside the listed PO files. What is this about &amp;quot;diffing&amp;quot;? If the files had already been reviewed before, some of the messages modified since then (those marked for review) may have changed very little (e.g. a few words in a paragraph-length message, or even just punctuation). Therefore, for each message marked for review, Alice also wants to see the diff since last review to current version. Here are two messages in typical review states added by &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: charlie:m&lt;br /&gt;
#: gui/mainwindow.cc:372&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;GAME OVER. {-You won-}{+Tie+}!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KRAJ IGRE. {-Pobeda-}{+Nerešeno+}!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: bob:m charlie:m&lt;br /&gt;
#: game-state.cpp:117&lt;br /&gt;
#, ediff-total&lt;br /&gt;
msgid &amp;quot;Click the pause button again to resume the game.&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Kliknite ponovo na dugme pauze da nastavite igru.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the first one in Kate:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_poascribe_diff_01.png|center|Message diffed for review by poascribe in Kate.]]&lt;br /&gt;
&lt;br /&gt;
In the first message, the first to note is the &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment. This comment succinctly lists who did what with the message since the last review; here &amp;lt;tt&amp;gt;charlie:m&amp;lt;/tt&amp;gt; means that Charlie is the one who modified it. Then, there is the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, which alice can use it to jump through messages marked for review. Finally, the original and translation have been diffed; here they show that, since the last review, the message was fuzzied by changing &amp;quot;You won&amp;quot; to &amp;quot;Tie&amp;quot;, and what Charlie did in translation to unfuzzy it. Even on a message as short as this, the diff tells something useful to Alice: the phrase &amp;quot;Game over&amp;quot; likely has a formulaic translation, and the fact that it is not part of the diff means that the earlier reviewer had made sure it is consistent, so Alice does not have to check that.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment of the second message reveals that both Charlie and Bob had been translating it. &amp;lt;tt&amp;gt;ediff-total&amp;lt;/tt&amp;gt; flag instead of plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; means that this message had no review at all up to now, so there are no embedded diffs in text fields.&lt;br /&gt;
&lt;br /&gt;
Alice can now go through marked files and messages, review translations, and possibly make modifications. When making changes in a message with embedded diffs, she can freely edit text outside of difference segments and within &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments (as these are the ones which belong to current version of the text). While reviewing, Alice does ''not'' remove any of the added message elements while reviewing (save for an occasional difference segment, when translation should be modified), as these elements are needed for later. If a message is particularly hard and Alice wants to defer its review for later, she can add the &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;urev&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; for short) flag to it.&lt;br /&gt;
&lt;br /&gt;
Once the review is complete, Alice commits the reviewed files in &amp;lt;tt&amp;gt;reviewed&amp;lt;/tt&amp;gt; mode (short &amp;lt;tt&amp;gt;re&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re LANG/summit/messages/kdetoys/{bovo,kdiamond,palapeli}.po&lt;br /&gt;
!    LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Cleared reviews: 21&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/palapeli.po (3)&lt;br /&gt;
===! Translated: 3&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Reviewed: 21&lt;br /&gt;
Sending      LANG/summit/messages/kdegames/palapeli.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/bovo.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/kdiamond.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/palapeli.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1284220.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three things have happened here. First, all review states (flags, embedded diffs, etc.) have been removed, restoring the PO file to normal. Then, any modifications that Alice have made during review are ascribed to her (here 3 out of 21 messages). Finally, all marked messages are ascribed as reviewed by Alice (any with &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;urev&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; flags would have been omitted here). When committing, the only summit catalog that got committed is the one with modifications made during review, and all the ascription catalogs were committed because of the reviews recorded in them.&lt;br /&gt;
&lt;br /&gt;
When many files with few changes in each are to be reviewed, it becomes burdensome to manually open each and every diffed for review, and then to make sure that all are committed with &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt;. To make this easier, &amp;lt;tt&amp;gt;-w torevivew.out&amp;lt;/tt&amp;gt; option can be added to &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;, which requests that paths of all diffed PO files are written into &amp;lt;tt&amp;gt;torevivew.out&amp;lt;/tt&amp;gt; file. This file can then be used to batch open POs for review in the editor, as well as fed back on &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;-f torevivew.out&amp;lt;/tt&amp;gt;. There is also the &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; option which causes &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; to directly open PO files in a PO editor, though this is currently applicable only to Lokalize. Putting it together, to efficiently review a whole bunch of small changes throughout many files, Alice can:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di PATHS... -w toreview.out -o lokalize&lt;br /&gt;
$ # ...only marked messages opened in Lokalize, review them...&lt;br /&gt;
$ poascribe re -f toreview.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selecting Messages for Review ===&lt;br /&gt;
&lt;br /&gt;
Invocations of &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; without any options, as in the previous section, were actually equivalent to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; is issuing the message ''selector''. &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is the default selector for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt; mode, and stands for MODified-After-Review: it selects the earliest historical modification of the message after the last (or no) review of that message, if there is any such. By selecting a historical modification of the message, the diff from it to current version can be computed and embedded into the PO file, as in previous examples.&lt;br /&gt;
&lt;br /&gt;
There are various specialized selectors, and fall into two groups: ''shallow selectors'' and ''history selectors''. Shallow selectors look only into the current version of the message, and cannot select historical versions, which means that they cannot provide embedded diffs. History selectors (&amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is of this type) can select messages from history and provide diffs. Several selectors can be issued on the command line, and the message is selected only if all selectors select it. Shallow selectors are then normally used as a pre-filter for history selectors. For example, to select messages modified after last reviewed, but only those found in stable branch, &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; selectors are chained:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s branch:stable -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that the history selector is given last, because the last selector determines which historical message is selected. If the ordering had been reversed here, same messages would get selected, but they would not have embedded diffs, because &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; is a shallow selector.&lt;br /&gt;
&lt;br /&gt;
Selectors can take parameters themselves, like &amp;lt;tt&amp;gt;branch:stable&amp;lt;/tt&amp;gt; in the previous example. Parameters are separated from the selector name by any non-alphanumeric character; this is colon by convention, but if a parameter contains a colon, something like slash, tilde, etc. can be used. Number of parameters can be variable, and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; in particular can take from none to three. If Alice wants to review only those messages modified ''by Charlie'' since last review, she states this by first argument to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:charlie PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Alice does not give too much credit to other reviewers, she can request selection of messages modified after last review ''by her'' with second parameter to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar::alice PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the first parameter (&amp;quot;modified by...&amp;quot;), which is not needed, must be explicitly skipped, before going to the second parameter (&amp;quot;reviewed by...&amp;quot;). The third optional parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; will be mentioned in the next section.&lt;br /&gt;
&lt;br /&gt;
When a selector parameter is a user name, normally it can also be a comma-separated list of user names (&amp;lt;tt&amp;gt;modar:bob,charlie&amp;lt;/tt&amp;gt;) or prefixed with tilde to negate, i.e. select all other users (&amp;lt;tt&amp;gt;modar:~alice&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Any selector can be negated by prepending &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; to its name. For example, the history selector &amp;lt;tt&amp;gt;modafter:DATE&amp;lt;/tt&amp;gt; selects first modification after the given date; to select messages modified after last review, but only if modified during June 2010:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modafter:2010-06 -s nmodafter:2010-07 -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Negating a history selector produces a shallow selector: while &amp;lt;tt&amp;gt;modafter&amp;lt;/tt&amp;gt; is history selector, &amp;lt;tt&amp;gt;nmodafter&amp;lt;/tt&amp;gt; is shallow. But the order of the two in the previous command line is not important, as the last selector is the usual &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selectors can be issued in other modes too. If the PO file is big and Alice has reviewed messages up to and including entry 246 when she has to pause until another day, she can commit reviews only up to this entry by issuing the &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; selector:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re -s espan::246 PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the first parameter to &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; is the first entry number, given if messages are not to be selected from the first). There is also the counterpart &amp;lt;tt&amp;gt;lspan&amp;lt;/tt&amp;gt; selector, which works with referent line numbers (those of &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; keywords) instead of entry numbers.&lt;br /&gt;
&lt;br /&gt;
=== Fine-Grained Reviews ===&lt;br /&gt;
&lt;br /&gt;
In the introduction, several distinct types of what can go wrong in translation were described. Not all reviewers may be able to check translation against all those problems. Here is a typical scenario of this kind:&lt;br /&gt;
&lt;br /&gt;
Alice is very computer-savvy and knows the translation project inside and out, which means that she can review well for context, terminology, and technical style. But, her language style leaves something to be desired, which shows through longer sentences and passages. Dan, on the other hand, is a very literary person, but not that much into the technical aspects. Dan's style reviews would thus be a perfect complement to Alice's general reviews.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; can support this scenario in the following way. A ''review type'' tag for language style is defined in the ascription configuration, using the &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[global]&lt;br /&gt;
...&lt;br /&gt;
review-tags = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The value to &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; is a space-separated list of identifiers, when more than one special review type is needed.) With this addition to configuration, Alice can continue to review as she did before, without any changes to her workflow.&lt;br /&gt;
&lt;br /&gt;
Dan selects messages for review quite similarly to Alice, with the exception of giving the &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; tag as ''third'' parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:::lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When committing reviews, Dan must also state this tag, in order to ascribe reviews as of language style type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re -t lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Dan is always going to review the language style, in order not to have to issue the selector and tag in the command line all the time, he can make them default per mode in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = dan&lt;br /&gt;
selector/diff = modar:::lstyle&lt;br /&gt;
tag/reviewed = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this Dan can use plain &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt;, just like Alice does.&lt;br /&gt;
&lt;br /&gt;
The important point of review tags is that they make reviews by types independent. For example, Dan may come around to review the language style of the given message after several modifications and general reviews have been ascribed to it -- &amp;lt;tt&amp;gt;modar:::lstyle&amp;lt;/tt&amp;gt; will simply ignore all reviews except for &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews. This is going to be reflected in the &amp;lt;tt&amp;gt;ascto:&amp;lt;/tt&amp;gt; comment to marked messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: charlie:m alice:r bob:m&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here Alice has made one review between Charlie's and Bob's modifications, and that review, being general instead of &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;, did not cause &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; to stop at it. After Dan reviews this message for language style, Alice runs selection for review and gets this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: bob:m dan:r(lstyle)&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, since &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews do not mix with general reviews, Dan's review did not hide Bob's modification that Alice did not check so far.&lt;br /&gt;
&lt;br /&gt;
(General review too has a tag assigned, the empty string, in case the reviewer needs to explicitly issue it in some context.)&lt;br /&gt;
&lt;br /&gt;
== Daily Use for The Coordinator ==&lt;br /&gt;
&lt;br /&gt;
After setting up the ascription system, the team coordinator should have to do very little to maintain it.&lt;br /&gt;
&lt;br /&gt;
=== Ascribing Merges ===&lt;br /&gt;
&lt;br /&gt;
Modifications made to summit catalogs by merging with templates must also be ascribed. Therefore, after merging the summit (&amp;lt;tt&amp;gt;posummit ... merge ...&amp;lt;/tt&amp;gt;) the coordinator substitutes the VCS command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command in &amp;lt;tt&amp;gt;modified&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the user is not explicitly given by &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option, this will ascribe merge modifications to the coordinator (more precisely, to the user set as default in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;), which is just fine. It is also possible to define a special user only for ascribing merge modifications, though there is no known advantage to that.&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option is not issued, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will automatically commit all modified summit and ascription catalogs when done.&lt;br /&gt;
&lt;br /&gt;
=== Shuffling Ascription Catalogs  ===&lt;br /&gt;
&lt;br /&gt;
Sometimes summit catalogs are shuffled in the repository: moved to another module, renamed, one catalog split into two, two catalogs merged into one. Such shuffling should be exactly mirrored in the ascription tree, and this too is done on the repository side, at the same time. This relies on the ascription root being set exactly to &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt; in the ascription configuration. So the team coordinator has nothing special to do here.&lt;br /&gt;
&lt;br /&gt;
If instead in the central KDE repository the translation team is working in an external repository, by consequence the ascription system must be set up in that repository. But so long as &amp;lt;tt&amp;gt;process_orphans.sh&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; is used to shuffle catalogs in the external repository as well, the ascription catalogs will be properly handled.&lt;br /&gt;
&lt;br /&gt;
== Filtering for Release ==&lt;br /&gt;
&lt;br /&gt;
The last component of the ascription system is how to prevent insufficiently reviewed messages from leaking into a release. In context of Pology and summit workflow, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; itself is used directly to this end. Instead, in the summit configuration (as opposed to ascription configuration), the team coordinator defines filters which pass messages by applying selectors.&lt;br /&gt;
&lt;br /&gt;
Each top level PO tree has its own summit configuration file, named &amp;lt;tt&amp;gt;MSGTREE.extras.summit&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            messages.extras.summit&lt;br /&gt;
            docmessages/&lt;br /&gt;
            docmessages.extras.summit&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the simple case of all reviews being general reviews, the filter is added to summit configuration like this (anywhere within &amp;lt;tt&amp;gt;*.extras.summit&amp;lt;/tt&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the filter is named &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;, and is defined as application of &amp;lt;tt&amp;gt;nmodar&amp;lt;/tt&amp;gt; selector, the negation of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;. This simply means: pass all messages ''not'' modified after the last review.&lt;br /&gt;
&lt;br /&gt;
When the team coordinator scatters to branches (executes &amp;lt;tt&amp;gt;posummit scatter&amp;lt;/tt&amp;gt;), messages from summit POs which do not pass this filter will not be sent to branch POs. The count of stopped messages by branch PO will be reported in the output as scattering proceeds.&lt;br /&gt;
&lt;br /&gt;
Why did we have to name the filter &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;? (Those knowing some Python will also notice that it is defined as a list element.) Because it is possible to define more than one filter, and select which one is used on each scattering. For example, the coordinator may wish that, when the release is near and time is short to review everything, messages from a few experienced translators can be passed into release without review. If those translators are Alice and Bob, an &amp;quot;emergency&amp;quot; filter can be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; uses the first filter in the list. When the coordinator needs to do emergency scattering, he requests the emergency filter by the &amp;lt;tt&amp;gt;-a&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter -a emergency&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What if several selectors are needed to pass the message? For example, the language style review (the earlier example with Alice and Dan) too may be requested for regular scattering, but omitted from emergency scattering. The filter setup for this scenario looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;, &amp;quot;nmodar:::lstyle&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The regular filter now reads: pass the message if it has not been modified after the last (general) review ''and'' has not been modified after the last style review.&lt;br /&gt;
&lt;br /&gt;
Simple combination of predefined selectors by AND-conditions may not be sufficient for more involved scenarios. When this is the case, the coordinator may write (or ask someone to write) a custom selector in Python, and plug it in as the second element in the filter tuple (instead of the list of predefined selectors).&lt;br /&gt;
&lt;br /&gt;
=== Writing a Selector Function ===&lt;br /&gt;
&lt;br /&gt;
((To be written.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-01-28T15:18:07Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Eliminated mention of 'fuzzy' reserved user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading'', ''approving''), each of which may return the translation to a previous stage, or forward it to some special stage. The process can also be more finer grained, where each message in the file goes through stages separately.&lt;br /&gt;
&lt;br /&gt;
Regardless of the particularities, workflows of this kind all have the following in common. Members of the translation team are assigned ''roles'' -- such as ''translator'', ''reviewer'', ''approver'', ''committer'' -- by which they enter into the workflow (single person can have more roles). The later review stages must wait for the earlier stages to complete, and the translation cannot be updated again before the current version clears the pipeline (or the pipeline is aborted). Most importantly, once the translation is committed, it becomes part of simply &amp;quot;admitted&amp;quot; translations, with no further qualifiers.&lt;br /&gt;
&lt;br /&gt;
The system of prescribed roles requires that team members assign them between themselves, stick to them, and shuffle them along the way. The prescribed review pipeline requires a tool to enforce and keep track of the stages in which translations are. This makes the review workflow complex and rigid, most probably with choke points for efficiency. Distribution of roles may become disbalanced by people coming and going, or the workflow tool may be prohibitive to some scenarios (e.g. single translator making small adjustments in dozens of files across the project, but having to upload each manually through a web interface).&lt;br /&gt;
&lt;br /&gt;
Of course, &amp;quot;rigid&amp;quot;, &amp;quot;complex&amp;quot;, &amp;quot;inefficient&amp;quot;, are comparative qualifications, so what is it that the classical review by stages can be compared to in this way?&lt;br /&gt;
&lt;br /&gt;
== Reviewing by Ascriptions ==&lt;br /&gt;
&lt;br /&gt;
Reviewing by ascriptions is even simpler conceptually, and yet less rigid, less complex, and much more efficient than the review by stages. It works on the message-level, rather than file-level. Anyone can simply translate some messages and directly commit modified files, without any review, but with ''ascribing'' modifications to own name. Anyone can review any committed messages at any moment, commit the modifications-on-review and ascribe reviews to own name and (possibly) to certain class -- full review, review of context, of terminology, of style, etc. Only when the translation is to be shipped to end users, the ''insufficiently'' reviewed messages are automatically omitted from the package, by evaluating the ''ascription history'' of each message.&lt;br /&gt;
&lt;br /&gt;
Most importantly, based on the ascription history, the reviewer can select only some particular messages, and review only the difference between their historical and current versions. For example, Alice can select to review only messages modified since she or Bob had last reviewed them for style; she could see the difference from that last review to current version, e.g. if in the whole paragraph only a single word has changed by Charlie when he reviewed the terminology. In terms of PO workflow, the ascription history propagates through merges, so the reviewer can compare the change in original and the change in translation since the last review, to judge if one fits the other.&lt;br /&gt;
&lt;br /&gt;
Since everyone just commits, translations can be efficiently kept in a version control repository, with the ascription system added on top. After having done some translating, the team member simply substitutes commit command of the version control system (VCS) with ascribe-modifications command of the ascription system (AS, which calls the underlying VCS internally). After reviewing, the team member uses ascribe-reviews command of the AS to commit reviews to ascription history (as well as modifications made during the review). To select messages for review, the team member issues diff-for-review command of the AS (with suitable parameters to narrow the set) and selected messages are marked in-place in PO files and [[Localization/Tools/Pology/PO_Embedded_Diffing|embedded with differences]], and possibly popped open in a PO editor.&lt;br /&gt;
&lt;br /&gt;
When the translations are to be released, the team coordinator issues filter-for-release command of the AS, which takes the working PO files and creates final PO files with insufficiently reviewed messages removed. &amp;quot;Release time&amp;quot; is used here only figuratively: this should be a fully automatic process, so it can be performed at any interval of convenience.&lt;br /&gt;
&lt;br /&gt;
What constitutes &amp;quot;sufficient review&amp;quot; can be defined in fine detail. It could be specified that messages modified by Alice need to have only review for terminology, but not necessarily for style; Charlie may belong to the group which needs to be reviewed on style, but not necessarily on context; Bob's reviews for style may be nice to have, but never blocking if missing. These decisions do not preclude released messages to be reviewed later on missing points, after higher priority reviews have been completed. The definition of sufficiency may be changed at any point, e.g. as team members get more experienced and require less review, without interfering with direct translation and review work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- (Here is one unorthodox possibility of using reviews by ascriptions. A random translator may want to keep an eye on what the reviewers change in the files he maintains. For example, to learn what are typical small errors that he makes while translating. Therefore, he himself reviews any modifications not made by him after his last review, and commits them. This will in no way interfere with &amp;quot;canonical&amp;quot; reviews, those considered at release time.) //--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In summary, with reviewing by ascriptions the lean efficiency of raw VCS operation is preserved while providing for great flexibility of review. All team members can be given commit access, no web or email detours are needed. There are no prescribed roles, but an equivalent of role assignment happens automatically at last possible moment, and can take into account both translators' and reviewers' abilities. There is no staging between completing and committing the translation, which enables translator to keep on polishing the translation undisturbed until the reviewer comes around. There is no inefficiency in handling small changes throughout many files, since single AS command commits all changes just as single VCS command would. AS in effect abstracts VCS, so general team members do not have to know the particularities of the underlying VCS. On commit operations, AS can also apply checks (e.g. decline to commit syntactically invalid PO files) and modifications (e.g. update translator's data in the PO header).&lt;br /&gt;
&lt;br /&gt;
== Ascription System in Pology ==&lt;br /&gt;
&lt;br /&gt;
[[Localization/Tools/Pology|Pology]] is a collection of various modular tools for supporting translation based on PO files. Among them is the script &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which implements an ascription system (AS); at present, it can use Subversion or Git as the underlying VCS. &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is still in experimental stage, so what follows is a brief description of how to use it in context of the KDE translation project. However, very little is truly specific to KDE; the only major assumption is that there exists a VCS repository with PO files of a given language grouped together, and that the translation team can use it without special restrictions.&lt;br /&gt;
&lt;br /&gt;
Very important for the AS is how branches are handled (in KDE, the rolling trunk and stable branches). AS can in principle be deployed by branch, but then there is the added complexity of porting translations between branches, which ascriptions should follow. Therefore, the AS implemented by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is currently limited to assumption that there is a single branch of translations at all times. The article [[Localization/Workflows/PO_Summit|&amp;quot;Translating in Summit&amp;quot;]] explains how a KDE translation team can set up and operate such a single branch, the summit, and this is the prerequisite for the following instructions. (Note that the summit system is useful on its own, and should be conductive to any kind of review workflow.)&lt;br /&gt;
&lt;br /&gt;
== Setting Up ==&lt;br /&gt;
&lt;br /&gt;
The summit branch for the language &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt; is positioned like this in the KDE repository:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            LANG/&lt;br /&gt;
                summit/&lt;br /&gt;
                    messages/&lt;br /&gt;
                    docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The team coordinator already has this part of the repository tree locally due to regular summit operations. For the same reason Pology is already set up. Setting up the ascription system is now simple. The file &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; is created in the root of the summit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# ---------------------------&lt;br /&gt;
# Global ascription settings.&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
&lt;br /&gt;
# The root of the ascription catalog tree.&lt;br /&gt;
ascript-root = ../summit-ascript&lt;br /&gt;
&lt;br /&gt;
# The underlying version control system.&lt;br /&gt;
version-control = svn&lt;br /&gt;
&lt;br /&gt;
# Data for updating catalog headers.&lt;br /&gt;
# - language code&lt;br /&gt;
language = LANG&lt;br /&gt;
# - full language name&lt;br /&gt;
language-team = LANGUAGE&lt;br /&gt;
# - email address of the team&lt;br /&gt;
team-email = kde-i18n-LANG@kde.org&lt;br /&gt;
&lt;br /&gt;
# Default commit message.&lt;br /&gt;
commit-message = Translation updates.&lt;br /&gt;
&lt;br /&gt;
# -----------------------&lt;br /&gt;
# Registered translators.&lt;br /&gt;
&lt;br /&gt;
[user-alice]&lt;br /&gt;
name = Alice Akmalryn&lt;br /&gt;
original-name = Алиса Акмалрин&lt;br /&gt;
email = alice.akmalryn@someplacenice.org&lt;br /&gt;
&lt;br /&gt;
[user-bob]&lt;br /&gt;
name = Bob Byomkin&lt;br /&gt;
original-name = Бобан Бјомкин&lt;br /&gt;
email = bob.byomkin@otherplacenice.org&lt;br /&gt;
&lt;br /&gt;
# ...and so on.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;ascript-root&amp;lt;/tt&amp;gt; setting should be exactly &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt;, for the reason mentioned later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit-message&amp;lt;/tt&amp;gt; field, if defined, allows team members to commit without providing a commit message. The value given by this field will be used by default, with translator's user name appended to the end in special syntax. For example: &amp;lt;tt&amp;gt;Translation updates. [&amp;gt;alice]&amp;lt;/tt&amp;gt;. (Translator's user name is also appended to manually supplied commit messages.) Translators can still supply a commit message when they wish, as shown later. If this field is not set, the commit message is supplied as usual on committing.&lt;br /&gt;
&lt;br /&gt;
* Team members are defined by &amp;lt;tt&amp;gt;[user-USERNAME]&amp;lt;/tt&amp;gt; sections. Ascription user names can be any valid ASCII identifier: ASCII letters, digits and underscores only, digit cannot be the first character. Ascription user names have no technical relation to the underlying VCS accounts, though it is mnemonically convenient if they are the same (in case of SVN). This means that a translator who does not have a VCS account (yet) can and should be added here, with assigned user name (best one suitable as SVN account name later); why this should be done will be explained later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field in user sections is there in case the preferred renderings of the name in English and in target language are not the same. When this is not the case, &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; can be omitted.&lt;br /&gt;
&lt;br /&gt;
As soon as the &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; file is committed, the ascription system is ready for operation. Only regular modifications to this file are those of adding new team members. (On the other hand, team members should never be removed, because even after they no longer contribute, their ascription records remain in the system.)&lt;br /&gt;
&lt;br /&gt;
=== Initial Ascription ===&lt;br /&gt;
&lt;br /&gt;
The most common situation at start of ascription workflow is that there already exists a body of translations, contributed to by many different people over time. The coordinator should ascribe all existing translations as initial modifications, but to whom? It cannot be said precisely who translated what. The solution is to introduce a generic user in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;, suitably known as &amp;quot;Unknown Hero&amp;quot; (or &amp;quot;Lost Translator&amp;quot;, you can be inventive):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[user-uhero]&lt;br /&gt;
name = Unknown Hero&lt;br /&gt;
original-name = Незнани јунак&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ascribe all existing translations as modified and reviewed by this user. The coordinator does this with the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe reviewed -u uhero -C LANG/summit/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;tt&amp;gt;reviewed&amp;lt;/tt&amp;gt; is the ascription mode, and the &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option provides the user name to which ascriptions are made. This is an important point: ascriptions are made to a user defined in ascription configuration, and have nothing to do with VCS accounts; someone who has the account can commit in the name of someone who does not. The &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option prevent automatic committing by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which is useful for this initial step. Finally the paths which contain all summit catalogs are given.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command is issued, a progress bar will appear, and the following output will start to unfold:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/rellinks.po  (50)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/autorefresh.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/babelfish.po  (38)&lt;br /&gt;
...&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/libphonon.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon-xine.po  (24)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon_gstreamer.po  (12)&lt;br /&gt;
===! Translated: 111775&lt;br /&gt;
===! Fuzzy: 26943&lt;br /&gt;
===! Obsolete translated: 2965&lt;br /&gt;
===! Obsolete fuzzy: 1626&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/rellinks.po  (50)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/autorefresh.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/babelfish.po  (38)&lt;br /&gt;
...&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/libphonon.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon-xine.po  (24)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon_gstreamer.po  (12)&lt;br /&gt;
===! Reviewed: 143309&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number in parenthesis indicates how many messages have been ascribed in the given PO file, and at the end the totals are given. Catalogs are processed twice, first to ascribe modifications and then reviews, because a review cannot be ascribed before the modification has been ascribed. Ascribing the complete summit for the first time will take quite some time (say 15-30 minutes).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--If, on the contrary, it is known who translated-reviewed what, ascription can be performed piece-wise with user names of real translators:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support/LANG/summit&lt;br /&gt;
$ poascribe reviewed -u alice -C kdelibs/ kdepimlibs/ kdebase/&lt;br /&gt;
$ poascribe reviewed -u bob -C kdemultimedia/ kdeutils/&lt;br /&gt;
$ ...&lt;br /&gt;
&amp;lt;/code&amp;gt;//--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the initial ascription has been made, the ascription tree will appear next to the summit tree. This tree will contain one ascription PO file for each summit PO file, with the same name and relative location within the tree:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
        summit-ascript/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ascription tree can now be committed as usual (&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will have already added it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit-ascript/ -m &amp;quot;Initial ascription.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Translators ==&lt;br /&gt;
&lt;br /&gt;
Team members other than the coordinator, whether translators or reviewers, need to keep around only the &amp;lt;tt&amp;gt;trunk/l10n-support/LANG/&amp;lt;/tt&amp;gt; directory. But they always need to update this directory fully (rather than just one particular module or file under &amp;lt;tt&amp;gt;.../*messages/&amp;lt;/tt&amp;gt;), so that the summit tree and the ascription tree (and configuration) are kept in sync.&lt;br /&gt;
&lt;br /&gt;
In order not to have to issue their own user name (&amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;) all the time, translators can set it in Pology user configuration &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, in &amp;lt;tt&amp;gt;[poascribe]&amp;lt;/tt&amp;gt; section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = alice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translators can then submit updated PO files simply by substituting &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt; (or whatever the VCS commit command is) with &amp;lt;tt&amp;gt;poascribe modified&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;mo&amp;lt;/tt&amp;gt; for short):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo LANG/summit/messages/kdefoo/*fooapp*.po&lt;br /&gt;
!    LANG/summit-ascript/messages/kdefoo/fooapp.po  (144)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdefoo/libfooapp.po  (25)&lt;br /&gt;
===! Translated: 169&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/libfooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/libfooapp.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1267069.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will add ascription records into ascription catalogs corresponding to summit catalogs to be committed, and commit them all. Like &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;poascribe mo&amp;lt;/tt&amp;gt; can take any number of file or directory paths, and can be issued from any working directory (it will always find ascription catalogs). If default commit message has not been set in the ascription configuration, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will ask for it; or it can be given in command line through &amp;lt;tt&amp;gt;-m&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
=== Translators Without Commit Access ===&lt;br /&gt;
&lt;br /&gt;
With the ascription system in place, every regular team member should have commit access. But, there may be some period of time before new translators are given accounts, revision control may be too technical for some, and even those with the account may not be able to commit temporarily for some reason.&lt;br /&gt;
&lt;br /&gt;
These translators may send in their work by email, to ''any'' team member with commit access (not necessarily the coordinator or a reviewer); this team member can commit received files without any review, as review can be conducted at any later time. If Bob sends some files to Alice, she can commit them immediately by stating Bob's user name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo -u bob ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, the translator who sent in the files has to be defined in the ascription configuration. There are no hidden costs or security issues to this (as opposed to opening a VCS account), so every new translator should be defined there before any work of that person is committed.&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Reviewers ==&lt;br /&gt;
&lt;br /&gt;
The ascription system opens up all sorts of possibilities for concrete review patterns. Reviewers should keep in mind that for each message the full modification and review history is available, so that the team can think about how to make good use of it. Therefore, what follows are some examples to illustrate the review facilities that &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; provides.&lt;br /&gt;
&lt;br /&gt;
=== Basic Reviewing ===&lt;br /&gt;
&lt;br /&gt;
At the very basic level (which is the only level in classical review by stages), messages can be classified into simply unreviewed and reviewed, without further qualifiers. Alice now wants to review all unreviewed messages in a group of PO files, say &amp;lt;tt&amp;gt;kdetoys&amp;lt;/tt&amp;gt; module. She issues (&amp;lt;tt&amp;gt;di&amp;lt;/tt&amp;gt; is short for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe di LANG/summit/messages/kdetoys/&lt;br /&gt;
!    LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Diffed for review: 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unreviewed messages have now been marked and diffed, inside the listed PO files. What is this about &amp;quot;diffing&amp;quot;? If the files had already been reviewed before, some of the messages modified since then (those marked for review) may have changed very little (e.g. a few words in a paragraph-length message, or even just punctuation). Therefore, for each message marked for review, Alice also wants to see the diff since last review to current version. Here are two messages in typical review states added by &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: charlie:m&lt;br /&gt;
#: gui/mainwindow.cc:372&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;GAME OVER. {-You won-}{+Tie+}!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KRAJ IGRE. {-Pobeda-}{+Nerešeno+}!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: bob:m charlie:m&lt;br /&gt;
#: game-state.cpp:117&lt;br /&gt;
#, ediff-total&lt;br /&gt;
msgid &amp;quot;Click the pause button again to resume the game.&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Кликните поново на дугме паузе за наставак игре.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the first one in Kate:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_poascribe_diff_01.png|center|Message diffed for review by poascribe in Kate.]]&lt;br /&gt;
&lt;br /&gt;
In the first message, the first to note is the &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment. This comment succinctly lists who did what with the message since the last review; here &amp;lt;tt&amp;gt;charlie:m&amp;lt;/tt&amp;gt; means that Charlie is the one who modified it. Then, there is the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, which alice can use it to jump through messages marked for review. Finally, the original and translation have been diffed; here they show that, since the last review, the message was fuzzied by changing &amp;quot;You won&amp;quot; to &amp;quot;Tie&amp;quot;, and what Charlie did in translation to unfuzzy it. Even on a message as short as this, the diff tells something useful to Alice: the phrase &amp;quot;Game over&amp;quot; likely has a formulaic translation, and the fact that it is not part of the diff means that the earlier reviewer had made sure it is consistent, so Alice does not have to check that.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment of the second message reveals that both Charlie and Bob had been translating it. &amp;lt;tt&amp;gt;ediff-total&amp;lt;/tt&amp;gt; flag instead of plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; means that this message had no review at all up to now, so there are no embedded diffs in text fields.&lt;br /&gt;
&lt;br /&gt;
Alice can now go through marked files and messages, review translations, and possibly make modifications. When making changes in a message with embedded diffs, she can freely edit text outside of difference segments and within &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments (as these are the ones which belong to current version of the text). While reviewing, Alice does ''not'' remove any of the added message elements while reviewing (save for an occasional difference segment, when translation should be modified), as these elements are needed for later. If a message is particularly hard and Alice wants to defer its review for later, she can add the &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;urev&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; for short) flag to it.&lt;br /&gt;
&lt;br /&gt;
Once the review is complete, Alice commits the reviewed files in &amp;lt;tt&amp;gt;reviewed&amp;lt;/tt&amp;gt; mode (short &amp;lt;tt&amp;gt;re&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re LANG/summit/messages/kdetoys/{bovo,kdiamond,palapeli}.po&lt;br /&gt;
!    LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Cleared reviews: 21&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/palapeli.po (3)&lt;br /&gt;
===! Translated: 3&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Reviewed: 21&lt;br /&gt;
Sending      LANG/summit/messages/kdegames/palapeli.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/bovo.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/kdiamond.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/palapeli.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1284220.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three things have happened here. First, all review states (flags, embedded diffs, etc.) have been removed, restoring the PO file to normal. Then, any modifications that Alice have made during review are ascribed to her (here 3 out of 21 messages). Finally, all marked messages are ascribed as reviewed by Alice (any with &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;urev&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; flags would have been omitted here). When committing, the only summit catalog that got committed is the one with modifications made during review, and all the ascription catalogs were committed because of the reviews recorded in them.&lt;br /&gt;
&lt;br /&gt;
When many files with few changes in each are to be reviewed, it becomes burdensome to manually open each and every diffed for review, and then to make sure that all are committed with &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt;. To make this easier, &amp;lt;tt&amp;gt;-w torevivew.out&amp;lt;/tt&amp;gt; option can be added to &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;, which requests that paths of all diffed PO files are written into &amp;lt;tt&amp;gt;torevivew.out&amp;lt;/tt&amp;gt; file. This file can then be used to batch open POs for review in the editor, as well as fed back on &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;-f torevivew.out&amp;lt;/tt&amp;gt;. There is also the &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; option which causes &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; to directly open PO files in a PO editor, though this is currently applicable only to Lokalize. Putting it together, to efficiently review a whole bunch of small changes throughout many files, Alice can:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di PATHS... -w toreview.out -o lokalize&lt;br /&gt;
$ # ...only marked messages opened in Lokalize, review them...&lt;br /&gt;
$ poascribe re -f toreview.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selecting Messages for Review ===&lt;br /&gt;
&lt;br /&gt;
Invocations of &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; without any options, as in the previous section, were actually equivalent to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; is issuing the message ''selector''. &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is the default selector for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt; mode, and stands for MODified-After-Review: it selects the earliest historical modification of the message after the last (or no) review of that message, if there is any such. By selecting a historical modification of the message, the diff from it to current version can be computed and embedded into the PO file, as in previous examples.&lt;br /&gt;
&lt;br /&gt;
There are various specialized selectors, and fall into two groups: ''shallow selectors'' and ''history selectors''. Shallow selectors look only into the current version of the message, and cannot select historical versions, which means that they cannot provide embedded diffs. History selectors (&amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is of this type) can select messages from history and provide diffs. Several selectors can be issued on the command line, and the message is selected only if all selectors select it. Shallow selectors are then normally used as a pre-filter for history selectors. For example, to select messages modified after last reviewed, but only those found in stable branch, &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; selectors are chained:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s branch:stable -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that the history selector is given last, because the last selector determines which historical message is selected. If the ordering had been reversed here, same messages would get selected, but they would not have embedded diffs, because &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; is a shallow selector.&lt;br /&gt;
&lt;br /&gt;
Selectors can take parameters themselves, like &amp;lt;tt&amp;gt;branch:stable&amp;lt;/tt&amp;gt; in the previous example. Parameters are separated from the selector name by any non-alphanumeric character; this is colon by convention, but if a parameter contains a colon, something like slash, tilde, etc. can be used. Number of parameters can be variable, and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; in particular can take from none to three. If Alice wants to review only those messages modified ''by Charlie'' since last review, she states this by first argument to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:charlie PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Alice does not give too much credit to other reviewers, she can request selection of messages modified after last review ''by her'' with second parameter to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar::alice PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the first parameter (&amp;quot;modified by...&amp;quot;), which is not needed, must be explicitly skipped, before going to the second parameter (&amp;quot;reviewed by...&amp;quot;). The third optional parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; will be mentioned in the next section.&lt;br /&gt;
&lt;br /&gt;
When a selector parameter is a user name, normally it can also be a comma-separated list of user names (&amp;lt;tt&amp;gt;modar:bob,charlie&amp;lt;/tt&amp;gt;) or prefixed with tilde to negate, i.e. select all other users (&amp;lt;tt&amp;gt;modar:~alice&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Any selector can be negated by prepending &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; to its name. For example, the history selector &amp;lt;tt&amp;gt;modafter:DATE&amp;lt;/tt&amp;gt; selects first modification after the given date; to select messages modified after last review, but only if modified during June 2010:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modafter:2010-06 -s nmodafter:2010-07 -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Negating a history selector produces a shallow selector: while &amp;lt;tt&amp;gt;modafter&amp;lt;/tt&amp;gt; is history selector, &amp;lt;tt&amp;gt;nmodafter&amp;lt;/tt&amp;gt; is shallow. But the order of the two in the previous command line is not important, as the last selector is the usual &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selectors can be issued in other modes too. If the PO file is big and Alice has reviewed messages up to and including entry 246 when she has to pause until another day, she can commit reviews only up to this entry by issuing the &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; selector:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re -s espan::246 PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the first parameter to &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; is the first entry number, given if messages are not to be selected from the first). There is also the counterpart &amp;lt;tt&amp;gt;lspan&amp;lt;/tt&amp;gt; selector, which works with referent line numbers (those of &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; keywords) instead of entry numbers.&lt;br /&gt;
&lt;br /&gt;
=== Fine-Grained Reviews ===&lt;br /&gt;
&lt;br /&gt;
In the introduction, several distinct types of what can go wrong in translation were described. Not all reviewers may be able to check translation against all those problems. Here is a typical scenario of this kind:&lt;br /&gt;
&lt;br /&gt;
Alice is very computer-savvy and knows the translation project inside and out, which means that she can review well for context, terminology, and technical style. But, her language style leaves something to be desired, which shows through longer sentences and passages. Dan, on the other hand, is a very literary person, but not that much into the technical aspects. Dan's style reviews would thus be a perfect complement to Alice's general reviews.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; can support this scenario in the following way. A ''review type'' tag for language style is defined in the ascription configuration, using the &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[global]&lt;br /&gt;
...&lt;br /&gt;
review-tags = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The value to &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; is a space-separated list of identifiers, when more than one special review type is needed.) With this addition to configuration, Alice can continue to review as she did before, without any changes to her workflow.&lt;br /&gt;
&lt;br /&gt;
Dan selects messages for review quite similarly to Alice, with the exception of giving the &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; tag as ''third'' parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:::lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When committing reviews, Dan must also state this tag, in order to ascribe reviews as of language style type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re -t lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Dan is always going to review the language style, in order not to have to issue the selector and tag in the command line all the time, he can make them default per mode in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = dan&lt;br /&gt;
selector/diff = modar:::lstyle&lt;br /&gt;
tag/reviewed = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this Dan can use plain &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt;, just like Alice does.&lt;br /&gt;
&lt;br /&gt;
The important point of review tags is that they make reviews by types independent. For example, Dan may come around to review the language style of the given message after several modifications and general reviews have been ascribed to it -- &amp;lt;tt&amp;gt;modar:::lstyle&amp;lt;/tt&amp;gt; will simply ignore all reviews except for &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews. This is going to be reflected in the &amp;lt;tt&amp;gt;ascto:&amp;lt;/tt&amp;gt; comment to marked messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: charlie:m alice:r bob:m&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here Alice has made one review between Charlie's and Bob's modifications, and that review, being general instead of &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;, did not cause &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; to stop at it. After Dan reviews this message for language style, Alice runs selection for review and gets this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: bob:m dan:r(lstyle)&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, since &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews do not mix with general reviews, Dan's review did not hide Bob's modification that Alice did not check so far.&lt;br /&gt;
&lt;br /&gt;
(General review too has a tag assigned, the empty string, in case the reviewer needs to explicitly issue it in some context.)&lt;br /&gt;
&lt;br /&gt;
== Daily Use for The Coordinator ==&lt;br /&gt;
&lt;br /&gt;
After setting up the ascription system, the team coordinator should have to do very little to maintain it.&lt;br /&gt;
&lt;br /&gt;
=== Ascribing Merges ===&lt;br /&gt;
&lt;br /&gt;
Modifications made to summit catalogs by merging with templates must also be ascribed. Therefore, after merging the summit (&amp;lt;tt&amp;gt;posummit ... merge ...&amp;lt;/tt&amp;gt;) the coordinator substitutes the VCS command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command in &amp;lt;tt&amp;gt;modified&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the user is not explicitly given by &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option, this will ascribe merge modifications to the coordinator (more precisely, to the user set as default in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;), which is just fine. It is also possible to define a special user only for ascribing merge modifications, though there is no known advantage to that.&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option is not issued, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will automatically commit all modified summit and ascription catalogs when done.&lt;br /&gt;
&lt;br /&gt;
=== Shuffling Ascription Catalogs  ===&lt;br /&gt;
&lt;br /&gt;
Sometimes summit catalogs are shuffled in the repository: moved to another module, renamed, one catalog split into two, two catalogs merged into one. Such shuffling should be exactly mirrored in the ascription tree, and this too is done on the repository side, at the same time. This relies on the ascription root being set exactly to &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt; in the ascription configuration. So the team coordinator has nothing special to do here.&lt;br /&gt;
&lt;br /&gt;
If instead in the central KDE repository the translation team is working in an external repository, by consequence the ascription system must be set up in that repository. But so long as &amp;lt;tt&amp;gt;process_orphans.sh&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; is used to shuffle catalogs in the external repository as well, the ascription catalogs will be properly handled.&lt;br /&gt;
&lt;br /&gt;
== Filtering for Release ==&lt;br /&gt;
&lt;br /&gt;
The last component of the ascription system is how to prevent insufficiently reviewed messages from leaking into a release. In context of Pology and summit workflow, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; itself is used directly to this end. Instead, in the summit configuration (as opposed to ascription configuration), the team coordinator defines filters which pass messages by applying selectors.&lt;br /&gt;
&lt;br /&gt;
Each top level PO tree has its own summit configuration file, named &amp;lt;tt&amp;gt;MSGTREE.extras.summit&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            messages.extras.summit&lt;br /&gt;
            docmessages/&lt;br /&gt;
            docmessages.extras.summit&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the simple case of all reviews being general reviews, the filter is added to summit configuration like this (anywhere within &amp;lt;tt&amp;gt;*.extras.summit&amp;lt;/tt&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the filter is named &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;, and is defined as application of &amp;lt;tt&amp;gt;nmodar&amp;lt;/tt&amp;gt; selector, the negation of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;. This simply means: pass all messages ''not'' modified after the last review.&lt;br /&gt;
&lt;br /&gt;
When the team coordinator scatters to branches (executes &amp;lt;tt&amp;gt;posummit scatter&amp;lt;/tt&amp;gt;), messages from summit POs which do not pass this filter will not be sent to branch POs. The count of stopped messages by branch PO will be reported in the output as scattering proceeds.&lt;br /&gt;
&lt;br /&gt;
Why did we have to name the filter &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;? (Those knowing some Python will also notice that it is defined as a list element.) Because it is possible to define more than one filter, and select which one is used on each scattering. For example, the coordinator may wish that, when the release is near and time is short to review everything, messages from a few experienced translators can be passed into release without review. If those translators are Alice and Bob, an &amp;quot;emergency&amp;quot; filter can be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; uses the first filter in the list. When the coordinator needs to do emergency scattering, he requests the emergency filter by the &amp;lt;tt&amp;gt;-a&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter -a emergency&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What if several selectors are needed to pass the message? For example, the language style review (the earlier example with Alice and Dan) too may be requested for regular scattering, but omitted from emergency scattering. The filter setup for this scenario looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;, &amp;quot;nmodar:::lstyle&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The regular filter now reads: pass the message if it has not been modified after the last (general) review ''and'' has not been modified after the last style review.&lt;br /&gt;
&lt;br /&gt;
Simple combination of predefined selectors by AND-conditions may not be sufficient for more involved scenarios. When this is the case, the coordinator may write (or ask someone to write) a custom selector in Python, and plug it in as the second element in the filter tuple (instead of the list of predefined selectors).&lt;br /&gt;
&lt;br /&gt;
=== Writing a Selector Function ===&lt;br /&gt;
&lt;br /&gt;
((To be written.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Summit</id>
		<title>Localization/Workflows/PO Summit</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Summit"/>
				<updated>2010-01-19T18:16:19Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Replaced real language code with LANG placeholder.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Translating in Summit|&lt;br /&gt;
prereqs=[[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Software Branches and Translation ==&lt;br /&gt;
&lt;br /&gt;
The obvious approach to releasing software is for developers to focus on one central body of code, a single &amp;quot;branch&amp;quot;, fixing bugs and adding new features to it, and from time to time taking a &amp;quot;snapshot&amp;quot; of the branch and packing it as next release. One approach to make the release process more robust, is for development to proceed in two parallel branches. From the &amp;quot;stable&amp;quot; branch the actual releases are made, mostly with bugs fixed and only very important features added. The other, &amp;quot;unstable&amp;quot; branch, is used to develop new and redesign existing features, and at some point will become the next stable branch. Depending on the project, releases may be made from the unstable branch as well, in parallel with stable releases, in order for eager users to help testing the novelties.&lt;br /&gt;
&lt;br /&gt;
In KDE, all three release models may be present at any given moment. Core KDE modules, which are together labeled as &amp;quot;the KDE&amp;quot; and released in unison, follow the two branch model, with stable and trunk branch, and releases from stable branch only. KDE extragear applications may do the same, but they are not required to; they may instead make releases from the trunk branch only, or also use stable and trunk branch, but make releases from both. This presents translators with the workflow as on the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_branches.png|center|Classic translation by branches]]&lt;br /&gt;
&lt;br /&gt;
The KDE [[Localization/Workflows/Repository_Automation|repository automation]] (aka &amp;quot;Scripty&amp;quot;) is preparing template POs and merging them with language POs. From the point of view of language teams, real people who perform global actions (e.g. moving around POs for all languages when an application moves from module to another) can also be grouped here. However, the translation team is still presented with two branches of POs to translate.&lt;br /&gt;
&lt;br /&gt;
In general, this means that, just like programmers, at times translators have to work on both branches, and propagate fixes from one branch to another (&amp;quot;backport&amp;quot; from trunk to stable, or &amp;quot;forwardport&amp;quot; from stable to trunk). This may be prone to coordinatorial confusion, and demand extra effort and attention when updating translations. Keeping up with two branches is easier in core KDE modules, as they are released from stable branch only and with singular schedule, but could be more taxing with extragear applications.&lt;br /&gt;
&lt;br /&gt;
The exact amount of effort spent due to parallel translation, porting of fixes, and coordination, depends on the translation team. For example, a well-manned and well-coordinated team, with established style and terminology guides, custom automation to support these, may be able to keep all POs in both branches fully translated at all times with ease. Or, a team may have worked out well-defined schedules, such that any given member of the team at one point switches from translating one branch to another, without looking back, thus effectively having everyone always working on one branch (even if not the same one).&lt;br /&gt;
&lt;br /&gt;
If, however, you as the team coordinator have said and thought &amp;quot;Should do that in trunk too, bugger&amp;quot;, &amp;quot;Didn't we fix that already?&amp;quot;, &amp;quot;No, you should take it from stable&amp;quot;, &amp;quot;It was released from WHAT branch?&amp;quot;, more often than you would have liked, the following presents one possibility for sidestepping such issues.&lt;br /&gt;
&lt;br /&gt;
== Translating in Summit ==&lt;br /&gt;
&lt;br /&gt;
For a PO catalog which exists in both stable and trunk branch, a new same-named catalog can be made by ''gathering'' all the unique messages from branch PO files, i.e. the ''summit'' of branch POs. Assuming that branch POs were not all that different, since they are two versions of the same catalog, the summit PO shouldn't have much more messages than either. Translators at all times work on the summit PO, from which the messages are periodically ''scattered'' back to original branch POs. Thus, translators can always work on summit POs, not having to do any parallel translation, branch switching or porting of fixes. The summit workflow is presented by the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_summit.png|center|Translation in summit]]&lt;br /&gt;
&lt;br /&gt;
In the summit mode, repository automation gathers summit PO templates from branch templates, and stores them separately from real branches, at {{path|trunk/l10n-support/templates/summit/}}. The language team also has a collection summit POs, at {{path|trunk/l10n-support/LANG/summit/}}, which is the sole location where translation happens. As before, repository automation handles merging of templates in branches, but merging of summit POs is done by the team coordinator; team coordinator can opt to manually merge branch POs as well (more on why-and-how of this later). From time to time, the team coordinator fills out branch POs by scattering from summit. Not to worry, each of these special actions upon the team coordinator is done with a single command.&lt;br /&gt;
&lt;br /&gt;
While it is in principle obvious that two branch POs can be made into one summit PO with the union of their messages, there are some important details that should be handled the right way by the summitting system:&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes modules in one branch, so that it no longer belongs to the same module in both branches (e.g. application is moved from one to another module in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes its name in one branch, but not in the other (e.g. application is renamed in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO in one branch is split into two POs in another (e.g. extracting a library out of monolithic application in trunk)?&lt;br /&gt;
&lt;br /&gt;
* Where to place messages unique to one branch in the summit PO? The original file context of a message, which messages precede it and which follow it, should be kept as much as possible.&lt;br /&gt;
&lt;br /&gt;
* If source references are used to achieve good ordering of messages in summit PO, what to do if some source file paths change in one branch (e.g. application gets restructured in trunk)?&lt;br /&gt;
&lt;br /&gt;
* How to handle messages with different plurality across branches (since messages are identified only by their &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, an not &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt;)?&lt;br /&gt;
&lt;br /&gt;
And handle these details it does, the present summitting system. This also means that teams working in the summit need not take care of the first three issues above, which are affecting manual branch handling too.&lt;br /&gt;
&lt;br /&gt;
Summit POs are normal, fully valid POs in their own right. A message in a summit PO is different from branch PO only by being equipped with another comment, &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt;, showing in which branches the message exists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgctxt &amp;quot;The destination url of a job&amp;quot;&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:517&lt;br /&gt;
msgid &amp;quot;&amp;amp;Keep this window open after transfer is complete&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first message above thus exists in trunk only, the second in stable only, and the third in both branches. The source reference always points to the source file in the first listed branch. Any extracted comments (&amp;lt;tt&amp;gt;#.&amp;lt;/tt&amp;gt;) other than the branch list are also taken from the first listed branch.&lt;br /&gt;
&lt;br /&gt;
Note that the two messages above are different only by context; the context was added in trunk, but not in stable, in order not to break message freeze. However, due to careful ordering of messages in summit POs, these two messages appear together, allowing translator to immediately make correction in stable branch too if the new context in trunk shows it to be necessary.&lt;br /&gt;
&lt;br /&gt;
=== Setting Up and Daily Operation ===&lt;br /&gt;
&lt;br /&gt;
Before initializing language summit, the team coordinator has to have all the necessary paths checked out from the KDE repository, and structured on the local machine exactly as in the repository. If the path to the root of KDE repository on the local machine is &amp;lt;tt&amp;gt;$KDEREPO&amp;lt;/tt&amp;gt;, and the language code &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt;, then the structure should be as follows, with leaf directories checked out in full:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            scripts/&lt;br /&gt;
            pology/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                templates/&lt;br /&gt;
                LANG/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that this structure is fully under version control (rather than e.g. top directories being manually created), so if that is not the case, the following commands will fetch everything anew in proper order:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
cd $KDEREPO&lt;br /&gt;
svn co --depth=empty svn+ssh://svn.kde.org/home/kde .&lt;br /&gt;
svn up --depth=empty branches branches/stable branches/stable/l10n-kde4&lt;br /&gt;
svn up --depth=empty trunk trunk/l10n-support trunk/l10n-kde4&lt;br /&gt;
svn up branches/stable/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the trailing dot in the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command, and do not miss to substitute LANG for the real language code in the last three commands. &amp;lt;tt&amp;gt;--depth=empty&amp;lt;/tt&amp;gt; option prevents recursive fetching, so that e.g. the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command does not fetch the complete repository tree. Later you can regularly update this tree with single command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
svn up $KDEREPO/{trunk,branches/stable}/l10n-kde4/{scripts,templates,LANG} \&lt;br /&gt;
       $KDEREPO/trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Summit operations are performed using the &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; command, which is part of [[Localization/Tools/Pology|Pology]], residing in {{path|trunk/l10n-support/pology/}}. Therefore the first thing to do is to setup Pology, which amounts only to setting the proper path:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ export PATH=$KDEREPO/trunk/l10n-support/pology/bin:$PATH&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To initialize the summit, by gathering from existing translation in branches, the team coordinator executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Depending on the amount of translation, after some minutes the initial gathering will have been completed, and language summit located under {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages/}}. This is the only time when the coordinator performs the gather operation on language POs; it is daily done only on templates by repository automation. Then, the created language summit should be merged with current summit templates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Merging the summit is something that the coordinator does periodically, with frequency of own desire. For example, it can be done daily, or with increasing frequency as the last day for translation for the next release approaches.&lt;br /&gt;
&lt;br /&gt;
After the first merging, language summit is ready for active translation. The coordinator should now commit {{path|$KDEREPO/trunk/l10n-support/LANG/}}, and, importantly, notify team members to stop working on branch POs and focus exclusively on summit POs.&lt;br /&gt;
&lt;br /&gt;
To scatter the summit, i.e. fill out POs in stable and trunk branch from the summit POs, the coordinator periodically executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As with merging, there is no fixed schedule when scattering should be done. Of course, it must necessarily be done before the next release is tagged, and in between it is useful to scatter for runtime testing, or to have translation statistics by branches on l10n.kde.org up to date.&lt;br /&gt;
&lt;br /&gt;
Periodic scattering and merging of the complete summit are basically all that a language team coordinator needs to do specifically to operate the summit. Also, since {{path|l10n-support/scripts/}} and {{path|l10n-support/pology/}} contain scripts and settings critical for proper functioning of summit operations, and may be tweaked at any time, they should always be updated from the repository together with PO files and templates (in fact, it is best to always update at once the whole tree as outlined above).&lt;br /&gt;
&lt;br /&gt;
{{note|For documentation POs, summit setup and operation is the same, only replacing every &amp;lt;tt&amp;gt;messages&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;docmessages&amp;lt;/tt&amp;gt; in the command lines above. The user interface and documentation summits are fully independent, so for a trial period it is reasonable to work with the interface summit only, and engage documentation summit once the trial has been deemed successfull.}}&lt;br /&gt;
&lt;br /&gt;
=== Operation Targets ===&lt;br /&gt;
&lt;br /&gt;
Sometimes it is advantageous to merge or scatter just a single catalog, a single module, a single branch, or any combination thereof. To this end, scatter and merge operations accept any number of ''operation targets'' after the operation keyword, specified as one of &amp;lt;tt&amp;gt;''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''MODULE''/&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''MODULE''/&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;''BRANCH'':&amp;lt;/tt&amp;gt;. For example, to scatter just to Dolphin's PO in stable branch, in order to test translation at runtime, one would execute:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(note no &amp;lt;tt&amp;gt;.po&amp;lt;/tt&amp;gt; ending on catalog name). Or, to scatter to every PO in &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; module in stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:kdeplasma-addons/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the trailing slash is mandatory, or else &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; would think that &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; is a catalog name). Finally, to scatter to all catalogs in the stable branch (with the trailing colon for the same reason as earlier):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command line arguments of &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; operations are intentionally arranged such that all the arguments fixed for one language are placed first. If operation targets are used frequently, then it is convenient to place the immutable part of the command line under a shell alias, with absolute path to the summit setup file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ alias posummit-kde-LANG=&amp;quot;posummit $KDEREPO/trunk/l10n-support/scripts/messages.summit LANG&amp;quot;&lt;br /&gt;
$ cd ANYWHERE&lt;br /&gt;
$ posummit-kde-LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Externally Injected Branch Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Once the summit is in operation, normally the only way for a catalog to appear in branches (trunk or stable) is through scattering from the summit. However, sometimes an application which had seen considerable development outside of the infrastructure of KDE project gets moved in, drawing in any of its existing translations into branches. Such externally injected branch catalogs cause warnings to be issued on summit merging, and outright failure on scattering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/foobar.po  # dummy injection&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/libfoobar.po  # dummy injection&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
...&lt;br /&gt;
posummit: warning: No summit catalog for branch catalog &lt;br /&gt;
    '../l10n-kde4/LANG/messages/kdetoys/foobar.po'.&lt;br /&gt;
posummit: warning: No summit catalog for branch catalog &lt;br /&gt;
    '../l10n-kde4/LANG/messages/kdetoys/libfoobar.po'.&lt;br /&gt;
...&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
...&lt;br /&gt;
posummit: error: Missing necessary summit catalogs: foobar libfoobar&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When this happens, the injected catalogs need to be gathered into the summit. This is done just like the initial gathering, only giving injected catalogs' names as operation targets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force foobar libfoobar&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Summit Customization ===&lt;br /&gt;
&lt;br /&gt;
File {{path|scripts/messages.summit}} (i.e. {{path|$KDEREPO/trunk/l10n-support/scripts/messages.summit}}), given as first argument to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, contains the general summit setup for all languages. This file is set to include customization file per language, if it exists at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages.extras.summit}}, which contains additions and overrides to the general setup as desired by the language team. Same as the general setup file, the customization file is a Python source. It uses an external object named &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; to define summit settings, and can, of course, contain any helper Python code (the file is executed only once, at the beginning of a &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; run). It has the following general layout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# -*- coding: UTF-8 -*-&lt;br /&gt;
# kate: syntax Python;&lt;br /&gt;
# This file is included by scripts/messages.summit&lt;br /&gt;
# for language-specific additions/overrides.&lt;br /&gt;
#&lt;br /&gt;
# ...&lt;br /&gt;
# ... operations with object S and other Python code ...&lt;br /&gt;
# ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Object &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; provides both data attributes and methods to configure different aspects of summit operation. For example, while the general setup specifies that text fields in summit catalogs should not be wrapped on column but should be wrapped on logical breaks (like some markup tags), this can be overriden using &amp;lt;tt&amp;gt;summit_wrap&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;summit_fine_wrap&amp;lt;/tt&amp;gt; attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.summit_wrap = True&lt;br /&gt;
S.summit_fine_wrap = False&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, to get the path to a file relative to the summit customization file itself (rather than to current working directory, where &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; was executed), method &amp;lt;tt&amp;gt;resolve_path_rooted&amp;lt;/tt&amp;gt; can be used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
relpath = S.resolve_path_rooted(&amp;quot;../whatever.txt&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following sections will present some typical customization possibilities.&lt;br /&gt;
&lt;br /&gt;
=== Fully Local Merging ===&lt;br /&gt;
&lt;br /&gt;
When scattering from the summit, sometimes there will be reports of &amp;quot;messages missing in the summit&amp;quot;. This happens because of time rift created by the Scripty merging branch POs, gathering summit templates, and a team coordinator merging the language summit, thus making some messages in branch POs not always present in the summit. This condition is benign, as such warnings will start to disappear with the message freeze approaching, but can be annoying. For this reason, team coordinator can stop Scripty from merging branch POs, and have the &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; command alone merge not only summit POs, but stable and trunk POs as well, such that summit and branches are always in perfect sync.&lt;br /&gt;
&lt;br /&gt;
First, to stop Scripty from merging branch POs, a file named &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; (with arbitrary content) should be committed to the roots of respective trees, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$ touch $KDEREPO/trunk/l10n-kde4/messages/LANG/no-auto-merge&lt;br /&gt;
$ touch $KDEREPO/branches/stable/l10n-kde4/LANG/messages/no-auto-merge&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, to make summit &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; merge everything, the following lines should be added into the summit customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Set local merging for all branches.&lt;br /&gt;
for branch in S.branches:&lt;br /&gt;
    branch[&amp;quot;merge_locally&amp;quot;] = True&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once local merging of all branches is set, the coordinator can also use operation targets for selective merging, e.g. to merge only stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge stable:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Merging with Compendium ===&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; takes into account only the catalog itself to fill out near-match translations to new messages introduced by merging. i.e. to produce fuzzy messages. However, an arbitrary PO file can be given to &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; as another possible source of earlier translations, through the &amp;lt;tt&amp;gt;--compendium&amp;lt;/tt&amp;gt; option. For maximum effect, this PO file is usually constructed as the collection of messages from all PO files project-wide, and hence called the ''compendium''.&lt;br /&gt;
&lt;br /&gt;
Compendium can be used in summit merge operations simply by setting &amp;lt;tt&amp;gt;compendium_on_merge&amp;lt;/tt&amp;gt; attribute in summit customization file. If the compendium is located at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages-compendium.po}}, then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Compendium to use when merging summit catalogs.&lt;br /&gt;
S.compendium_on_merge = S.resolve_path_rooted(&amp;quot;messages-compendium.po&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that if not located as above, compendium should not be placed within {{path|.../LANG/summit/messages/}}, as then it would be considered a summit catalog itself. In case fully local merging is engaged, only summit POs will be merged with compendium; it makes no sense for branch POs, since they are not being directly translated.&lt;br /&gt;
&lt;br /&gt;
See [http://www.gnu.org/software/automake/manual/gettext/Creating-Compendia.html &amp;quot;Creating Compendia&amp;quot;] section of Gettext manual for details on how to create a compendium out of current body of summit translations. Once you establish the precise commands to create the compendium (whether to collect fuzzies too, whether to include old compendium as one of sources for the new, etc.), you would periodically refresh and commit the updated compendium.&lt;br /&gt;
&lt;br /&gt;
=== Vivifying Summit Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Translation of a summit catalog normally starts the same way as it did for branch catalogs, by copying it over from template and initializing the header. This can be done manually, but it can also be quite automatic when using project manager as sometimes provided by dedicated PO editors. However, relying on the editor's project manager can be disadvantageous at times. For example, aside from the PO editor, other, frequently command line tools may be used to process the body of translation, and these tools might need to consider non-started templates as if they were empty POs (e.g. statistics). Team members who do not have full local checkout, or no project set up in the editor, may need to jump between language and template directories when looking for files to translate.&lt;br /&gt;
&lt;br /&gt;
Therefore, summit setup can be customized to automatically create (&amp;quot;vivify&amp;quot;) summit catalogs for every new summit template, so that there is never the need (for a tool or human) to specifically treat templates as empty catalogs. This is done by adding the following lines into customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Create empty summit catalog for every new summit template.&lt;br /&gt;
S.vivify_on_merge = True&lt;br /&gt;
S.vivify_w_translator = &amp;quot;Noone Noonian &amp;lt;noone.noonian@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_langteam = &amp;quot;Neverneese &amp;lt;neverteam@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_plurals = &amp;quot;nplurals=2; plural=n != 1;&amp;quot;&lt;br /&gt;
# Minimum translation state to create branch catalog on scatter.&lt;br /&gt;
S.scatter_min_completeness = 0.9&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;vivify_w_*&amp;lt;/tt&amp;gt; attributes set the necessary data to initialize headers of newly created summit catalogs. Aside from those listed above, there is also the &amp;lt;tt&amp;gt;vivify_w_charset&amp;lt;/tt&amp;gt; attribute, which is by default &amp;lt;tt&amp;gt;&amp;quot;UTF-8&amp;quot;&amp;lt;/tt&amp;gt;, and very probably should not be changed.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; attribute does not refer to vivification of summit catalogs, but should invariably be set in this context. When scattering from summit, normally the branch catalog is automatically created if there is the corresponding summit catalog. When vivification is engaged, this would result in creation of empty branch catalogs too, which is not desired for two reasons. Firstly, empty branch catalogs would become part of the released language pack, for which there is no practical reason. Secondly, KDE's i18n system regards an application with installed catalog as translated, so messages coming from basic system catalogs (e.g. &amp;lt;tt&amp;gt;kdelibs4&amp;lt;/tt&amp;gt;) would show through, resulting in mostly untranslated user interface with specks of translation -- many users consider this rather ungainly. Therefore, &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; sets how complete the translation of currently non-existing branch catalog should be after scatter (0.0 empty, 1.0 fully complete), for the branch catalog to actually be created. If the &amp;lt;tt&amp;gt;--force&amp;lt;/tt&amp;gt; option is given to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, the branch catalog will be created regardless of its translation state, which may be handy in combination with [[#Operation Targets|operation target]] when wanting to check work in progress in running application.&lt;br /&gt;
&lt;br /&gt;
If [[#Merging with Compendium|the compendium has been set]] for merging, every vivified summit catalog will also be merged against the compendium, to fill out as many of messages with approximate translations.&lt;br /&gt;
&lt;br /&gt;
=== Scatter Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Checks, modifications...))&lt;br /&gt;
&lt;br /&gt;
=== Merge Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Special header fields...))&lt;br /&gt;
&lt;br /&gt;
== Disadvantages to Summit and Remedies ==&lt;br /&gt;
&lt;br /&gt;
Although hopefully shadowed by the advantages, working in summit is not without its disadvantages. These should be weighed when deciding of whether to try out the summit workflow.&lt;br /&gt;
&lt;br /&gt;
Obviously, while summit operations are made to be quite automatic, some extra aptitude is asked of the team coordinator. Reasonable shell handling, understanding of version control operations, feeling the pulse of repository automation, are all prerequisites, and some scripting ability advantageous.&lt;br /&gt;
&lt;br /&gt;
After the summit is put in operation, any changes made manually in branch POs will not propagate to summit, and will be soon lost to scattering -- summit translations override everything in branches. This means that the whole team must work in the summit, it is not possible for some members to use the summit, and some not.&lt;br /&gt;
&lt;br /&gt;
A summit PO file will necessarily have more messages than either of the branch files. For example, in the KDE 4.0/4.1 and 4.1/4.2 cycle, summit POs of core KDE modules had on average less than 5% more words than their stable counterparts. However, the said percent is the top, never approached limit of wasted workload due to trunk messages coming and going, given that as the next feature KDE release approaches, more and more trunk messages will find their way into it.&lt;br /&gt;
&lt;br /&gt;
Another, more pressing issue with increased size of summit POs is the following scenario: a stable release is around the corner, and the team has no time to update summit POs fully, but could update only stable messages in them. E.g. there are 1000 untranslated and fuzzy messages, out of which only 100 are from the stable branch. A clever dedicated PO editor could allow jumping only through untranslated and fuzzy messages which also satisfy a general search criteria, which in this case would be that a comment matches &amp;lt;tt&amp;gt;#\.\+&amp;gt;.*stable&amp;lt;/tt&amp;gt; regular expression. On the other hand, with some external help, it is enough if the PO editor can merely search through comments. Then, the &amp;lt;tt&amp;gt;posieve&amp;lt;/tt&amp;gt; command (ready to use next to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;) can equip untranslated and fuzzy stable messages with &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag (producing &amp;lt;tt&amp;gt;#, ..., untranslated&amp;lt;/tt&amp;gt; comment), and this flag can be searched for in the PO editor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve tag-untranslated -sbranch:stable -swfuzzy PATHS_TO_PO_FILES_OR_DIRS&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag does not need to be manually removed when the message is updated. It will automatically disappear on the next merge, as it is not among flags known to Gettext.&lt;br /&gt;
&lt;br /&gt;
There is also the organizational issue with starting to use the summit, and, if it does not help as expected, stopping to use it. Team members have to be reminded to not send in branch POs at start, and then to be sent back to branch POs if summit is disbanded. On the plus side, disbanding summit is technically simple: just remove from the repository {{path|l10n-supprot/LANG/summit}}, possibly also &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; files if [[#Fully Local Merging|fully local merging]] was set up, and that is it.&lt;br /&gt;
&lt;br /&gt;
== Another Way to Improve Branch Handling ==&lt;br /&gt;
&lt;br /&gt;
If summit seems a lot to digest, or is simply an overkill for team's needs, but still some improvement to manual handling of branches would be welcomed, KDE's dedicated PO editor [[Localization/Tools/Lokalize|Lokalize]] offers a ''branch sync'' mode. It works as follows.&lt;br /&gt;
&lt;br /&gt;
In Lokalize project definition, the local paths of trunk and stable PO roots are set in ''Translation directory:'' and ''Branch directory:'' fields. Then, when a trunk PO file is opened, if it has a stable counterpart with same name and location as in the trunk, this stable PO is also going to be opened. For each trunk message in the main editing pane, if such a message exists in stable PO too, the stable message will be shown in the ''Secondary Sync'' pane; changes in the translation of trunk message will reflect to the stable message, and stable PO file will also be saved when the trunk is saved.&lt;br /&gt;
&lt;br /&gt;
Furthermore, any team member can personally choose to work like this, there is no need to change the workflow of the language team as whole. When sending modifications to the coordinator, team members who rely on this feature of Lokalize simply send both trunk and stable POs that got modified.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Summit</id>
		<title>Localization/Workflows/PO Summit</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Summit"/>
				<updated>2010-01-19T14:33:37Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: Added command for upating the repository tree.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Translating in Summit|&lt;br /&gt;
prereqs=[[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Software Branches and Translation ==&lt;br /&gt;
&lt;br /&gt;
The obvious approach to releasing software is for developers to focus on one central body of code, a single &amp;quot;branch&amp;quot;, fixing bugs and adding new features to it, and from time to time taking a &amp;quot;snapshot&amp;quot; of the branch and packing it as next release. One approach to make the release process more robust, is for development to proceed in two parallel branches. From the &amp;quot;stable&amp;quot; branch the actual releases are made, mostly with bugs fixed and only very important features added. The other, &amp;quot;unstable&amp;quot; branch, is used to develop new and redesign existing features, and at some point will become the next stable branch. Depending on the project, releases may be made from the unstable branch as well, in parallel with stable releases, in order for eager users to help testing the novelties.&lt;br /&gt;
&lt;br /&gt;
In KDE, all three release models may be present at any given moment. Core KDE modules, which are together labeled as &amp;quot;the KDE&amp;quot; and released in unison, follow the two branch model, with stable and trunk branch, and releases from stable branch only. KDE extragear applications may do the same, but they are not required to; they may instead make releases from the trunk branch only, or also use stable and trunk branch, but make releases from both. This presents translators with the workflow as on the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_branches.png|center|Classic translation by branches]]&lt;br /&gt;
&lt;br /&gt;
The KDE [[Localization/Workflows/Repository_Automation|repository automation]] (aka &amp;quot;Scripty&amp;quot;) is preparing template POs and merging them with language POs. From the point of view of language teams, real people who perform global actions (e.g. moving around POs for all languages when an application moves from module to another) can also be grouped here. However, the translation team is still presented with two branches of POs to translate.&lt;br /&gt;
&lt;br /&gt;
In general, this means that, just like programmers, at times translators have to work on both branches, and propagate fixes from one branch to another (&amp;quot;backport&amp;quot; from trunk to stable, or &amp;quot;forwardport&amp;quot; from stable to trunk). This may be prone to coordinatorial confusion, and demand extra effort and attention when updating translations. Keeping up with two branches is easier in core KDE modules, as they are released from stable branch only and with singular schedule, but could be more taxing with extragear applications.&lt;br /&gt;
&lt;br /&gt;
The exact amount of effort spent due to parallel translation, porting of fixes, and coordination, depends on the translation team. For example, a well-manned and well-coordinated team, with established style and terminology guides, custom automation to support these, may be able to keep all POs in both branches fully translated at all times with ease. Or, a team may have worked out well-defined schedules, such that any given member of the team at one point switches from translating one branch to another, without looking back, thus effectively having everyone always working on one branch (even if not the same one).&lt;br /&gt;
&lt;br /&gt;
If, however, you as the team coordinator have said and thought &amp;quot;Should do that in trunk too, bugger&amp;quot;, &amp;quot;Didn't we fix that already?&amp;quot;, &amp;quot;No, you should take it from stable&amp;quot;, &amp;quot;It was released from WHAT branch?&amp;quot;, more often than you would have liked, the following presents one possibility for sidestepping such issues.&lt;br /&gt;
&lt;br /&gt;
== Translating in Summit ==&lt;br /&gt;
&lt;br /&gt;
For a PO catalog which exists in both stable and trunk branch, a new same-named catalog can be made by ''gathering'' all the unique messages from branch PO files, i.e. the ''summit'' of branch POs. Assuming that branch POs were not all that different, since they are two versions of the same catalog, the summit PO shouldn't have much more messages than either. Translators at all times work on the summit PO, from which the messages are periodically ''scattered'' back to original branch POs. Thus, translators can always work on summit POs, not having to do any parallel translation, branch switching or porting of fixes. The summit workflow is presented by the following figure.&lt;br /&gt;
&lt;br /&gt;
[[Image:Translating_in_summit.png|center|Translation in summit]]&lt;br /&gt;
&lt;br /&gt;
In the summit mode, repository automation gathers summit PO templates from branch templates, and stores them separately from real branches, at {{path|trunk/l10n-support/templates/summit/}}. The language team also has a collection summit POs, at {{path|trunk/l10n-support/LANG/summit/}}, which is the sole location where translation happens. As before, repository automation handles merging of templates in branches, but merging of summit POs is done by the team coordinator; team coordinator can opt to manually merge branch POs as well (more on why-and-how of this later). From time to time, the team coordinator fills out branch POs by scattering from summit. Not to worry, each of these special actions upon the team coordinator is done with a single command.&lt;br /&gt;
&lt;br /&gt;
While it is in principle obvious that two branch POs can be made into one summit PO with the union of their messages, there are some important details that should be handled the right way by the summitting system:&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes modules in one branch, so that it no longer belongs to the same module in both branches (e.g. application is moved from one to another module in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO changes its name in one branch, but not in the other (e.g. application is renamed in trunk)?&lt;br /&gt;
&lt;br /&gt;
* What if a PO in one branch is split into two POs in another (e.g. extracting a library out of monolithic application in trunk)?&lt;br /&gt;
&lt;br /&gt;
* Where to place messages unique to one branch in the summit PO? The original file context of a message, which messages precede it and which follow it, should be kept as much as possible.&lt;br /&gt;
&lt;br /&gt;
* If source references are used to achieve good ordering of messages in summit PO, what to do if some source file paths change in one branch (e.g. application gets restructured in trunk)?&lt;br /&gt;
&lt;br /&gt;
* How to handle messages with different plurality across branches (since messages are identified only by their &amp;lt;tt&amp;gt;msgctxt&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; field, an not &amp;lt;tt&amp;gt;msgid_plural&amp;lt;/tt&amp;gt;)?&lt;br /&gt;
&lt;br /&gt;
And handle these details it does, the present summitting system. This also means that teams working in the summit need not take care of the first three issues above, which are affecting manual branch handling too.&lt;br /&gt;
&lt;br /&gt;
Summit POs are normal, fully valid POs in their own right. A message in a summit PO is different from branch PO only by being equipped with another comment, &amp;lt;tt&amp;gt;#. +&amp;gt; ...&amp;lt;/tt&amp;gt;, showing in which branches the message exists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgctxt &amp;quot;The destination url of a job&amp;quot;&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:469&lt;br /&gt;
msgid &amp;quot;Destination:&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
⁠&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#: kdeui/jobs/kwidgetjobtracker.cpp:517&lt;br /&gt;
msgid &amp;quot;&amp;amp;Keep this window open after transfer is complete&amp;quot;&lt;br /&gt;
msgstr &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first message above thus exists in trunk only, the second in stable only, and the third in both branches. The source reference always points to the source file in the first listed branch. Any extracted comments (&amp;lt;tt&amp;gt;#.&amp;lt;/tt&amp;gt;) other than the branch list are also taken from the first listed branch.&lt;br /&gt;
&lt;br /&gt;
Note that the two messages above are different only by context; the context was added in trunk, but not in stable, in order not to break message freeze. However, due to careful ordering of messages in summit POs, these two messages appear together, allowing translator to immediately make correction in stable branch too if the new context in trunk shows it to be necessary.&lt;br /&gt;
&lt;br /&gt;
=== Setting Up and Daily Operation ===&lt;br /&gt;
&lt;br /&gt;
Before initializing language summit, the team coordinator has to have all the necessary paths checked out from the KDE repository, and structured on the local machine exactly as in the repository. If the path to the root of KDE repository on the local machine is &amp;lt;tt&amp;gt;$KDEREPO&amp;lt;/tt&amp;gt;, and the language code &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt;, then the structure should be as follows, with leaf directories checked out in full:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-kde4/&lt;br /&gt;
            scripts/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            scripts/&lt;br /&gt;
            pology/&lt;br /&gt;
            templates/&lt;br /&gt;
            LANG/&lt;br /&gt;
    branches/&lt;br /&gt;
        stable/&lt;br /&gt;
            l10n-kde4/&lt;br /&gt;
                scripts/&lt;br /&gt;
                templates/&lt;br /&gt;
                LANG/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that this structure is fully under version control (rather than e.g. top directories being manually created), so if that is not the case, the following commands will fetch everything anew in proper order:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
cd $KDEREPO&lt;br /&gt;
svn co --depth=empty svn+ssh://svn.kde.org/home/kde .&lt;br /&gt;
svn up --depth=empty branches branches/stable branches/stable/l10n-kde4&lt;br /&gt;
svn up --depth=empty trunk trunk/l10n-support trunk/l10n-kde4&lt;br /&gt;
svn up branches/stable/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-kde4/{scripts,templates,LANG}&lt;br /&gt;
svn up trunk/l10n-support/{pology,scripts,templates,LANG}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the trailing dot in the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command, and do not miss to substitute LANG for the real language code in the last three commands. &amp;lt;tt&amp;gt;--depth=empty&amp;lt;/tt&amp;gt; option prevents recursive fetching, so that e.g. the first &amp;lt;tt&amp;gt;svn&amp;lt;/tt&amp;gt; command does not fetch the complete repository tree. Later you can regularly update this tree with single command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
svn up $KDEREPO/{trunk,branches/stable}/l10n-kde4/{scripts,templates,cs} \&lt;br /&gt;
       $KDEREPO/trunk/l10n-support/{pology,scripts,templates,cs}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Summit operations are performed using the &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; command, which is part of [[Localization/Tools/Pology|Pology]], residing in {{path|trunk/l10n-support/pology/}}. Therefore the first thing to do is to setup Pology, which amounts only to setting the proper path:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ export PATH=$KDEREPO/trunk/l10n-support/pology/bin:$PATH&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To initialize the summit, by gathering from existing translation in branches, the team coordinator executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Depending on the amount of translation, after some minutes the initial gathering will have been completed, and language summit located under {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages/}}. This is the only time when the coordinator performs the gather operation on language POs; it is daily done only on templates by repository automation. Then, the created language summit should be merged with current summit templates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Merging the summit is something that the coordinator does periodically, with frequency of own desire. For example, it can be done daily, or with increasing frequency as the last day for translation for the next release approaches.&lt;br /&gt;
&lt;br /&gt;
After the first merging, language summit is ready for active translation. The coordinator should now commit {{path|$KDEREPO/trunk/l10n-support/LANG/}}, and, importantly, notify team members to stop working on branch POs and focus exclusively on summit POs.&lt;br /&gt;
&lt;br /&gt;
To scatter the summit, i.e. fill out POs in stable and trunk branch from the summit POs, the coordinator periodically executes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As with merging, there is no fixed schedule when scattering should be done. Of course, it must necessarily be done before the next release is tagged, and in between it is useful to scatter for runtime testing, or to have translation statistics by branches on l10n.kde.org up to date.&lt;br /&gt;
&lt;br /&gt;
Periodic scattering and merging of the complete summit are basically all that a language team coordinator needs to do specifically to operate the summit. Also, since {{path|l10n-support/scripts/}} and {{path|l10n-support/pology/}} contain scripts and settings critical for proper functioning of summit operations, and may be tweaked at any time, they should always be updated from the repository together with PO files and templates (in fact, it is best to always update at once the whole tree as outlined above).&lt;br /&gt;
&lt;br /&gt;
{{note|For documentation POs, summit setup and operation is the same, only replacing every &amp;lt;tt&amp;gt;messages&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;docmessages&amp;lt;/tt&amp;gt; in the command lines above. The user interface and documentation summits are fully independent, so for a trial period it is reasonable to work with the interface summit only, and engage documentation summit once the trial has been deemed successfull.}}&lt;br /&gt;
&lt;br /&gt;
=== Operation Targets ===&lt;br /&gt;
&lt;br /&gt;
Sometimes it is advantageous to merge or scatter just a single catalog, a single module, a single branch, or any combination thereof. To this end, scatter and merge operations accept any number of ''operation targets'' after the operation keyword, specified as one of &amp;lt;tt&amp;gt;''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''CATALOG''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''MODULE''/&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;''BRANCH'':''MODULE''/&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;''BRANCH'':&amp;lt;/tt&amp;gt;. For example, to scatter just to Dolphin's PO in stable branch, in order to test translation at runtime, one would execute:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(note no &amp;lt;tt&amp;gt;.po&amp;lt;/tt&amp;gt; ending on catalog name). Or, to scatter to every PO in &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; module in stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:kdeplasma-addons/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the trailing slash is mandatory, or else &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; would think that &amp;lt;tt&amp;gt;kdeplasma-addons&amp;lt;/tt&amp;gt; is a catalog name). Finally, to scatter to all catalogs in the stable branch (with the trailing colon for the same reason as earlier):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter stable:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command line arguments of &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; operations are intentionally arranged such that all the arguments fixed for one language are placed first. If operation targets are used frequently, then it is convenient to place the immutable part of the command line under a shell alias, with absolute path to the summit setup file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ alias posummit-kde-LANG=&amp;quot;posummit $KDEREPO/trunk/l10n-support/scripts/messages.summit LANG&amp;quot;&lt;br /&gt;
$ cd ANYWHERE&lt;br /&gt;
$ posummit-kde-LANG scatter stable:dolphin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Externally Injected Branch Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Once the summit is in operation, normally the only way for a catalog to appear in branches (trunk or stable) is through scattering from the summit. However, sometimes an application which had seen considerable development outside of the infrastructure of KDE project gets moved in, drawing in any of its existing translations into branches. Such externally injected branch catalogs cause warnings to be issued on summit merging, and outright failure on scattering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/foobar.po  # dummy injection&lt;br /&gt;
$ touch ../l10n-kde4/LANG/messages/kdetoys/libfoobar.po  # dummy injection&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge&lt;br /&gt;
...&lt;br /&gt;
posummit: warning: No summit catalog for branch catalog &lt;br /&gt;
    '../l10n-kde4/LANG/messages/kdetoys/foobar.po'.&lt;br /&gt;
posummit: warning: No summit catalog for branch catalog &lt;br /&gt;
    '../l10n-kde4/LANG/messages/kdetoys/libfoobar.po'.&lt;br /&gt;
...&lt;br /&gt;
$&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter&lt;br /&gt;
...&lt;br /&gt;
posummit: error: Missing necessary summit catalogs: foobar libfoobar&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When this happens, the injected catalogs need to be gathered into the summit. This is done just like the initial gathering, only giving injected catalogs' names as operation targets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posummit scripts/messages.summit LANG gather --create --force foobar libfoobar&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Summit Customization ===&lt;br /&gt;
&lt;br /&gt;
File {{path|scripts/messages.summit}} (i.e. {{path|$KDEREPO/trunk/l10n-support/scripts/messages.summit}}), given as first argument to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, contains the general summit setup for all languages. This file is set to include customization file per language, if it exists at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages.extras.summit}}, which contains additions and overrides to the general setup as desired by the language team. Same as the general setup file, the customization file is a Python source. It uses an external object named &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; to define summit settings, and can, of course, contain any helper Python code (the file is executed only once, at the beginning of a &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; run). It has the following general layout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# -*- coding: UTF-8 -*-&lt;br /&gt;
# kate: syntax Python;&lt;br /&gt;
# This file is included by scripts/messages.summit&lt;br /&gt;
# for language-specific additions/overrides.&lt;br /&gt;
#&lt;br /&gt;
# ...&lt;br /&gt;
# ... operations with object S and other Python code ...&lt;br /&gt;
# ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Object &amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt; provides both data attributes and methods to configure different aspects of summit operation. For example, while the general setup specifies that text fields in summit catalogs should not be wrapped on column but should be wrapped on logical breaks (like some markup tags), this can be overriden using &amp;lt;tt&amp;gt;summit_wrap&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;summit_fine_wrap&amp;lt;/tt&amp;gt; attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.summit_wrap = True&lt;br /&gt;
S.summit_fine_wrap = False&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or, to get the path to a file relative to the summit customization file itself (rather than to current working directory, where &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; was executed), method &amp;lt;tt&amp;gt;resolve_path_rooted&amp;lt;/tt&amp;gt; can be used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
relpath = S.resolve_path_rooted(&amp;quot;../whatever.txt&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following sections will present some typical customization possibilities.&lt;br /&gt;
&lt;br /&gt;
=== Fully Local Merging ===&lt;br /&gt;
&lt;br /&gt;
When scattering from the summit, sometimes there will be reports of &amp;quot;messages missing in the summit&amp;quot;. This happens because of time rift created by the Scripty merging branch POs, gathering summit templates, and a team coordinator merging the language summit, thus making some messages in branch POs not always present in the summit. This condition is benign, as such warnings will start to disappear with the message freeze approaching, but can be annoying. For this reason, team coordinator can stop Scripty from merging branch POs, and have the &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; command alone merge not only summit POs, but stable and trunk POs as well, such that summit and branches are always in perfect sync.&lt;br /&gt;
&lt;br /&gt;
First, to stop Scripty from merging branch POs, a file named &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; (with arbitrary content) should be committed to the roots of respective trees, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$ touch $KDEREPO/trunk/l10n-kde4/messages/LANG/no-auto-merge&lt;br /&gt;
$ touch $KDEREPO/branches/stable/l10n-kde4/LANG/messages/no-auto-merge&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, to make summit &amp;lt;tt&amp;gt;posummit ... merge&amp;lt;/tt&amp;gt; merge everything, the following lines should be added into the summit customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Set local merging for all branches.&lt;br /&gt;
for branch in S.branches:&lt;br /&gt;
    branch[&amp;quot;merge_locally&amp;quot;] = True&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once local merging of all branches is set, the coordinator can also use operation targets for selective merging, e.g. to merge only stable branch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG merge stable:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Merging with Compendium ===&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; takes into account only the catalog itself to fill out near-match translations to new messages introduced by merging. i.e. to produce fuzzy messages. However, an arbitrary PO file can be given to &amp;lt;tt&amp;gt;msgmerge&amp;lt;/tt&amp;gt; as another possible source of earlier translations, through the &amp;lt;tt&amp;gt;--compendium&amp;lt;/tt&amp;gt; option. For maximum effect, this PO file is usually constructed as the collection of messages from all PO files project-wide, and hence called the ''compendium''.&lt;br /&gt;
&lt;br /&gt;
Compendium can be used in summit merge operations simply by setting &amp;lt;tt&amp;gt;compendium_on_merge&amp;lt;/tt&amp;gt; attribute in summit customization file. If the compendium is located at {{path|$KDEREPO/trunk/l10n-support/LANG/summit/messages-compendium.po}}, then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Compendium to use when merging summit catalogs.&lt;br /&gt;
S.compendium_on_merge = S.resolve_path_rooted(&amp;quot;messages-compendium.po&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that if not located as above, compendium should not be placed within {{path|.../LANG/summit/messages/}}, as then it would be considered a summit catalog itself. In case fully local merging is engaged, only summit POs will be merged with compendium; it makes no sense for branch POs, since they are not being directly translated.&lt;br /&gt;
&lt;br /&gt;
See [http://www.gnu.org/software/automake/manual/gettext/Creating-Compendia.html &amp;quot;Creating Compendia&amp;quot;] section of Gettext manual for details on how to create a compendium out of current body of summit translations. Once you establish the precise commands to create the compendium (whether to collect fuzzies too, whether to include old compendium as one of sources for the new, etc.), you would periodically refresh and commit the updated compendium.&lt;br /&gt;
&lt;br /&gt;
=== Vivifying Summit Catalogs ===&lt;br /&gt;
&lt;br /&gt;
Translation of a summit catalog normally starts the same way as it did for branch catalogs, by copying it over from template and initializing the header. This can be done manually, but it can also be quite automatic when using project manager as sometimes provided by dedicated PO editors. However, relying on the editor's project manager can be disadvantageous at times. For example, aside from the PO editor, other, frequently command line tools may be used to process the body of translation, and these tools might need to consider non-started templates as if they were empty POs (e.g. statistics). Team members who do not have full local checkout, or no project set up in the editor, may need to jump between language and template directories when looking for files to translate.&lt;br /&gt;
&lt;br /&gt;
Therefore, summit setup can be customized to automatically create (&amp;quot;vivify&amp;quot;) summit catalogs for every new summit template, so that there is never the need (for a tool or human) to specifically treat templates as empty catalogs. This is done by adding the following lines into customization file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
# Create empty summit catalog for every new summit template.&lt;br /&gt;
S.vivify_on_merge = True&lt;br /&gt;
S.vivify_w_translator = &amp;quot;Noone Noonian &amp;lt;noone.noonian@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_langteam = &amp;quot;Neverneese &amp;lt;neverteam@nowhere.null&amp;gt;&amp;quot;&lt;br /&gt;
S.vivify_w_plurals = &amp;quot;nplurals=2; plural=n != 1;&amp;quot;&lt;br /&gt;
# Minimum translation state to create branch catalog on scatter.&lt;br /&gt;
S.scatter_min_completeness = 0.9&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;vivify_w_*&amp;lt;/tt&amp;gt; attributes set the necessary data to initialize headers of newly created summit catalogs. Aside from those listed above, there is also the &amp;lt;tt&amp;gt;vivify_w_charset&amp;lt;/tt&amp;gt; attribute, which is by default &amp;lt;tt&amp;gt;&amp;quot;UTF-8&amp;quot;&amp;lt;/tt&amp;gt;, and very probably should not be changed.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; attribute does not refer to vivification of summit catalogs, but should invariably be set in this context. When scattering from summit, normally the branch catalog is automatically created if there is the corresponding summit catalog. When vivification is engaged, this would result in creation of empty branch catalogs too, which is not desired for two reasons. Firstly, empty branch catalogs would become part of the released language pack, for which there is no practical reason. Secondly, KDE's i18n system regards an application with installed catalog as translated, so messages coming from basic system catalogs (e.g. &amp;lt;tt&amp;gt;kdelibs4&amp;lt;/tt&amp;gt;) would show through, resulting in mostly untranslated user interface with specks of translation -- many users consider this rather ungainly. Therefore, &amp;lt;tt&amp;gt;scatter_min_completeness&amp;lt;/tt&amp;gt; sets how complete the translation of currently non-existing branch catalog should be after scatter (0.0 empty, 1.0 fully complete), for the branch catalog to actually be created. If the &amp;lt;tt&amp;gt;--force&amp;lt;/tt&amp;gt; option is given to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;, the branch catalog will be created regardless of its translation state, which may be handy in combination with [[#Operation Targets|operation target]] when wanting to check work in progress in running application.&lt;br /&gt;
&lt;br /&gt;
If [[#Merging with Compendium|the compendium has been set]] for merging, every vivified summit catalog will also be merged against the compendium, to fill out as many of messages with approximate translations.&lt;br /&gt;
&lt;br /&gt;
=== Scatter Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Checks, modifications...))&lt;br /&gt;
&lt;br /&gt;
=== Merge Hooks ===&lt;br /&gt;
&lt;br /&gt;
((TODO. Special header fields...))&lt;br /&gt;
&lt;br /&gt;
== Disadvantages to Summit and Remedies ==&lt;br /&gt;
&lt;br /&gt;
Although hopefully shadowed by the advantages, working in summit is not without its disadvantages. These should be weighed when deciding of whether to try out the summit workflow.&lt;br /&gt;
&lt;br /&gt;
Obviously, while summit operations are made to be quite automatic, some extra aptitude is asked of the team coordinator. Reasonable shell handling, understanding of version control operations, feeling the pulse of repository automation, are all prerequisites, and some scripting ability advantageous.&lt;br /&gt;
&lt;br /&gt;
After the summit is put in operation, any changes made manually in branch POs will not propagate to summit, and will be soon lost to scattering -- summit translations override everything in branches. This means that the whole team must work in the summit, it is not possible for some members to use the summit, and some not.&lt;br /&gt;
&lt;br /&gt;
A summit PO file will necessarily have more messages than either of the branch files. For example, in the KDE 4.0/4.1 and 4.1/4.2 cycle, summit POs of core KDE modules had on average less than 5% more words than their stable counterparts. However, the said percent is the top, never approached limit of wasted workload due to trunk messages coming and going, given that as the next feature KDE release approaches, more and more trunk messages will find their way into it.&lt;br /&gt;
&lt;br /&gt;
Another, more pressing issue with increased size of summit POs is the following scenario: a stable release is around the corner, and the team has no time to update summit POs fully, but could update only stable messages in them. E.g. there are 1000 untranslated and fuzzy messages, out of which only 100 are from the stable branch. A clever dedicated PO editor could allow jumping only through untranslated and fuzzy messages which also satisfy a general search criteria, which in this case would be that a comment matches &amp;lt;tt&amp;gt;#\.\+&amp;gt;.*stable&amp;lt;/tt&amp;gt; regular expression. On the other hand, with some external help, it is enough if the PO editor can merely search through comments. Then, the &amp;lt;tt&amp;gt;posieve&amp;lt;/tt&amp;gt; command (ready to use next to &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt;) can equip untranslated and fuzzy stable messages with &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag (producing &amp;lt;tt&amp;gt;#, ..., untranslated&amp;lt;/tt&amp;gt; comment), and this flag can be searched for in the PO editor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ posieve tag-untranslated -sbranch:stable -swfuzzy PATHS_TO_PO_FILES_OR_DIRS&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;untranslated&amp;lt;/tt&amp;gt; flag does not need to be manually removed when the message is updated. It will automatically disappear on the next merge, as it is not among flags known to Gettext.&lt;br /&gt;
&lt;br /&gt;
There is also the organizational issue with starting to use the summit, and, if it does not help as expected, stopping to use it. Team members have to be reminded to not send in branch POs at start, and then to be sent back to branch POs if summit is disbanded. On the plus side, disbanding summit is technically simple: just remove from the repository {{path|l10n-supprot/LANG/summit}}, possibly also &amp;lt;tt&amp;gt;no-auto-merge&amp;lt;/tt&amp;gt; files if [[#Fully Local Merging|fully local merging]] was set up, and that is it.&lt;br /&gt;
&lt;br /&gt;
== Another Way to Improve Branch Handling ==&lt;br /&gt;
&lt;br /&gt;
If summit seems a lot to digest, or is simply an overkill for team's needs, but still some improvement to manual handling of branches would be welcomed, KDE's dedicated PO editor [[Localization/Tools/Lokalize|Lokalize]] offers a ''branch sync'' mode. It works as follows.&lt;br /&gt;
&lt;br /&gt;
In Lokalize project definition, the local paths of trunk and stable PO roots are set in ''Translation directory:'' and ''Branch directory:'' fields. Then, when a trunk PO file is opened, if it has a stable counterpart with same name and location as in the trunk, this stable PO is also going to be opened. For each trunk message in the main editing pane, if such a message exists in stable PO too, the stable message will be shown in the ''Secondary Sync'' pane; changes in the translation of trunk message will reflect to the stable message, and stable PO file will also be saved when the trunk is saved.&lt;br /&gt;
&lt;br /&gt;
Furthermore, any team member can personally choose to work like this, there is no need to change the workflow of the language team as whole. When sending modifications to the coordinator, team members who rely on this feature of Lokalize simply send both trunk and stable POs that got modified.&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-01-13T23:34:05Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: -O option renamed to -o.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading'', ''approving''), each of which may return the translation to a previous stage, or forward it to some special stage. The process can also be more finer grained, where each message in the file goes through stages separately.&lt;br /&gt;
&lt;br /&gt;
Regardless of the particularities, workflows of this kind all have the following in common. Members of the translation team are assigned ''roles'' -- such as ''translator'', ''reviewer'', ''approver'', ''committer'' -- by which they enter into the workflow (single person can have more roles). The later review stages must wait for the earlier stages to complete, and the translation cannot be updated again before the current version clears the pipeline (or the pipeline is aborted). Most importantly, once the translation is committed, it becomes part of simply &amp;quot;admitted&amp;quot; translations, with no further qualifiers.&lt;br /&gt;
&lt;br /&gt;
The system of prescribed roles requires that team members assign them between themselves, stick to them, and shuffle them along the way. The prescribed review pipeline requires a tool to enforce and keep track of the stages in which translations are. This makes the review workflow complex and rigid, most probably with choke points for efficiency. Distribution of roles may become disbalanced by people coming and going, or the workflow tool may be prohibitive to some scenarios (e.g. single translator making small adjustments in dozens of files across the project, but having to upload each manually through a web interface).&lt;br /&gt;
&lt;br /&gt;
Of course, &amp;quot;rigid&amp;quot;, &amp;quot;complex&amp;quot;, &amp;quot;inefficient&amp;quot;, are comparative qualifications, so what is it that the classical review by stages can be compared to in this way?&lt;br /&gt;
&lt;br /&gt;
== Reviewing by Ascriptions ==&lt;br /&gt;
&lt;br /&gt;
Reviewing by ascriptions is even simpler conceptually, and yet less rigid, less complex, and much more efficient than the review by stages. It works on the message-level, rather than file-level. Anyone can simply translate some messages and directly commit modified files, without any review, but with ''ascribing'' modifications to own name. Anyone can review any committed messages at any moment, commit the modifications-on-review and ascribe reviews to own name and (possibly) to certain class -- full review, review of context, of terminology, of style, etc. Only when the translation is to be shipped to end users, the ''insufficiently'' reviewed messages are automatically omitted from the package, by evaluating the ''ascription history'' of each message.&lt;br /&gt;
&lt;br /&gt;
Most importantly, based on the ascription history, the reviewer can select only some particular messages, and review only the difference between their historical and current versions. For example, Alice can select to review only messages modified since she or Bob had last reviewed them for style; she could see the difference from that last review to current version, e.g. if in the whole paragraph only a single word has changed by Charlie when he reviewed the terminology. In terms of PO workflow, the ascription history propagates through merges, so the reviewer can compare the change in original and the change in translation since the last review, to judge if one fits the other.&lt;br /&gt;
&lt;br /&gt;
Since everyone just commits, translations can be efficiently kept in a version control repository, with the ascription system added on top. After having done some translating, the team member simply substitutes commit command of the version control system (VCS) with ascribe-modifications command of the ascription system (AS, which calls the underlying VCS internally). After reviewing, the team member uses ascribe-reviews command of the AS to commit reviews to ascription history (as well as modifications made during the review). To select messages for review, the team member issues diff-for-review command of the AS (with suitable parameters to narrow the set) and selected messages are marked in-place in PO files and [[Localization/Tools/Pology/PO_Embedded_Diffing|embedded with differences]], and possibly popped open in a PO editor.&lt;br /&gt;
&lt;br /&gt;
When the translations are to be released, the team coordinator issues filter-for-release command of the AS, which takes the working PO files and creates final PO files with insufficiently reviewed messages removed. &amp;quot;Release time&amp;quot; is used here only figuratively: this should be a fully automatic process, so it can be performed at any interval of convenience.&lt;br /&gt;
&lt;br /&gt;
What constitutes &amp;quot;sufficient review&amp;quot; can be defined in fine detail. It could be specified that messages modified by Alice need to have only review for terminology, but not necessarily for style; Charlie may belong to the group which needs to be reviewed on style, but not necessarily on context; Bob's reviews for style may be nice to have, but never blocking if missing. These decisions do not preclude released messages to be reviewed later on missing points, after higher priority reviews have been completed. The definition of sufficiency may be changed at any point, e.g. as team members get more experienced and require less review, without interfering with direct translation and review work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- (Here is one unorthodox possibility of using reviews by ascriptions. A random translator may want to keep an eye on what the reviewers change in the files he maintains. For example, to learn what are typical small errors that he makes while translating. Therefore, he himself reviews any modifications not made by him after his last review, and commits them. This will in no way interfere with &amp;quot;canonical&amp;quot; reviews, those considered at release time.) //--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In summary, with reviewing by ascriptions the lean efficiency of raw VCS operation is preserved while providing for great flexibility of review. All team members can be given commit access, no web or email detours are needed. There are no prescribed roles, but an equivalent of role assignment happens automatically at last possible moment, and can take into account both translators' and reviewers' abilities. There is no staging between completing and committing the translation, which enables translator to keep on polishing the translation undisturbed until the reviewer comes around. There is no inefficiency in handling small changes throughout many files, since single AS command commits all changes just as single VCS command would. AS in effect abstracts VCS, so general team members do not have to know the particularities of the underlying VCS. On commit operations, AS can also apply checks (e.g. decline to commit syntactically invalid PO files) and modifications (e.g. update translator's data in the PO header).&lt;br /&gt;
&lt;br /&gt;
== Ascription System in Pology ==&lt;br /&gt;
&lt;br /&gt;
[[Localization/Tools/Pology|Pology]] is a collection of various modular tools for supporting translation based on PO files. Among them is the script &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which implements an ascription system (AS); at present, it can use Subversion or Git as the underlying VCS. &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is still in experimental stage, so what follows is a brief description of how to use it in context of the KDE translation project. However, very little is truly specific to KDE; the only major assumption is that there exists a VCS repository with PO files of a given language grouped together, and that the translation team can use it without special restrictions.&lt;br /&gt;
&lt;br /&gt;
Very important for the AS is how branches are handled (in KDE, the rolling trunk and stable branches). AS can in principle be deployed by branch, but then there is the added complexity of porting translations between branches, which ascriptions should follow. Therefore, the AS implemented by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; is currently limited to assumption that there is a single branch of translations at all times. The article [[Localization/Workflows/PO_Summit|&amp;quot;Translating in Summit&amp;quot;]] explains how a KDE translation team can set up and operate such a single branch, the summit, and this is the prerequisite for the following instructions. (Note that the summit system is useful on its own, and should be conductive to any kind of review workflow.)&lt;br /&gt;
&lt;br /&gt;
== Setting Up ==&lt;br /&gt;
&lt;br /&gt;
The summit branch for the language &amp;lt;tt&amp;gt;LANG&amp;lt;/tt&amp;gt; is positioned like this in the KDE repository:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
$KDEREPO/&lt;br /&gt;
    trunk/&lt;br /&gt;
        l10n-support/&lt;br /&gt;
            LANG/&lt;br /&gt;
                summit/&lt;br /&gt;
                    messages/&lt;br /&gt;
                    docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The team coordinator already has this part of the repository tree locally due to regular summit operations. For the same reason Pology is already set up. Setting up the ascription system is now simple. The file &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; is created in the root of the summit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
# ---------------------------&lt;br /&gt;
# Global ascription settings.&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
&lt;br /&gt;
# The root of the ascription catalog tree.&lt;br /&gt;
ascript-root = ../summit-ascript&lt;br /&gt;
&lt;br /&gt;
# The underlying version control system.&lt;br /&gt;
version-control = svn&lt;br /&gt;
&lt;br /&gt;
# Data for updating catalog headers.&lt;br /&gt;
# - language code&lt;br /&gt;
language = LANG&lt;br /&gt;
# - full language name&lt;br /&gt;
language-team = LANGUAGE&lt;br /&gt;
# - email address of the team&lt;br /&gt;
team-email = kde-i18n-LANG@kde.org&lt;br /&gt;
&lt;br /&gt;
# Default commit message.&lt;br /&gt;
commit-message = Translation updates.&lt;br /&gt;
&lt;br /&gt;
# -----------------------&lt;br /&gt;
# Registered translators.&lt;br /&gt;
&lt;br /&gt;
[user-alice]&lt;br /&gt;
name = Alice Akmalryn&lt;br /&gt;
original-name = Алиса Акмалрин&lt;br /&gt;
email = alice.akmalryn@someplacenice.org&lt;br /&gt;
&lt;br /&gt;
[user-bob]&lt;br /&gt;
name = Bob Byomkin&lt;br /&gt;
original-name = Бобан Бјомкин&lt;br /&gt;
email = bob.byomkin@otherplacenice.org&lt;br /&gt;
&lt;br /&gt;
# ...and so on.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;ascript-root&amp;lt;/tt&amp;gt; setting should be exactly &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt;, for the reason mentioned later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit-message&amp;lt;/tt&amp;gt; field, if defined, allows team members to commit without providing a commit message. The value given by this field will be used by default, with translator's user name appended to the end in special syntax. For example: &amp;lt;tt&amp;gt;Translation updates. [&amp;gt;alice]&amp;lt;/tt&amp;gt;. (Translator's user name is also appended to manually supplied commit messages.) Translators can still supply a commit message when they wish, as shown later. If this field is not set, the commit message is supplied as usual on committing.&lt;br /&gt;
&lt;br /&gt;
* Team members are defined by &amp;lt;tt&amp;gt;[user-USERNAME]&amp;lt;/tt&amp;gt; sections. Ascription user names can be any valid ASCII identifier: ASCII letters, digits and underscores only, digit cannot be the first character. Ascription user names have no technical relation to the underlying VCS accounts, though it is mnemonically convenient if they are the same (in case of SVN). This means that a translator who does not have a VCS account (yet) can and should be added here, with assigned user name (best one suitable as SVN account name later); why this should be done will be explained later.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; field in user sections is there in case the preferred renderings of the name in English and in target language are not the same. When this is not the case, &amp;lt;tt&amp;gt;original-name&amp;lt;/tt&amp;gt; can be omitted.&lt;br /&gt;
&lt;br /&gt;
As soon as the &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt; file is committed, the ascription system is ready for operation. Only regular modifications to this file are those of adding new team members. (On the other hand, team members should never be removed, because even after they no longer contribute, their ascription records remain in the system.)&lt;br /&gt;
&lt;br /&gt;
=== Initial Ascription ===&lt;br /&gt;
&lt;br /&gt;
The most common situation at start of ascription workflow is that there already exists a body of translations, contributed to by many different people over time. The coordinator should ascribe all existing translations as initial modifications, but to whom? It cannot be said precisely who translated what. The solution is to introduce a generic user in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;, suitably known as &amp;quot;Unknown Hero&amp;quot; (or &amp;quot;Lost Translator&amp;quot;, you can be inventive):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[user-uhero]&lt;br /&gt;
name = Unknown Hero&lt;br /&gt;
original-name = Незнани јунак&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and ascribe all existing translations as modified and reviewed by this user. The coordinator does this with the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe reviewed -u uhero -C LANG/summit/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;tt&amp;gt;reviewed&amp;lt;/tt&amp;gt; is the ascription mode, and the &amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option provides the user name to which ascriptions are made. This is an important point: ascriptions are made to a user defined in ascription configuration, and have nothing to do with VCS accounts; someone who has the account can commit in the name of someone who does not. The &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option prevent automatic committing by &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;, which is useful for this initial step. Finally the paths which contain all summit catalogs are given.&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command is issued, a progress bar will appear, and the following output will start to unfold:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/rellinks.po  (50)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/autorefresh.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/babelfish.po  (38)&lt;br /&gt;
...&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/libphonon.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon-xine.po  (24)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon_gstreamer.po  (12)&lt;br /&gt;
===! Translated: 111775&lt;br /&gt;
===! Fuzzy: 26943&lt;br /&gt;
===! Obsolete translated: 2965&lt;br /&gt;
===! Obsolete fuzzy: 1626&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/rellinks.po  (50)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/autorefresh.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/extragear-base/babelfish.po  (38)&lt;br /&gt;
...&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/libphonon.po  (13)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon-xine.po  (24)&lt;br /&gt;
!    LANG/summit-ascript/messages/qt/phonon_gstreamer.po  (12)&lt;br /&gt;
===! Reviewed: 143309&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number in parenthesis indicates how many messages have been ascribed in the given PO file, and at the end the totals are given. Catalogs are processed twice, first to ascribe modifications and then reviews, because a review cannot be ascribed before the modification has been ascribed. Ascribing the complete summit for the first time will take quite some time (say 15-30 minutes).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--If, on the contrary, it is known who translated-reviewed what, ascription can be performed piece-wise with user names of real translators:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support/LANG/summit&lt;br /&gt;
$ poascribe reviewed -u alice -C kdelibs/ kdepimlibs/ kdebase/&lt;br /&gt;
$ poascribe reviewed -u bob -C kdemultimedia/ kdeutils/&lt;br /&gt;
$ ...&lt;br /&gt;
&amp;lt;/code&amp;gt;//--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the initial ascription has been made, the ascription tree will appear next to the summit tree. This tree will contain one ascription PO file for each summit PO file, with the same name and relative location within the tree:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
            ascription-config&lt;br /&gt;
        summit-ascript/&lt;br /&gt;
            messages/&lt;br /&gt;
                kdelibs/&lt;br /&gt;
                    kcertpart.po&lt;br /&gt;
                    kdelibs4.po&lt;br /&gt;
                    ...&lt;br /&gt;
                ...&lt;br /&gt;
            docmessages/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ascription tree can now be committed as usual (&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will have already added it):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit-ascript/ -m &amp;quot;Initial ascription.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Translators ==&lt;br /&gt;
&lt;br /&gt;
Team members other than the coordinator, whether translators or reviewers, need to keep around only the &amp;lt;tt&amp;gt;trunk/l10n-support/LANG/&amp;lt;/tt&amp;gt; directory. But they always need to update this directory fully (rather than just one particular module or file under &amp;lt;tt&amp;gt;.../*messages/&amp;lt;/tt&amp;gt;), so that the summit tree and the ascription tree (and configuration) are kept in sync.&lt;br /&gt;
&lt;br /&gt;
In order not to have to issue their own user name (&amp;lt;tt&amp;gt;-u&amp;lt;/tt&amp;gt; option to &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt;) all the time, translators can set it in Pology user configuration &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;, in &amp;lt;tt&amp;gt;[poascribe]&amp;lt;/tt&amp;gt; section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = alice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translators can then submit updated PO files simply by substituting &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt; (or whatever the VCS commit command is) with &amp;lt;tt&amp;gt;poascribe modified&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;mo&amp;lt;/tt&amp;gt; for short):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo LANG/summit/messages/kdefoo/*fooapp*.po&lt;br /&gt;
!    LANG/summit-ascript/messages/kdefoo/fooapp.po  (144)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdefoo/libfooapp.po  (25)&lt;br /&gt;
===! Translated: 169&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit/messages/kdefoo/libfooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/fooapp.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdefoo/libfooapp.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1267069.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will add ascription records into ascription catalogs corresponding to summit catalogs to be committed, and commit them all. Like &amp;lt;tt&amp;gt;svn commit&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;poascribe mo&amp;lt;/tt&amp;gt; can take any number of file or directory paths, and can be issued from any working directory (it will always find ascription catalogs). If default commit message has not been set in the ascription configuration, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will ask for it; or it can be given in command line through &amp;lt;tt&amp;gt;-m&amp;lt;/tt&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
=== Translators Without Commit Access ===&lt;br /&gt;
&lt;br /&gt;
With the ascription system in place, every regular team member should have commit access. But, there may be some period of time before new translators are given accounts, revision control may be too technical for some, and even those with the account may not be able to commit temporarily for some reason.&lt;br /&gt;
&lt;br /&gt;
These translators may send in their work by email, to ''any'' team member with commit access (not necessarily the coordinator or a reviewer); this team member can commit received files without any review, as review can be conducted at any later time. If Bob sends some files to Alice, she can commit them immediately by stating Bob's user name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo -u bob ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, the translator who sent in the files has to be defined in the ascription configuration. There are no hidden costs or security issues to this (as opposed to opening a VCS account), so every new translator should be defined there before any work of that person is committed.&lt;br /&gt;
&lt;br /&gt;
== Daily Use for Reviewers ==&lt;br /&gt;
&lt;br /&gt;
The ascription system opens up all sorts of possibilities for concrete review patterns. Reviewers should keep in mind that for each message the full modification and review history is available, so that the team can think about how to make good use of it. Therefore, what follows are some examples to illustrate the review facilities that &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; provides.&lt;br /&gt;
&lt;br /&gt;
=== Basic Reviewing ===&lt;br /&gt;
&lt;br /&gt;
At the very basic level (which is the only level in classical review by stages), messages can be classified into simply unreviewed and reviewed, without further qualifiers. Alice now wants to review all unreviewed messages in a group of PO files, say &amp;lt;tt&amp;gt;kdetoys&amp;lt;/tt&amp;gt; module. She issues (&amp;lt;tt&amp;gt;di&amp;lt;/tt&amp;gt; is short for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ poascribe di LANG/summit/messages/kdetoys/&lt;br /&gt;
!    LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Diffed for review: 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unreviewed messages have now been marked and diffed, inside the listed PO files. What is this about &amp;quot;diffing&amp;quot;? If the files had already been reviewed before, some of the messages modified since then (those marked for review) may have changed very little (e.g. a few words in a paragraph-length message, or even just punctuation). Therefore, for each message marked for review, Alice also wants to see the diff since last review to current version. Here are two messages in typical review states added by &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: charlie:m&lt;br /&gt;
#: gui/mainwindow.cc:372&lt;br /&gt;
#, ediff&lt;br /&gt;
msgid &amp;quot;GAME OVER. {-You won-}{+Tie+}!&amp;quot;&lt;br /&gt;
msgstr &amp;quot;KRAJ IGRE. {-Pobeda-}{+Nerešeno+}!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#. +&amp;gt; trunk stable&lt;br /&gt;
#. ascto: bob:m charlie:m&lt;br /&gt;
#: game-state.cpp:117&lt;br /&gt;
#, ediff-total&lt;br /&gt;
msgid &amp;quot;Click the pause button again to resume the game.&amp;quot;&lt;br /&gt;
msgstr &amp;quot;Кликните поново на дугме паузе за наставак игре.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and the first one in Kate:&lt;br /&gt;
&lt;br /&gt;
[[Image:Kate_poascribe_diff_01.png|center|Message diffed for review by poascribe in Kate.]]&lt;br /&gt;
&lt;br /&gt;
In the first message, the first to note is the &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment. This comment succinctly lists who did what with the message since the last review; here &amp;lt;tt&amp;gt;charlie:m&amp;lt;/tt&amp;gt; means that Charlie is the one who modified it. Then, there is the &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; flag, which alice can use it to jump through messages marked for review. Finally, the original and translation have been diffed; here they show that, since the last review, the message was fuzzied by changing &amp;quot;You won&amp;quot; to &amp;quot;Tie&amp;quot;, and what Charlie did in translation to unfuzzy it. Even on a message as short as this, the diff tells something useful to Alice: the phrase &amp;quot;Game over&amp;quot; likely has a formulaic translation, and the fact that it is not part of the diff means that the earlier reviewer had made sure it is consistent, so Alice does not have to check that.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#. ascto:&amp;lt;/tt&amp;gt; comment of the second message reveals that both Charlie and Bob had been translating it. &amp;lt;tt&amp;gt;ediff-total&amp;lt;/tt&amp;gt; flag instead of plain &amp;lt;tt&amp;gt;ediff&amp;lt;/tt&amp;gt; means that this message had no review at all up to now, so there are no embedded diffs in text fields.&lt;br /&gt;
&lt;br /&gt;
Alice can now go through marked files and messages, review translations, and possibly make modifications. When making changes in a message with embedded diffs, she can freely edit text outside of difference segments and within &amp;lt;tt&amp;gt;{+...+}&amp;lt;/tt&amp;gt; segments (as these are the ones which belong to current version of the text). While reviewing, Alice does ''not'' remove any of the added message elements while reviewing (save for an occasional difference segment, when translation should be modified), as these elements are needed for later. If a message is particularly hard and Alice wants to defer its review for later, she can add the &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt; (or &amp;lt;tt&amp;gt;urev&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; for short) flag to it.&lt;br /&gt;
&lt;br /&gt;
Once the review is complete, Alice commits the reviewed files in &amp;lt;tt&amp;gt;reviewed&amp;lt;/tt&amp;gt; mode (short &amp;lt;tt&amp;gt;re&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re LANG/summit/messages/kdetoys/{bovo,kdiamond,palapeli}.po&lt;br /&gt;
!    LANG/summit/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Cleared reviews: 21&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/palapeli.po (3)&lt;br /&gt;
===! Translated: 3&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/bovo.po  (2)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/kdiamond.po  (7)&lt;br /&gt;
!    LANG/summit-ascript/messages/kdegames/palapeli.po  (12)&lt;br /&gt;
===! Reviewed: 21&lt;br /&gt;
Sending      LANG/summit/messages/kdegames/palapeli.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/bovo.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/kdiamond.po&lt;br /&gt;
Sending      LANG/summit-ascript/messages/kdegames/palapeli.po&lt;br /&gt;
Transmitting file data ....&lt;br /&gt;
Committed revision 1284220.&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three things have happened here. First, all review states (flags, embedded diffs, etc.) have been removed, restoring the PO file to normal. Then, any modifications that Alice have made during review are ascribed to her (here 3 out of 21 messages). Finally, all marked messages are ascribed as reviewed by Alice (any with &amp;lt;tt&amp;gt;unreviewed&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;urev&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;nrev&amp;lt;/tt&amp;gt; flags would have been omitted here). When committing, the only summit catalog that got committed is the one with modifications made during review, and all the ascription catalogs were committed because of the reviews recorded in them.&lt;br /&gt;
&lt;br /&gt;
When many files with few changes in each are to be reviewed, it becomes burdensome to manually open each and every diffed for review, and then to make sure that all are committed with &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt;. To make this easier, &amp;lt;tt&amp;gt;-w torevivew.out&amp;lt;/tt&amp;gt; option can be added to &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt;, which requests that paths of all diffed PO files are written into &amp;lt;tt&amp;gt;torevivew.out&amp;lt;/tt&amp;gt; file. This file can then be used to batch open POs for review in the editor, as well as fed back on &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;-f torevivew.out&amp;lt;/tt&amp;gt;. There is also the &amp;lt;tt&amp;gt;-o&amp;lt;/tt&amp;gt; option which causes &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; to directly open PO files in a PO editor, though this is currently applicable only to Lokalize. Putting it together, to efficiently review a whole bunch of small changes throughout many files, Alice can:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di PATHS... -w toreview.out -o lokalize&lt;br /&gt;
$ # ...only marked messages opened in Lokalize, review them...&lt;br /&gt;
$ poascribe re -f toreview.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selecting Messages for Review ===&lt;br /&gt;
&lt;br /&gt;
Invocations of &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; without any options, as in the previous section, were actually equivalent to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option &amp;lt;tt&amp;gt;-s&amp;lt;/tt&amp;gt; is issuing the message ''selector''. &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is the default selector for &amp;lt;tt&amp;gt;diff&amp;lt;/tt&amp;gt; mode, and stands for MODified-After-Review: it selects the earliest historical modification of the message after the last (or no) review of that message, if there is any such. By selecting a historical modification of the message, the diff from it to current version can be computed and embedded into the PO file, as in previous examples.&lt;br /&gt;
&lt;br /&gt;
There are various specialized selectors, and fall into two groups: ''shallow selectors'' and ''history selectors''. Shallow selectors look only into the current version of the message, and cannot select historical versions, which means that they cannot provide embedded diffs. History selectors (&amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; is of this type) can select messages from history and provide diffs. Several selectors can be issued on the command line, and the message is selected only if all selectors select it. Shallow selectors are then normally used as a pre-filter for history selectors. For example, to select messages modified after last reviewed, but only those found in stable branch, &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; selectors are chained:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s branch:stable -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is important that the history selector is given last, because the last selector determines which historical message is selected. If the ordering had been reversed here, same messages would get selected, but they would not have embedded diffs, because &amp;lt;tt&amp;gt;branch&amp;lt;/tt&amp;gt; is a shallow selector.&lt;br /&gt;
&lt;br /&gt;
Selectors can take parameters themselves, like &amp;lt;tt&amp;gt;branch:stable&amp;lt;/tt&amp;gt; in the previous example. Parameters are separated from the selector name by any non-alphanumeric character; this is colon by convention, but if a parameter contains a colon, something like slash, tilde, etc. can be used. Number of parameters can be variable, and &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; in particular can take from none to three. If Alice wants to review only those messages modified ''by Charlie'' since last review, she states this by first argument to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:charlie PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Alice does not give too much credit to other reviewers, she can request selection of messages modified after last review ''by her'' with second parameter to &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar::alice PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the first parameter (&amp;quot;modified by...&amp;quot;), which is not needed, must be explicitly skipped, before going to the second parameter (&amp;quot;reviewed by...&amp;quot;). The third optional parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; will be mentioned in the next section.&lt;br /&gt;
&lt;br /&gt;
When a selector parameter is a user name, normally it can also be a comma-separated list of user names (&amp;lt;tt&amp;gt;modar:bob,charlie&amp;lt;/tt&amp;gt;) or prefixed with tilde to negate, i.e. select all other users (&amp;lt;tt&amp;gt;modar:~alice&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Any selector can be negated by prepending &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; to its name. For example, the history selector &amp;lt;tt&amp;gt;modafter:DATE&amp;lt;/tt&amp;gt; selects first modification after the given date; to select messages modified after last review, but only if modified during June 2010:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modafter:2010-06 -s nmodafter:2010-07 -s modar PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Negating a history selector produces a shallow selector: while &amp;lt;tt&amp;gt;modafter&amp;lt;/tt&amp;gt; is history selector, &amp;lt;tt&amp;gt;nmodafter&amp;lt;/tt&amp;gt; is shallow. But the order of the two in the previous command line is not important, as the last selector is the usual &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selectors can be issued in other modes too. If the PO file is big and Alice has reviewed messages up to and including entry 246 when she has to pause until another day, she can commit reviews only up to this entry by issuing the &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; selector:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re -s espan::246 PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the first parameter to &amp;lt;tt&amp;gt;espan&amp;lt;/tt&amp;gt; is the first entry number, given if messages are not to be selected from the first). There is also the counterpart &amp;lt;tt&amp;gt;lspan&amp;lt;/tt&amp;gt; selector, which works with referent line numbers (those of &amp;lt;tt&amp;gt;msgid&amp;lt;/tt&amp;gt; keywords) instead of entry numbers.&lt;br /&gt;
&lt;br /&gt;
=== Fine-Grained Reviews ===&lt;br /&gt;
&lt;br /&gt;
In the introduction, several distinct types of what can go wrong in translation were described. Not all reviewers may be able to check translation against all those problems. Here is a typical scenario of this kind:&lt;br /&gt;
&lt;br /&gt;
Alice is very computer-savvy and knows the translation project inside and out, which means that she can review well for context, terminology, and technical style. But, her language style leaves something to be desired, which shows through longer sentences and passages. Dan, on the other hand, is a very literary person, but not that much into the technical aspects. Dan's style reviews would thus be a perfect complement to Alice's general reviews.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; can support this scenario in the following way. A ''review type'' tag for language style is defined in the ascription configuration, using the &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[global]&lt;br /&gt;
...&lt;br /&gt;
review-tags = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The value to &amp;lt;tt&amp;gt;review-tags&amp;lt;/tt&amp;gt; is a space-separated list of identifiers, when more than one special review type is needed.) With this addition to configuration, Alice can continue to review as she did before, without any changes to her workflow.&lt;br /&gt;
&lt;br /&gt;
Dan selects messages for review quite similarly to Alice, with the exception of giving the &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; tag as ''third'' parameter of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe di -s modar:::lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When committing reviews, Dan must also state this tag, in order to ascribe reviews as of language style type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe re -t lstyle PATHS...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If Dan is always going to review the language style, in order not to have to issue the selector and tag in the command line all the time, he can make them default per mode in &amp;lt;tt&amp;gt;~/.pologyrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[poascribe]&lt;br /&gt;
user = dan&lt;br /&gt;
selector/diff = modar:::lstyle&lt;br /&gt;
tag/reviewed = lstyle&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this Dan can use plain &amp;lt;tt&amp;gt;poascribe di&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;poascribe re&amp;lt;/tt&amp;gt;, just like Alice does.&lt;br /&gt;
&lt;br /&gt;
The important point of review tags is that they make reviews by types independent. For example, Dan may come around to review the language style of the given message after several modifications and general reviews have been ascribed to it -- &amp;lt;tt&amp;gt;modar:::lstyle&amp;lt;/tt&amp;gt; will simply ignore all reviews except for &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews. This is going to be reflected in the &amp;lt;tt&amp;gt;ascto:&amp;lt;/tt&amp;gt; comment to marked messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: charlie:m alice:r bob:m&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here Alice has made one review between Charlie's and Bob's modifications, and that review, being general instead of &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt;, did not cause &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt; to stop at it. After Dan reviews this message for language style, Alice runs selection for review and gets this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code po&amp;gt;&lt;br /&gt;
#...&lt;br /&gt;
#. ascto: bob:m dan:r(lstyle)&lt;br /&gt;
#...&lt;br /&gt;
msgid &amp;quot;...&amp;quot;&lt;br /&gt;
msgstr &amp;quot;...&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, since &amp;lt;tt&amp;gt;lstyle&amp;lt;/tt&amp;gt; reviews do not mix with general reviews, Dan's review did not hide Bob's modification that Alice did not check so far.&lt;br /&gt;
&lt;br /&gt;
(General review too has a tag assigned, the empty string, in case the reviewer needs to explicitly issue it in some context.)&lt;br /&gt;
&lt;br /&gt;
== Daily Use for The Coordinator ==&lt;br /&gt;
&lt;br /&gt;
After setting up the ascription system, the team coordinator should have to do very little to maintain it.&lt;br /&gt;
&lt;br /&gt;
=== Ascribing Merges ===&lt;br /&gt;
&lt;br /&gt;
Modifications made to summit catalogs by merging with templates must also be ascribed. This ascription is made in the name of the reserved &amp;lt;tt&amp;gt;fuzzy&amp;lt;/tt&amp;gt; user, which exists by default and is not defined in &amp;lt;tt&amp;gt;ascription-config&amp;lt;/tt&amp;gt;. Therefore, after merging the summit (&amp;lt;tt&amp;gt;posummit ... merge ...&amp;lt;/tt&amp;gt;) the coordinator substitutes the VCS command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ svn commit LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; command in &amp;lt;tt&amp;gt;modified&amp;lt;/tt&amp;gt; mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ poascribe mo -u fuzzy LANG/summit/messages/ -m &amp;quot;Merged summit.&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;tt&amp;gt;-C&amp;lt;/tt&amp;gt; option is not issued, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; will automatically commit all modified summit and ascription catalogs when done.&lt;br /&gt;
&lt;br /&gt;
=== Shuffling Ascription Catalogs  ===&lt;br /&gt;
&lt;br /&gt;
Sometimes summit catalogs are shuffled in the repository: moved to another module, renamed, one catalog split into two, two catalogs merged into one. Such shuffling should be exactly mirrored in the ascription tree, and this too is done on the repository side, at the same time. This relies on the ascription root being set exactly to &amp;lt;tt&amp;gt;../summit-ascript&amp;lt;/tt&amp;gt; in the ascription configuration. So the team coordinator has nothing special to do here.&lt;br /&gt;
&lt;br /&gt;
If instead in the central KDE repository the translation team is working in an external repository, by consequence the ascription system must be set up in that repository. But so long as &amp;lt;tt&amp;gt;process_orphans.sh&amp;lt;/tt&amp;gt; script from &amp;lt;tt&amp;gt;trunk/l10n-support/scripts/&amp;lt;/tt&amp;gt; is used to shuffle catalogs in the external repository as well, the ascription catalogs will be properly handled.&lt;br /&gt;
&lt;br /&gt;
== Filtering for Release ==&lt;br /&gt;
&lt;br /&gt;
The last component of the ascription system is how to prevent insufficiently reviewed messages from leaking into a release. In context of Pology and summit workflow, &amp;lt;tt&amp;gt;poascribe&amp;lt;/tt&amp;gt; itself is used directly to this end. Instead, in the summit configuration (as opposed to ascription configuration), the team coordinator defines filters which pass messages by applying selectors.&lt;br /&gt;
&lt;br /&gt;
Each top level PO tree has its own summit configuration file, named &amp;lt;tt&amp;gt;MSGTREE.extras.summit&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    LANG/&lt;br /&gt;
        summit/&lt;br /&gt;
            messages/&lt;br /&gt;
            messages.extras.summit&lt;br /&gt;
            docmessages/&lt;br /&gt;
            docmessages.extras.summit&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the simple case of all reviews being general reviews, the filter is added to summit configuration like this (anywhere within &amp;lt;tt&amp;gt;*.extras.summit&amp;lt;/tt&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the filter is named &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;, and is defined as application of &amp;lt;tt&amp;gt;nmodar&amp;lt;/tt&amp;gt; selector, the negation of &amp;lt;tt&amp;gt;modar&amp;lt;/tt&amp;gt;. This simply means: pass all messages ''not'' modified after the last review.&lt;br /&gt;
&lt;br /&gt;
When the team coordinator scatters to branches (executes &amp;lt;tt&amp;gt;posummit scatter&amp;lt;/tt&amp;gt;), messages from summit POs which do not pass this filter will not be sent to branch POs. The count of stopped messages by branch PO will be reported in the output as scattering proceeds.&lt;br /&gt;
&lt;br /&gt;
Why did we have to name the filter &amp;lt;tt&amp;gt;regular&amp;lt;/tt&amp;gt;? (Those knowing some Python will also notice that it is defined as a list element.) Because it is possible to define more than one filter, and select which one is used on each scattering. For example, the coordinator may wish that, when the release is near and time is short to review everything, messages from a few experienced translators can be passed into release without review. If those translators are Alice and Bob, an &amp;quot;emergency&amp;quot; filter can be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, &amp;lt;tt&amp;gt;posummit&amp;lt;/tt&amp;gt; uses the first filter in the list. When the coordinator needs to do emergency scattering, he requests the emergency filter by the &amp;lt;tt&amp;gt;-a&amp;lt;/tt&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
$ cd $KDEREPO/trunk/l10n-support&lt;br /&gt;
$ posummit scripts/messages.summit LANG scatter -a emergency&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What if several selectors are needed to pass the message? For example, the language style review (the earlier example with Alice and Dan) too may be requested for regular scattering, but omitted from emergency scattering. The filter setup for this scenario looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code python&amp;gt;&lt;br /&gt;
S.ascription_filters = [&lt;br /&gt;
    (&amp;quot;regular&amp;quot;, [&amp;quot;nmodar&amp;quot;, &amp;quot;nmodar:::lstyle&amp;quot;]),&lt;br /&gt;
    (&amp;quot;emergency&amp;quot;, [&amp;quot;nmodar:~alice,bob&amp;quot;]),&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The regular filter now reads: pass the message if it has not been modified after the last (general) review ''and'' has not been modified after the last style review.&lt;br /&gt;
&lt;br /&gt;
Simple combination of predefined selectors by AND-conditions may not be sufficient for more involved scenarios. When this is the case, the coordinator may write (or ask someone to write) a custom selector in Python, and plug it in as the second element in the filter tuple (instead of the list of predefined selectors).&lt;br /&gt;
&lt;br /&gt;
=== Writing a Selector Function ===&lt;br /&gt;
&lt;br /&gt;
((To be written.))&lt;/div&gt;</summary>
		<author><name>Ilic</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Localization/Workflows/PO_Ascription</id>
		<title>Localization/Workflows/PO Ascription</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Localization/Workflows/PO_Ascription"/>
				<updated>2010-01-13T14:28:34Z</updated>
		
		<summary type="html">&lt;p&gt;Ilic: -E option changed to -O.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:I18n/Language Navigation Bar|Localization/Workflows/PO_Summit}}&lt;br /&gt;
&lt;br /&gt;
{{LocalizationBrowser|&lt;br /&gt;
section=[[Localization#Workflows|Workflows]]|&lt;br /&gt;
name=Reviewing by Ascriptions|&lt;br /&gt;
prereqs=[[Localization/Workflows/PO_Summit|Translating in Summit]]|&lt;br /&gt;
related=[[Localization/Tools/Pology|Pology]], [[Localization/Workflows/Coordinator|Language Coordinator]]|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Why Review Translations? ==&lt;br /&gt;
&lt;br /&gt;
Especially to new translators, it may not be obvious to which extent the translation needs to be reviewed. If the translator has exercised due diligence, how &amp;quot;wrong&amp;quot; can the translation be? Even if the translator has good command of the source language (English in context of this article), the answer is &amp;quot;very wrong&amp;quot;, when all aspects are considered. Here are some of them.&lt;br /&gt;
&lt;br /&gt;
With comparatively simple grammar of English, the meaning of a short English sentence -- as typically encountered in application user interfaces -- is very dependent on the surrounding context. This context may not be obvious when the translator is going through isolated messages in the translation file, so he may commit the worst of errors from the user's viewpoint, the senseless translation. An experienced reviewer will have developed sense for troublesome contexts, and will have several means to decisively determine the context (including, for example, running the development version of the application).&lt;br /&gt;
&lt;br /&gt;
Even if the context is correctly established, the translator may use &amp;quot;wrong&amp;quot; terminology, which is the next worse thing for the user. A term used in translation does not need to be wrong by itself, in fact it may be exactly the correct term -- in another translation project. The reviewer will have more experience with terminology of the present project, and be able to bring the translation in line with it.&lt;br /&gt;
&lt;br /&gt;
Style in the technical sense is a consistent choice between several perfectly valid constructs in target language when applied to text in the given technical context. For example, how to translate menu titles and items, button labels, or tooltips. The choices may include noun or verb forms, particular grammar categories, tone of address, and so on. There may be a style guide to the project which details such choices, and the reviewer will know it well.&lt;br /&gt;
&lt;br /&gt;
Style in the linguistic sense is especially applicable to longer texts, such as tooltips in user interfaces, and passages in documentation. A typical error of a new translator is to closely adhere to English style and grammar. This may produce translation which is semantically and grammatically valid in the target language, but very out of style -- the &amp;quot;translationese&amp;quot;. Reviewer is there to naturalize such passages.&lt;br /&gt;
&lt;br /&gt;
Finally, the reviewer may be an experienced translator, but that does not mean that his own translations need no review. Immersion into the source language, distraction, fatigue, will lead the reviewer into any of the above errors in translation, only with less frequency. So reviewers should also review one anothers' translations.&lt;br /&gt;
&lt;br /&gt;
== Classical Reviewing by Stages ==&lt;br /&gt;
&lt;br /&gt;
Classical review workflow by stages seems simple enough. Translator translates a PO file (or updates existing translation), and declares it ready to review. A reviewer reviews it, and declares it ready to &amp;quot;commit&amp;quot;. Committing here should be understood generally, as inclusion into the pool from which translations are periodically shipped to end users. A committer finally commits the file. The process is iterative: the reviewer may return the file to the translator, and translator later again declare it as ready for review. There may be several stages of review (such as ''proof-reading''