5

编辑:我完全重写了这个问题,因为我的前两个版本似乎不够清楚。感谢您迄今为止的建议。

我想国际化教程项目的源代码(请注意,不是运行时应用程序)。这是一个示例(在 Java 中):

/** A comment */
public String doSomething() {
  System.out.println("Something was done successfully");
}

用英语,然后让法语版本类似于:

/** Un commentaire */
public String faitQuelqueChose() {
  System.out.println("Quelque chose a été fait avec succès.");
}

等等。然后在某处有一个属性文件之类的东西来使用常用工具编辑这些翻译,例如:

com.foo.class.comment1=A comment
com.foo.class.method1=doSomething
com.foo.class.string1=Something was done successfully

对于其他语言:

com.foo.class.comment1=Un commentaire
com.foo.class.method1=faitQuelqueChose
com.foo.class.string1=Quelque chose a été fait avec succès.

我试图找到最简单、最有效和不引人注目的方法,用最少的人工繁重的工作(除了明显地翻译实际文本)来做到这一点。最好在 Eclipse 下工作。例如,原始代码将用英语编写,然后外部化(到属性,最好保持原始源不变),翻译(人工)然后重新生成(作为单独的源文件/项目)。

我发现的一些小径(除了 AlexS 建议的):

我只是很惊讶没有一个工具可以做到这一点。

4

6 回答 6

2

我会使用唯一的字符串作为方法名(或任何你想被本地化版本替换的东西。

public String m37hod_1() {
  System.out.println(m355a6e_1);
}

然后我会为每种语言定义一个属性文件,如下所示:

m37hod_1=doSomething
m355a6e_1="Something was done successfully"

然后我会编写一个小程序来解析源文件并替换字符串。所以一切都在日食之外。

或者我也会使用 ant 任务Replace和 propertyfiles,而不是独立的翻译程序。像这样的东西:

<replace 
    file="${src}/*.*"
    value="defaultvalue"
    propertyFile="${language}.properties">
  <replacefilter 
    token="m37hod_1" 
    property="m37hod_1"/>
  <replacefilter 
    token="m355a6e_1" 
    property="m355a6e_1"/>
</replace>

使用其中一种方法,您无需在教程中解释任何有关本地化的内容(除非您愿意),但可以专注于您的真正主题。

于 2012-06-19T15:28:27.327 回答
2

你想要的是一个庞大的代码更改引擎。

ANTLR 不会成功;AST 是必要的,但还不够。请参阅我关于解析后的生活的文章。如果 Eclipse 包对名称和类型解析提供一些支持,Eclipse 的“AST”可能会更好;否则你将永远无法弄清楚如何替换每个“doSomething”(可能是重载的或本地的),除非你愿意全部替换它们(你可能不能这样做,因为有些符号是指 Java库元素)。

我们的DMS 软件再造工具包可用于完成您的任务。DMS 可以将 Java 解析为 AST(包括注释捕获),以任意方式遍历 AST,分析/更改 AST,并将修改后的 AST 导出为有效源代码(包括注释)。

基本上,您想枚举所有注释、字符串和标识符声明,将它们导出到外部“数据库”以映射(手动?通过谷歌翻译?)到等价物。在每种情况下,您不仅要注意感兴趣的项目,还要注意其精确位置(源文件、行、甚至列),因为在原始文本中拼写相同的项目在修改后的文本中可能需要不同的拼写。

如果你有 AST,那么枚举字符串非常容易;只需爬取树并查找包含字符串文字的树节点。(ANTLR 和 Eclipse 也确实可以做到这一点)。

如果您拥有的解析器捕获了评论,那么评论的枚举也很简单。DMS 可以。我不太确定是 ANTLR 的 Java 语法还是 Eclipse AST 引擎;我怀疑他们都有能力。

声明(类、方法、字段、局部变量)的枚举相对简单;有更多的情况需要担心(例如,匿名类包含对基类的扩展)。您可以编写一个过程来遍历 AST 并匹配树结构,但这是 DMS 开始发挥作用的地方:您可以编写看起来像您想要匹配的源代码的表面语法模式。例如:

   pattern local_for_loop_index(i: IDENTIFIER, t: type, e: expression, e2: expression, e3:expression): for_loop_header
         = "for (\t \i = \e,\e2,\e3)"

将匹配本地 for 循环变量的声明,并返回 IDENTIFIER、类型和各种表达式的子树;您只想捕获标识符(及其位置,可以通过从 DMS 在每个树节点上标记的源位置信息中获取 if 轻松完成)。您可能需要 10-20 个这样的模式来涵盖所有不同类型标识符的情况。

捕获步骤完成,需要将所有捕获的实体翻译成您的目标语言。我把它留给你;剩下的就是把翻译后的实体放回去。

关键是精确的源位置。行号在实践中不够好;您可能在同一行中有多个翻译的实体,在最坏的情况下,一些具有不同的范围(例如嵌套 for 循环)。注释、字符串和声明的替换过程很简单;重新扫描树中与任何已识别位置匹配的节点,并用其翻译替换在那里找到的实体。(您可以使用 DMS 和 ANTLR 执行此操作。我认为 Eclipse ADT 需要您生成“补丁”,但我想这会起作用。)。

有趣的部分在于替换标识符uses。为此,您需要知道两件事:

  • 对于标识符的任何使用,声明的用途是什么;如果您知道这一点,则可以将其替换为声明的新名称;DMS 提供完整的名称和类型解析以及使用列表,使这变得非常简单,并且
  • 重命名的标识符是否在与原始标识符不同的范围内相互影响?一般来说,这更难做到。但是,对于 Java 语言,我们有一个“阴影”检查,因此您至少可以在重命名后确定您有问题。(甚至还有一个重命名程序可以用来解决这种阴影冲突

修补树后,您只需使用 DMS 的内置漂亮打印机将修补的树重写为源文件。我认为 Eclipse AST 可以写出它的树和补丁。我不确定 ANTLR 是否提供了从 AST 重新生成源代码的任何工具,尽管有人可能已经为 Java 语法编写了一个工具。由于所有挑剔的细节,这比听起来更难做到。YMMV。

鉴于您的目标,我有点惊讶您不希望包含“class foo { ... }”的源文件“foo.java”重命名为.java。这不仅需要将转换后的树写入翻译后的文件名(非常容易),甚至可能需要重建目录树(DMS 也提供了用于进行目录构建和文件复制的工具)。

如果您想为多种语言执行此操作,则需要为每种语言运行一次该过程。如果您只想为字符串执行此操作(经典的国际化案例),您可以通过调用具有唯一资源 ID 的资源访问来替换每个字符串(需要更改,并非所有字符串都需要更改);运行时表将保存各种字符串。

于 2012-06-25T11:03:06.393 回答
1

一种方法是用一种语言完成代码,然后翻译成其他语言。

您可以使用 Eclipse 来帮助您。

  1. 将完成的代码复制到特定语言的项目中。
  2. 然后:
    • 标识符:在大纲视图(窗口>显示视图>大纲)中,选择每个项目并重构>重命名(Alt+Shift+R)。这负责重命名标识符,无论它在哪里使用。
    • 评论:使用搜索>文件查找“/*”或“//”的所有实例。单击每个并修改。
    • 字符串
      1. 使用Source>Externalize strings 查找所有文字字符串。
      2. 搜索>“Messages.getString()”文件。
      3. 单击每个结果并进行修改。
      4. 在每个文件上,“编辑>查找/替换”,将“//\$NON-NLS-.*\$”替换为空字符串。
于 2012-06-19T19:26:48.823 回答
0

您可以使用freemarker模板(或其他模板语言,例如velocity )编写代码。

做某事.tml

/** ${lang['doSomething.comment']} */
public String ${lang['doSomething.methodName']}() {
    System.out.println("${lang['doSomething.message']}");
}

lang_en.prop

doSomething.comment=A comment
doSomething.methodName=doSomething
doSomething.message=Something was done successfully

然后在构建过程中将模板与每个语言属性文件合并(使用 Ant / Gradle / Maven 等)

于 2013-12-16T14:42:41.023 回答
0

使用 .properties 文件,例如:

Locale locale = new Locale(language, country);
ResourceBundle  captions= ResourceBundle.getBundle("Messages",locale);

这样,Java 会根据当前本地(从操作系统或 Java 区域设置获取)选择 Messages.properties 文件

该文件应该在类路径上,称为 Messages.properties(默认文件),或 Messages_de.properties 用于德语等。

完整教程请参见:http: //docs.oracle.com/javase/tutorial/i18n/intro/steps.html

就源代码而言,我强烈建议使用英语。像 getUnternehmen() 这样的方法名称对于普通开发人员来说比普通的英文名称更糟糕。如果您需要让外国开发人员熟悉您的代码,请用他们的语言编写适当的开发人员文档。

如果您想要英语和其他语言的 Javadoc,请参阅此SO 线程

于 2012-06-19T15:16:22.310 回答
0

对于打印/记录的字符串,java 拥有一些国际化功能,即 ResourceBundle。oracle网站上有一个关于这个的教程

Eclipse 也为此提供了功能(我记得是“外部化字符串”)。

对于函数名称,我不认为有任何问题,因为这将需要您维护许多版本的代码源...

问候

于 2012-06-19T15:17:47.103 回答