翻訳もれを探す

数日前から、Etoysのドイツ語の翻訳をやっているGerhard Steinerとやりとりをしています。
ご承知のように現在のEtoysの翻訳可能な文字列は3千以上あるのですが、Pootle上のEtoys翻訳プロジェクトで、ドイツ語は9割以上の語に訳語が入力されているという、脅威のがんばりかたです。

彼はこの翻訳をドイツ語コミュニティのSqueakerにレビューしてもらいたいんだけど、あまりに語の数が多いことにびびっていました。さらに OLPC Etoysでgettextに移行した後、いくつかのところで翻訳されていない箇所があり、かつそれがLanguageEditorではちゃんと訳語が入力されていることから、「一度翻訳してチェック済みなのになんでまたPootleでチェックしないといけないんだ」と問題視していました。
「GetTextに移行する際に翻訳データはPootleに移行したからLanguageEditorは無視していい」ということを一所懸命説得しました。

しかし、やりとりの中で、#translatedNoopが漏れているために翻訳漏れとなっている箇所で、昔の辞書には訳語が登録されている箇所をたくさん指摘してくれました。
そして、昔の辞書とPootleでoriginal stringを比較することができたら、チェックしないといけない作業量が見えるからがんばれるんだということを主張していました。

確かにそれはもっともだと思い、実際に試してみました。
このようなPOTへの抽出漏れをつぶすことができたら、全ての言語の翻訳の改善に貢献できます。

チェックツール

quick hackなので、きれいに書きなおせるところがたくさんありますが、恥をしのんでコードを載せます。

'From etoys3.0 of 11 February 2008 [latest update: #1914] on 14 March 2008 at 9:03:32 pm'!
Object subclass: #TranslationValidator
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Multilingual-Editor'!

!TranslationValidator methodsFor: 'as yet unclassified' stamp: 'KR 3/14/2008 20:45'!
helpStringsForPreference
	| strings |
	strings := OrderedCollection new.
	Preferences allPreferenceObjects do: [:pref |
		strings add: pref helpString
	].
	^strings.
! !

!TranslationValidator methodsFor: 'as yet unclassified' stamp: 'KR 3/14/2008 19:02'!
legacyOriginalStrings
	| strings |
	strings := Dictionary new.
	InternalTranslator cachedTranslations do: [:trans |
		trans generics keys do: [:key |
			strings at: key ifAbsentPut: key.
		]
	].
	^strings! !

!TranslationValidator methodsFor: 'as yet unclassified' stamp: 'KR 3/14/2008 19:48'!
methodsWithString: aString
	^self systemNavigation allMethodsSelect: [:method |
				method hasLiteralSuchThat: [:lit |
					(lit isString and: [lit isSymbol not]) and:
					[lit = aString]]]! !

!TranslationValidator methodsFor: 'as yet unclassified' stamp: 'KR 3/14/2008 19:37'!
missingButUsedPhrases
	| used |
	used := OrderedCollection new.
	self missingPhrases do: [:missing |
		(self methodsWithString: missing) isEmpty ifFalse: [used add: missing]
	].
	^used! !

!TranslationValidator methodsFor: 'as yet unclassified' stamp: 'KR 3/14/2008 20:47'!
missingHelpStrings
	| strings used |
	strings := Dictionary new.
	self helpStringsForPreference do: [:each |
		strings at: each put: each
	].
	used := OrderedCollection new.
	self missingPhrases do: [:missing |
		strings at: missing ifPresent: [:v|
			used add: missing
		]
	].
	^used! !

!TranslationValidator methodsFor: 'as yet unclassified' stamp: 'KR 3/14/2008 19:29'!
missingPhrases
	| oldStrings newStrings missings|
	missings := OrderedCollection new.
	oldStrings := self legacyOriginalStrings.
	newStrings := Dictionary new.
	self newOriginalStrings do: [:each | newStrings at: each put: each].
	oldStrings do: [:oldString |
		newStrings at: oldString ifAbsent: [missings add: oldString]
	].
	^missings! !

!TranslationValidator methodsFor: 'as yet unclassified' stamp: 'KR 3/14/2008 20:40'!
missingSymbols
	| symbols used |
	symbols := Dictionary new.
	Symbol allSymbols do: [:each |
		symbols at: (each asString) put: each
	].
	used := OrderedCollection new.
	self missingPhrases do: [:missing |
		symbols at: missing ifPresent: [:v|
			used add: missing
		]
	].
	^used! !

!TranslationValidator methodsFor: 'as yet unclassified' stamp: 'KR 3/14/2008 19:22'!
newOriginalStrings
	| trans domains |
	domains := Dictionary new.
	trans := GetTextExporter2 new.
	trans appendTranslations: domains.
	^(domains at: 'etoys' ) keys! !

やっていること、使い方、結果

基本的には、今のPootleに載っているPOTには抜き出されていないけど、昔の辞書には載っていた文字列で、翻訳もれの可能性があるものをリストアップしようとしています。その後は、個別に修正の必要があるかどうかを調べ、#translated/#translatedNoopを埋め込むパッチを書くことになります。
以下の実行結果は、OLPC Etoys 3.0-1914上でのものです。

(1) 昔の辞書に載っている文字列 :4418語

TranslationValidator new legacyOriginalStrings

(2) POTに抜き出されている文字列:3731語

TranslationValidator new legacyOriginalStrings

(3) 昔の辞書には載っているけど、POTには入っていない文字列: 1747語

TranslationValidator new missingPhrases

以下は、(3)の内訳です。
(3.1) ソースコード中でリテラルとして使われているもの: 545語

TranslationValidator new missingButUsedPhrases

(3.2) イメージ中のシンボルと一致する語:549語
ただし(3.1)とかぶっている語もあります。
あと、OLPC Etoysを開発する過程で、オリジナル文字列のuncamel化(たとえば evaporationRate を evaporation rateに直す)をしているので、このうちのいくらかはPOTに移行できていると思います。今日はその検証まではできていません。

TranslationValidator new missingSymbols

(3.3) プリファレンスのヘルプ文字列: 1語
Preference>>helpString をそのままバルーンヘルプとして表示している箇所があり、かつ翻訳が入力されているのですが、なんとその文字列がソースコード上どこにもリテラルとして存在しない!というのが見つかっています。Googleで検索して調べたら、アップデートストリームなどに投稿されたパッチで、DoItに直接書いてあったりするのです。(MLのアーカイブにぬけぬけと残っていました)
GetTextのテクノロジでは、翻訳文字列は本来ソースコード中のリテラルから拾うので、このような文字列はPOTに抜け落ちてしまいます。あまりにもアドホックになってしまうので現在Exporterでは対処していません。
一応、このようなもので辞書に残っているものも抜き出しておきます。

TranslationValidator new missingHelpStrings