.mo文件 读取类MOFile

本文介绍了一个用于解析MO文件的Java类。MO文件是一种用于软件国际化和本地化的文件格式,该类能够读取并解析MO文件中的字符串及其翻译,还包括文件格式版本、项目ID等元数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.time.DateUtils;

public class MOFile {

	/**
	 * string encoding
	 */
	private static final String UTF_8 = "UTF-8";

	/**
	 * The file format revision of this MO file.
	 */
	public int fileFormatRevision;

	/**
	 * The dictionary of the string and translated strings in this MO file.
	 * 
	 * <p>
	 * The original strings are the keys ; the translated strings are the
	 * values.
	 * </p>
	 */
	public Map<String, String> strings;

	/**
	 * The number of translations in this MO file.
	 */
	public int numStrings;

	/**
	 * The project id and version in which this MO file is used.
	 */
	public String projectIdVersion;

	/**
	 * Where to report bugs of msgid strings
	 */
	public String reportMsgidBugsTo;

	/**
	 * The creation date of the PO template file that was used to create this MO
	 * file.
	 */
	public Date potCreationDate;

	/**
	 * The creation date of the PO file that was used to create this MO file.
	 */
	public Date poRevisionDate;

	/**
	 * The last translator who has worked on the translations of this MO file.
	 */
	public String lastTranslator;

	/**
	 * The language team behind the translations of this MO file.
	 */
	public String languageTeam;

	/**
	 * The mime version of this MO file, such as <code>1.0</code>
	 */
	public String mimeVersion;

	/**
	 * The content type of this MO file, such as
	 * <code>text/plain; charset=UTF-8</code>
	 */
	public String contentType;
	
	/**
	 * Constructor.
	 */
	public MOFile() {}

	/**
	 * The content mime type of this MO file, such as <code>text/plain</code>.
	 */
	public String contentMimeType() {
		return contentType.substring(0, contentType.indexOf(";"));
	}

	/**
	 * The charset of the content of this MO file, such as <code>UTF-8</code>.
	 */
	public String contentCharset() {
		return contentType.substring(contentType.indexOf("=") + 1);
	}

	/**
	 * Value is usually <code>8bit</code>.
	 */
	public String contentTransferEncoding;

	/**
	 * The raw plural forms as specified in the MO file, such as
	 * <code>nplurals=2; plural=n>1</code>.
	 */
	public String pluralForms;

	/**
	 * The plural expression used in the MO file, to determine if a string is a
	 * plural form. The expression is usually <code>n>1</code>.
	 */
	public int plural() {
		return Integer.valueOf(pluralForms.substring(pluralForms.lastIndexOf(">") + 1, pluralForms.lastIndexOf(";")));
	}

	/**
	 * The locale of this catalog.
	 */
	public String locale;

	/**
	 * The plural value used in the MO file, to determine if a string is a
	 * plural form. The value is usually <code>2</code>.
	 */
	public int nPlural() {
		return Integer.valueOf(pluralForms.substring(pluralForms.indexOf("=") + 1, pluralForms.indexOf(";")));
	}

	/**
	 * Parses the bytes representing a MO file.
	 * 
	 * @param bytes
	 *            The bytes of the MO file
	 * @return A MOFile instance containing the informations of the original .mo
	 *         file.
	 * @throws Exception
	 * 
	 * @throws GettextError
	 *             if the bytes does not represent a valid MO file.
	 * @throws TypeError
	 *             if the specified ByteArray is null.
	 * 
	 */
	public static MOFile parseMOBytes(ByteBuffer bytes) throws Exception {
		if (bytes == null) throw new IllegalArgumentException("The <bytes> parameter must not be null");

		int originalPosition = bytes.position();
		ByteOrder originalEndian = bytes.order();
		int magicNumber = bytes.getInt();
		if (magicNumber == 0xde120495) bytes.order(ByteOrder.LITTLE_ENDIAN);
		else if (magicNumber == 0x950412de) bytes.order(ByteOrder.BIG_ENDIAN);
		else throw new RuntimeException("The magic number is invalid.");

		int fileFormatRevision = bytes.getInt();
		if (fileFormatRevision > 0) throw new RuntimeException("Unknown or unsupported MO file format revision.");

		int n = bytes.getInt();
		if (n <= 0) throw new RuntimeException("The MO file has no translations.");

		int o = bytes.getInt();
		int t = bytes.getInt();
		
		// skip 8 bytes
		bytes.getInt();
		bytes.getInt();

		// Loop through string and translations location informations
		// and retrieve string and translations infos
		int LOOP_INCREMENT = 8;// 4+4
		int NUM_LOOPS = n;// (n-1+1)
		Map<String, String> dictionary = new HashMap<String, String>();
		int i = -1;
		int bytesIndent;
		int strlen;
		int stroffset;
		int trStrlen;
		int trStroffset;

		while (++i < NUM_LOOPS) {
			bytesIndent = i * LOOP_INCREMENT;
			bytes.position(o + bytesIndent);
			strlen = bytes.getInt();
			stroffset = bytes.getInt();
			bytes.position(t + bytesIndent);
			trStrlen = bytes.getInt();
			trStroffset = bytes.getInt();

			// get string
			bytes.position(stroffset);
			byte[] dst = new byte[strlen];
			bytes.get(dst);
			String str = new String(dst, UTF_8);
			bytes.position(trStroffset);
			dst = new byte[trStrlen];
			bytes.get(dst);
			String trStr = new String(dst, UTF_8);
			dictionary.put(str, trStr);
		}

		// The informations are assumed to be
		// in the first string to be translated.
		// The original string is empty
		// We should be careful to check the evolution of it.
		bytes.position(t);
		int infolen = bytes.getInt();
		int infooffset = bytes.getInt();

		bytes.position(infooffset);
		byte[] dst = new byte[infolen];
		bytes.get(dst);
		String infos = new String(dst, UTF_8);
		String[] elements = infos.split("\n");

		// Create and fill the MOFile instance
		MOFile mo = new MOFile();
		mo.fileFormatRevision = fileFormatRevision;
		mo.strings = dictionary;
		mo.numStrings = n;
		mo.projectIdVersion = elements[0].substring(elements[0].indexOf(":") + 2);
		mo.reportMsgidBugsTo = elements[1].substring(elements[1].indexOf(":") + 2);

		try {
			// YYYY-MM-DD HH::MM(+|-HHMM)
			String rawPotCreationDate = elements[2].substring(elements[2].indexOf(":") + 2);
			mo.potCreationDate = DateUtils.parseDate(rawPotCreationDate, new String[] { "yyyy-MM-dd HH:ssZ" });
			String rawPoRevisionDate = elements[3].substring(elements[3].indexOf(":") + 2);
			mo.poRevisionDate = DateUtils.parseDate(rawPoRevisionDate, new String[] { "yyyy-MM-dd HH:ssZ" });
		} catch(Exception e) {
			
		}

		mo.lastTranslator = elements[4].substring(elements[4].indexOf(":") + 2);
		mo.languageTeam = elements[5].substring(elements[5].indexOf(":") + 2);
		mo.mimeVersion = elements[6].substring(elements[6].indexOf(":") + 2);
		mo.contentType = elements[7].substring(elements[7].indexOf(":") + 2);
		mo.contentTransferEncoding = elements[8].substring(elements[8].indexOf(":") + 2);
		mo.pluralForms = elements[9].substring(elements[9].indexOf(":") + 2);

		// Put the byte array in its original state.
		bytes.position(originalPosition);
		bytes.order(originalEndian);
		return mo;
	}

	public static void main(String[] args) throws Exception {
		File file = new File("E:\\data_i18n_v3.mo");
		byte[] bytes = FileUtils.readFileToByteArray(file);
		ByteBuffer buff = ByteBuffer.wrap(bytes);
		MOFile mo = parseMOBytes(buff);
		System.out.println(mo.projectIdVersion);
		System.out.println(mo.numStrings);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值