🛠️

英語ドキュメントに日本語翻訳を付ける

11 min read

近年増加

英語ドキュメントを 読む 読まなければいけない 機会が増えました。
いろいろなオープンソースが次から次にでてきていて、どなたかが英語のドキュメントを日本語翻訳してくれる前に「このOSS調査して」といった話しがここ数年で増えました。

Chromeの日本語翻訳

Chromeのgoogle翻訳で日本語表示はできますが、翻訳する文節の区切りが混ざっていまいち正しくないところやサンプルコードも丸ごと翻訳されてしまいます(はい、贅沢を言っています すみません)。

資料として日本語翻訳ドキュメントを作成

翻訳した内容をちゃんとドキュメント化したいと考えました。

  • 楽して日本語翻訳を付ける
  • 機械翻訳でよい
  • 元の英語はそのまま表示されていて日本語翻訳文を直後に追加したい

とこれらを考えてJavaで日本語翻訳プログラム(かなりな部分が手作業)を作成しました。
手順は以下の通りです。

  1. wgetでサイトのドキュメントを丸ごとダウンロード
wget -r -np https://sample.cooom/documentation.html

このような英語ドキュメントです。

  1. ダウンロードしたドキュメントのhtml内の英文を訳したい文節の単位で■で囲む(人力)
<a id="Overview"></a>
<h2>Overview</h2><p>Slurm can be configured to collect accounting information for every 
job and job step executed.■
■Accounting records can be written to a simple text file or a database.■
■Information is available about both currently executing jobs and 
jobs which have already terminated.■
■The <b>sacct</b> command can report resource usage for running or terminated 
jobs including individual tasks, which can be useful to detect load imbalance 
between the tasks.■
■The <b>sstat</b> command can be used to status only currently running jobs.■
■It also can give you valuable information about imbalance between tasks.■
■The <b>sreport</b> can be used to generate reports based upon all jobs 
executed in a particular time interval.■</p>
  1. プログラム1を実行して■で囲んだ英文を抽出する
    文節単位に <hr>commnet.<hr> タグに続けて抽出した英文を並べてファイルに出力します
<hr style="border:0;border-top:1px solid #FF0000;">comment.<hr style="border:0;border-top:1px solid #FF0000;">Slurm can be configured to collect accounting information for every job and job step executed.
<hr style="border:0;border-top:1px solid #FF0000;">comment.<hr style="border:0;border-top:1px solid #FF0000;">Accounting records can be written to a simple text file or a database.
<hr style="border:0;border-top:1px solid #FF0000;">comment.<hr style="border:0;border-top:1px solid #FF0000;">Information is available about both currently executing jobs and jobs which have already terminated.
<hr style="border:0;border-top:1px solid #FF0000;">comment.<hr style="border:0;border-top:1px solid #FF0000;">The sacct command can report resource usage for running or terminated jobs including individual tasks, which can be useful to detect load imbalance between the tasks.
<hr style="border:0;border-top:1px solid #FF0000;">comment.<hr style="border:0;border-top:1px solid #FF0000;">The sstat command can be used to status only currently running jobs.
<hr style="border:0;border-top:1px solid #FF0000;">comment.<hr style="border:0;border-top:1px solid #FF0000;">It also can give you valuable information about imbalance between tasks.
<hr style="border:0;border-top:1px solid #FF0000;">comment.<hr style="border:0;border-top:1px solid #FF0000;">The sreport can be used to generate reports based upon all jobs executed in a particular time interval.
  1. 英文をまとめて日本語翻訳してファイルに書き出す(機械翻訳)(人力)
コメント。
Slurmは、実行されたすべてのジョブおよびジョブステップのアカウンティング情報を収集するように構成できます。
コメント。
アカウンティングレコードは、単純なテキストファイルまたはデータベースに書き込むことができます。
コメント。
現在実行中のジョブとすでに終了しているジョブの両方に関する情報が利用可能です。
コメント。
sacctコマンドは、個々のタスクを含む実行中または終了したジョブのリソース使用量をレポートできます。これは、タスク間の負荷の不均衡を検出するのに役立ちます。
コメント。
sstatコマンドを使用して、現在実行中のジョブのみをステータス設定できます。
コメント。
また、タスク間の不均衡に関する貴重な情報を提供することもできます。
コメント。
sreportを使用して、特定の時間間隔で実行されたすべてのジョブに基づいてレポートを生成できます。
  1. プログラム2を実行して 2. のhtml と 4. の日本語翻訳したファイルをマージする
<a id="Overview"></a>
<h2>Overview</h2>

<p>Slurm can be configured to collect accounting information for every 
job and job step executed.<font size="3" color="red"><br />Slurmは、実行されたすべてのジョブおよびジョブステップのアカウンティング情報を収集するように構成できます。<br /></font>
Accounting records can be written to a simple text file or a database.<font size="3" color="red"><br />アカウンティングレコードは、単純なテキストファイルまたはデータベースに書き込むことができます。<br /></font>
Information is available about both currently executing jobs and 
jobs which have already terminated.<font size="3" color="red"><br />現在実行中のジョブとすでに終了しているジョブの両方に関する情報が利用可能です。<br /></font>
The <b>sacct</b> command can report resource usage for running or terminated 
jobs including individual tasks, which can be useful to detect load imbalance 
between the tasks.<font size="3" color="red"><br />sacctコマンドは、個々のタスクを含む実行中または終了したジョブのリソース使用量をレポートできます。これは、タスク間の負荷の不均衡を検出するのに役立ちます。<br /></font>
The <b>sstat</b> command can be used to status only currently running jobs.<font size="3" color="red"><br />sstatコマンドを使用して、現在実行中のジョブのみをステータス設定できます。<br /></font>
It also can give you valuable information about imbalance between tasks.<font size="3" color="red"><br />また、タスク間の不均衡に関する貴重な情報を提供することもできます。<br /></font>
The <b>sreport</b> can be used to generate reports based upon all jobs 
executed in a particular time interval.<font size="3" color="red"><br />sreportを使用して、特定の時間間隔で実行されたすべてのジョブに基づいてレポートを生成できます。<br /></font></p>
  1. 英文の直後に赤文字で日本語翻訳が付加できました

プログラム

Java8で作成しています。

package jp.co.dna_ltd;

import java.io.IOException;

public class EngToJpn {
	public static void main(String[] args) throws IOException {
		// プログラム1はtypeを1にして実行
		// プログラム2はtypeを2にして実行
		int type = 1;

		FileAccess fileAccess = new FileAccess();
		if(type == 1) {
			fileAccess.fileList(
					"D:\\日本語翻訳\\step1",
					"D:\\日本語翻訳\\step2");
		}else if(type == 2) {
			fileAccess.fileList2(
					"D:\\日本語翻訳\\step1",
					"D:\\日本語翻訳\\step3",
					"D:\\日本語翻訳\\step4");
		}
	}
}
package jp.co.dna_ltd;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringEscapeUtils;

@SuppressWarnings("deprecation")
public class FileAccess {

	List<File> fileList = new ArrayList<File>();

	// 再起的に指定拡張子
	public void searchFile(String targetPath) {
		File dir = new File(targetPath);
		//パス配下のディレクトリ/ファイルを配列に入れる
		File[] list = dir.listFiles();

		for (File path : list) {
			if (path.isFile()) {
				//取得したパスをバックスラッシュで分割 "\\"ではなく"\\\\"を渡す
				String[] splitedPath = path.toString().split("\\\\");
				String file = splitedPath[splitedPath.length - 1];
				if (file.toString().endsWith(".html")) {
					System.out.println(path);
					fileList.add(path);
				}
				//fileがファイル以外ならメソッドの再帰呼び出し
			} else {
				searchFile(path.toString());
			}
		}
		return;
	}

	public void fileList(String pathName, String pathOutName) throws IOException {
		// 読込基底ディレクトリ
		searchFile(pathName);
		// 全HTMLファイルをループ
		for(File file: fileList) {

			List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);

			StringBuilder sb = new StringBuilder();
			for(String line: lines) {
				// 改行を無くして全て1行にする
				sb.append(line.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", ""));
			}
			System.out.println(sb.toString());
			String allLine = sb.toString();

			// ■で分割して奇数の配列(つまり翻訳したい英文部分)を抽出する
			String[] splitLine = allLine.split("■");

			// 出力ファイルを設定
			FileSystem fs = FileSystems.getDefault();
			Path outputPath = fs.getPath(pathOutName + "\\" + file.getName());

			try (BufferedWriter bw = Files.newBufferedWriter(outputPath, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW)) {
				int cnt = 0;
				// 翻訳する際に複数行で翻訳が干渉しないように hrタグと comment. 行を挟む
				bw.write("<hr style=\"border:0;border-top:1px solid #FF0000;\">");
				bw.write("comment.");
				bw.write("<hr style=\"border:0;border-top:1px solid #FF0000;\">");
				for(String line: splitLine) {
					if((cnt % 2) == 1) {
						// ■で分割して奇数の配列(つまり翻訳したい英文部分)を抽出する
						// ■~■ 内に含まれている <>タグを削除する
						line = line.replaceAll("<(.*?)>", "");
						bw.write(line + "\n");
						bw.write("<hr style=\"border:0;border-top:1px solid #FF0000;\">");
						bw.write("comment.");
						bw.write("<hr style=\"border:0;border-top:1px solid #FF0000;\">");
					}
					cnt++;
				}
			}
		}
	}

	public void fileList2(String pathNameIn1, String pathNameIn2, String pathNameOut1) throws IOException {

		// 読込基底ディレクトリ
		searchFile(pathNameIn2);
		for(File file: fileList) {

			System.out.println(file.getName());

			List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
			for(int i = lines.size() - 1 ; i >= 0; i--) {
				if((i % 2) == 0) {
					lines.remove(i);
				}
			}
			List<String> linesRep = new ArrayList<>();
			for(int i = 0; i < lines.size(); i++) {
				if(lines.get(i).indexOf("$") >= 0) {
					System.out.println(i + " $");
				}
				if(lines.get(i).indexOf("<") >= 0) {
					System.out.println(i + " <");
				}
				if(lines.get(i).indexOf(">") >= 0) {
					System.out.println(i + " >");
				}
				String line = lines.get(i);
				line = line.replaceAll("\\$", "$");
				line = line.replaceAll("<", "<");
				line = line.replaceAll(">", ">");
				linesRep.add(line);
			}

			String htmlFileName = pathNameIn1 + "\\" + file.getName();
			File htmlFile = new File(htmlFileName);
			List<String> htmlLines = Files.readAllLines(htmlFile.toPath(), StandardCharsets.UTF_8);
			List<String> repLines = new ArrayList<>();

			int cntall = 0;
			int replace = 0;
			int cnt = 0;
			for(String line: htmlLines) {
				for(;;) {
					int findIndex = line.indexOf("■");
					if(findIndex != -1) {
						if((cnt % 2) == 0) {
							line = line.replaceFirst("■", "");
							cnt++;
						}else {
							line = line.replaceFirst("■", "<font size=\"3\" color=\"red\"><br />"+StringEscapeUtils.escapeHtml4(linesRep.get(replace))+"<br /></font>");
							cnt++;
							replace++;
						}
					}else {
						break;
					}
				}
				repLines.add(line);

				System.out.println("cntall" + cntall);
				cntall++;
			}

			for(String line: repLines) {
				System.out.println(line);
			}

			FileSystem fs = FileSystems.getDefault();
			Path outputPath = fs.getPath(pathNameOut1 + "\\" + file.getName());

			try (BufferedWriter bw = Files.newBufferedWriter(outputPath, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW)) {
				for(String line: repLines) {
					bw.write(line + "\n");
				}
			}
		}
	}
}

Discussion

ログインするとコメントできます