OSDN Git Service

#30840 不要になっていたTemplate:Documentation絡みの処理も除去,
[wptscs/wpts.git] / Wptscs / Logics / MediaWikiTranslator.cs
index 8f91a34..9e79e8f 100644 (file)
@@ -3,7 +3,7 @@
 //      Wikipedia用の翻訳支援処理実装クラスソース</summary>
 //
 // <copyright file="MediaWikiTranslator.cs" company="honeplusのメモ帳">
-//      Copyright (C) 2012 Honeplus. All rights reserved.</copyright>
+//      Copyright (C) 2013 Honeplus. All rights reserved.</copyright>
 // <author>
 //      Honeplus</author>
 // ================================================================================================
@@ -134,23 +134,23 @@ namespace Honememo.Wptscs.Logics
 
             // 対象記事に言語間リンクが存在する場合、処理を継続するか確認
             // ※ 言語間リンク取得中は、処理状態を解析中に変更
-            MediaWikiLink interlanguage;
+            string interlanguage;
             using (var sm = this.StatusManager.Switch(Resources.StatusParsing))
             {
                 interlanguage = article.GetInterlanguage(this.To.Language.Code);
             }
 
-            if (interlanguage != null)
+            if (!string.IsNullOrEmpty(interlanguage))
             {
                 // 確認処理の最中は処理時間をカウントしない(ダイアログ等を想定するため)
                 this.Stopwatch.Stop();
-                if (this.IsContinueAtInterwikiExisted != null && !this.IsContinueAtInterwikiExisted(interlanguage.Title))
+                if (this.IsContinueAtInterwikiExisted != null && !this.IsContinueAtInterwikiExisted(interlanguage))
                 {
                     throw new ApplicationException("user canceled");
                 }
 
                 this.Stopwatch.Start();
-                this.Logger.AddResponse(Resources.LogMessageTargetArticleHadInterWiki, interlanguage.Title);
+                this.Logger.AddResponse(Resources.LogMessageTargetArticleHadInterWiki, interlanguage);
             }
 
             // 冒頭部を作成
@@ -221,7 +221,7 @@ namespace Honememo.Wptscs.Logics
         /// <returns>冒頭部のテキスト。</returns>
         protected virtual string CreateOpening(string title)
         {
-            string langPart = String.Empty;
+            string langPart = string.Empty;
             IElement langLink = this.GetLanguageLink();
             if (langLink != null)
             {
@@ -229,7 +229,7 @@ namespace Honememo.Wptscs.Logics
             }
 
             string langBody = this.To.FormatLang(this.From.Language.Code, title);
-            if (String.IsNullOrEmpty(langBody))
+            if (string.IsNullOrEmpty(langBody))
             {
                 langBody = title;
             }
@@ -250,12 +250,12 @@ namespace Honememo.Wptscs.Logics
             MediaWikiLink link = new MediaWikiLink();
             link.Title = page.Title;
             link.Interwiki = this.From.Language.Code;
-            return "\n\n" + link.ToString() + "\n" + String.Format(
+            return "\n\n" + link.ToString() + "\n" + string.Format(
                 Resources.ArticleFooter,
                 FormUtils.ApplicationName(),
                 this.From.Language.Code,
                 page.Title,
-                page.Timestamp.HasValue ? page.Timestamp.Value.ToString("U") : String.Empty) + "\n";
+                page.Timestamp.HasValue ? page.Timestamp.Value.ToString("U") : string.Empty) + "\n";
         }
 
         #endregion
@@ -329,7 +329,7 @@ namespace Honememo.Wptscs.Logics
                     if (parent.Title.StartsWith(title))
                     {
                         // サブページ(親)の場合、変換してもしょうがないのでセクションだけチェックして終了
-                        if (!String.IsNullOrEmpty(link.Section))
+                        if (!string.IsNullOrEmpty(link.Section))
                         {
                             link.Section = this.ReplaceLinkSection(link.Section);
                             link.ParsedString = null;
@@ -340,7 +340,7 @@ namespace Honememo.Wptscs.Logics
 
                     link.Title = title;
                 }
-                else if (!String.IsNullOrEmpty(link.Interwiki))
+                else if (!string.IsNullOrEmpty(link.Interwiki))
                 {
                     // 言語間リンク・姉妹プロジェクトへのリンクの場合、変換対象外とする
                     // ただし、先頭が : でない、翻訳先言語への言語間リンクだけは削除
@@ -364,10 +364,10 @@ namespace Honememo.Wptscs.Logics
                 {
                     // 記事自体が存在しない(赤リンク)場合、リンクはそのまま
                 }
-                else if (interWiki == String.Empty)
+                else if (interWiki == string.Empty)
                 {
                     // 言語間リンクが存在しない場合、可能なら{{仮リンク}}に置き換え
-                    if (!String.IsNullOrEmpty(this.To.LinkInterwikiFormat))
+                    if (!string.IsNullOrEmpty(this.To.LinkInterwikiFormat))
                     {
                         return this.ReplaceLinkLinkInterwiki(link);
                     }
@@ -399,7 +399,7 @@ namespace Honememo.Wptscs.Logics
             }
 
             // セクション部分([[#関連項目]]とか)を変換
-            if (!String.IsNullOrEmpty(link.Section))
+            if (!string.IsNullOrEmpty(link.Section))
             {
                 link.Section = this.ReplaceLinkSection(link.Section);
             }
@@ -432,7 +432,7 @@ namespace Honememo.Wptscs.Logics
                 // 記事自体が存在しない(赤リンク)場合、リンクはそのまま
                 return template;
             }
-            else if (interWiki == String.Empty)
+            else if (interWiki == string.Empty)
             {
                 // 言語間リンクが存在しない場合、[[:en:Template:xxx]]みたいな普通のリンクに置換
                 // おまけで、元のテンプレートの状態をコメントでつける
@@ -505,12 +505,15 @@ namespace Honememo.Wptscs.Logics
         protected virtual IElement ReplaceVariable(MediaWikiVariable variable, MediaWikiPage parent)
         {
             // 変数、これ自体は処理しないが、再帰的に探索
-            string old = variable.Value.ToString();
-            variable.Value = this.ReplaceElement(variable.Value, parent);
-            if (variable.Value.ToString() != old)
+            if (variable.Value != null)
             {
-                // 内部要素が変化した(置き換えが行われた)場合、変換前のテキストを破棄
-                variable.ParsedString = null;
+                string old = variable.Value.ToString();
+                variable.Value = this.ReplaceElement(variable.Value, parent);
+                if (variable.Value.ToString() != old)
+                {
+                    // 内部要素が変化した(置き換えが行われた)場合、変換前のテキストを破棄
+                    variable.ParsedString = null;
+                }
             }
 
             return variable;
@@ -613,13 +616,13 @@ namespace Honememo.Wptscs.Logics
                 if (this.ItemTable.TryGetValue(decodedTitle, out item))
                 {
                     // 存在する場合はその値を使用
-                    if (!String.IsNullOrWhiteSpace(item.Alias))
+                    if (!string.IsNullOrWhiteSpace(item.Alias))
                     {
                         // リダイレクトがあれば、そのメッセージも表示
                         this.Logger.AddAlias(new MediaWikiLink(item.Alias));
                     }
 
-                    if (!String.IsNullOrEmpty(item.Word))
+                    if (!string.IsNullOrEmpty(item.Word))
                     {
                         this.Logger.AddDestination(new MediaWikiLink(item.Word), true);
                         return item.Word;
@@ -627,7 +630,7 @@ namespace Honememo.Wptscs.Logics
                     else
                     {
                         this.Logger.AddDestination(new TextElement(Resources.LogMessageInterWikiNotFound), true);
-                        return String.Empty;
+                        return string.Empty;
                     }
                 }
 
@@ -657,31 +660,32 @@ namespace Honememo.Wptscs.Logics
             // 記事名から記事を探索
             item = new TranslationDictionary.Item { Timestamp = DateTime.UtcNow };
             MediaWikiPage page = this.GetDestinationPage(title);
-            if (page != null && page.IsRedirect())
-            {
-                // リダイレクトの場合、リダイレクトである旨出力し、その先の記事を取得
-                this.Logger.AddAlias(new MediaWikiLink(page.Redirect.Title));
-                item.Alias = page.Redirect.Title;
-                page = this.GetDestinationPage(page.Redirect.Title);
-            }
-
             if (page == null)
             {
                 // ページ自体が存在しない場合はnull
                 return null;
             }
 
+            if (page.IsRedirect())
+            {
+                // リダイレクトの場合、リダイレクトである旨出力
+                this.Logger.AddAlias(new MediaWikiLink(page.Title));
+                item.Alias = page.Title;
+            }
+
             // 記事があればその言語間リンクを取得
-            MediaWikiLink interlanguage = page.GetInterlanguage(this.To.Language.Code);
-            if (interlanguage != null)
+            string interlanguage = page.GetInterlanguage(this.To.Language.Code);
+            if (!string.IsNullOrEmpty(interlanguage))
             {
-                item.Word = interlanguage.Title;
-                this.Logger.AddDestination(interlanguage);
+                item.Word = interlanguage;
+                MediaWikiLink link = new MediaWikiLink(interlanguage);
+                link.Interwiki = this.To.Language.Code;
+                this.Logger.AddDestination(link);
             }
             else
             {
                 // 見つからない場合は空
-                item.Word = String.Empty;
+                item.Word = string.Empty;
                 this.Logger.AddDestination(new TextElement(Resources.LogMessageInterWikiNotFound));
             }
 
@@ -723,8 +727,8 @@ namespace Honememo.Wptscs.Logics
             // 言語コード等も特に無く、かつセクションが指定されている場合
             // (記事名もセクションも指定されていない・・・というケースもありえるが、
             //   その場合他に指定できるものも思いつかないので通す)
-            return String.IsNullOrEmpty(link.Title)
-                || (link.Title == parent && String.IsNullOrEmpty(link.Interwiki) && !String.IsNullOrEmpty(link.Section));
+            return string.IsNullOrEmpty(link.Title)
+                || (link.Title == parent && string.IsNullOrEmpty(link.Interwiki) && !string.IsNullOrEmpty(link.Section));
         }
 
         /// <summary>
@@ -770,7 +774,7 @@ namespace Honememo.Wptscs.Logics
                 // 記事自体が存在しない(赤リンク)場合、リンクはそのまま
                 return link;
             }
-            else if (interWiki == String.Empty)
+            else if (interWiki == string.Empty)
             {
                 // 言語間リンクが存在しない場合、コメントで元の文字列を保存した後
                 // [[:en:xxx]]みたいな形式に置換。また | 以降は削除する
@@ -842,7 +846,7 @@ namespace Honememo.Wptscs.Logics
             // ※ 渡されたlinkをそのまま使わないのは、余計なゴミが含まれる可能性があるため
             MediaWikiLink title = new MediaWikiLink { Title = link.Title, Section = link.Section };
             string langTitle = title.GetLinkString();
-            if (!String.IsNullOrEmpty(title.Section))
+            if (!string.IsNullOrEmpty(title.Section))
             {
                 // 変換先言語版のセクションは、セクションの変換を通したものにする
                 title.Section = this.ReplaceLinkSection(title.Section);
@@ -955,38 +959,64 @@ namespace Honememo.Wptscs.Logics
         {
             // 指定された記事をWikipediaから取得、リダイレクトの場合その先まで探索
             // ※ この処理ではキャッシュは使用しない。
-            // ※ 万が一相互にリダイレクトしていると無限ループとなるが、特に判定はしない。
-            //    ユーザーが画面上から止めることを期待。
             this.Logger.AddMessage(Resources.LogMessageGetTargetArticle, this.From.Location, title);
             MediaWikiPage page;
-            for (string s = title; this.TryGetPage(s, out page); s = page.Redirect.Title)
+            if (!this.TryGetPage(title, out page))
             {
-                if (page == null)
-                {
-                    // 記事が存在しない場合、メッセージを出力して終了
-                    this.Logger.AddResponse(Resources.LogMessageTargetArticleNotFound);
-                    break;
-                }
-
-                // 取得した記事のURIを以後のアクセスで用いるRefererとして登録
-                this.From.WebProxy.Referer = page.Uri.AbsoluteUri;
-                this.To.WebProxy.Referer = page.Uri.AbsoluteUri;
-
-                if (!page.IsRedirect())
-                {
-                    // リダイレクト以外ならこれで終了
-                    break;
-                }
+                // 取得失敗時はそのまま終了
+                return null;
+            }
+            else if (page == null)
+            {
+                // 記事が存在しない場合、メッセージを出力して終了
+                this.Logger.AddResponse(Resources.LogMessageTargetArticleNotFound);
+                return null;
+            }
 
-                // リダイレクトであれば、さらにその先の記事を取得
+            if (page.IsRedirect())
+            {
+                // リダイレクトであれば、その旨メッセージを表示
                 this.Logger.AddResponse(Resources.LogMessageRedirect
-                    + " " + new MediaWikiLink(page.Redirect.Title).ToString());
+                    + " " + new MediaWikiLink(page.Title).ToString());
+            }
+
+            // ページ本文にアクセスして遅延読み込みを実行させる
+            if (!this.TryLoadPage(page))
+            {
+                // 読み込み失敗時はそのまま終了
+                return null;
             }
 
+            // 取得した記事のURIを以後のアクセスで用いるRefererとして登録
+            this.From.WebProxy.Referer = page.Uri.AbsoluteUri;
+            this.To.WebProxy.Referer = page.Uri.AbsoluteUri;
+
             return page;
         }
 
         /// <summary>
+        /// 翻訳支援対象のページの本文・タイムスタンプを読み込み。
+        /// </summary>
+        /// <param name="page">翻訳支援対象のページ。</param>
+        /// <returns>読み込み成功の場合<c>true</c>、失敗した(通信エラーなど)の場合<c>false</c>。</returns>
+        private bool TryLoadPage(MediaWikiPage page)
+        {
+            // ページ本文にアクセスして遅延読み込みを実行させる
+            try
+            {
+                string dummy = page.Text;
+            }
+            catch (Exception e)
+            {
+                // その他例外の場合、エラー情報を出力
+                this.Logger.AddError(e);
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
         /// 指定した言語での言語名称を [[言語名称|略称]]の内部リンクで取得。
         /// </summary>
         /// <returns>
@@ -1004,7 +1034,7 @@ namespace Honememo.Wptscs.Logics
 
             // 略称を取得
             IElement shortName = null;
-            if (!String.IsNullOrEmpty(name.ShortName))
+            if (!string.IsNullOrEmpty(name.ShortName))
             {
                 shortName = new TextElement(name.ShortName);
             }
@@ -1042,7 +1072,7 @@ namespace Honememo.Wptscs.Logics
         {
             // 確認ダイアログを表示
             if (MessageBox.Show(
-                        String.Format(Resources.QuestionMessageArticleExisted, interwiki),
+                        string.Format(Resources.QuestionMessageArticleExisted, interwiki),
                         Resources.QuestionTitle,
                         MessageBoxButtons.YesNo,
                         MessageBoxIcon.Question)