【问题标题】:'Un'-externalize strings from Eclipse or Intellij'Un'-从 Eclipse 或 Intellij 外部化字符串
【发布时间】:2011-01-22 07:06:23
【问题描述】:

我在属性文件中有一堆字符串,我想“取消外部化”,即内联到我的代码中。

我看到 Eclipse 和 Intellij 都非常支持从代码中“外部化”字符串,但是它们中的任何一个都支持将字符串从属性文件内联回代码中吗?

例如,如果我有类似的代码 -

My.java

System.out.println(myResourceBundle.getString("key"));

我的.properties

key=a whole bunch of text

我希望将我的 java 代码替换为 -

My.java

System.out.println("a whole bunch of text");

【问题讨论】:

  • 你能解释一下,它应该有什么好处?根据您的评论,您可能想要速度,但与字符串输出相比,地图查找时间是否可以忽略不计?

标签: java internationalization externalizing


【解决方案1】:

我编写了一个简单的 java 程序,您可以使用它来执行此操作。

Dexternalize.java

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;


public class Deexternalize {

    public static final Logger logger = Logger.getLogger(Deexternalize.class.toString());

    public static void main(String[] args) throws IOException {
        if(args.length != 2) {
            System.out.println("Deexternalize props_file java_file_to_create");
            return;
        }

        Properties defaultProps = new Properties();
        FileInputStream in = new FileInputStream(args[0]);
        defaultProps.load(in);
        in.close();

        File javaFile = new File(args[1]);

        List<String> data = process(defaultProps,javaFile);

        buildFile(javaFile,data);

    }

    public static List<String> process(Properties propsFile, File javaFile) {
        List<String> data = new ArrayList<String>();
        Set<Entry<Object,Object>> setOfProps = propsFile.entrySet();
        int indexOf = javaFile.getName().indexOf(".");
        String javaClassName = javaFile.getName().substring(0,indexOf);

        data.add("public class " + javaClassName + " {\n");
        StringBuilder sb = null;

        // for some reason it's adding them in reverse order so putting htem on a stack
        Stack<String> aStack = new Stack<String>();

        for(Entry<Object,Object> anEntry : setOfProps) {
            sb = new StringBuilder("\tpublic static final String ");
            sb.append(anEntry.getKey().toString());
            sb.append(" = \"");
            sb.append(anEntry.getValue().toString());
            sb.append("\";\n");
            aStack.push(sb.toString());
        }

        while(!aStack.empty()) {
            data.add(aStack.pop());
        }

        if(sb != null) {
            data.add("}");
        }

        return data;
    }

    public static final void buildFile(File fileToBuild, List<String> lines) {
        BufferedWriter theWriter = null;

        try {
            // Check to make sure if the file exists already.
            if(!fileToBuild.exists()) {
                fileToBuild.createNewFile();
            }

            theWriter = new BufferedWriter(new FileWriter(fileToBuild));

            // Write the lines to the file.
            for(String theLine : lines) {
                // DO NOT ADD windows carriage return.
                if(theLine.endsWith("\r\n")){
                    theWriter.write(theLine.substring(0, theLine.length()-2));
                    theWriter.write("\n");
                } else if(theLine.endsWith("\n")) {
                    // This case is UNIX format already since we checked for
                    // the carriage return already.
                    theWriter.write(theLine);
                } else {
                    theWriter.write(theLine);
                    theWriter.write("\n");
                }
            }

        } catch(IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        } finally {
            try {
                theWriter.close();
            } catch(IOException ex) {
                logger.log(Level.SEVERE, null, ex);
            }
        }
    }
}

基本上,您需要做的就是使用属性文件的位置和要创建的包含属性的 java 文件的名称来调用这个 java 程序。

例如这个属性文件:

test.properties

TEST_1=test test test
TEST_2=test 2456
TEST_3=123456

会变成:

java_test.java

public class java_test {
    public static final String TEST_1 = "test test test";
    public static final String TEST_2 = "test 2456";
    public static final String TEST_3 = "123456";
}

希望这是你需要的!

编辑:

我明白你现在的要求了。如果你撒点正则表达式魔法,你可以使用我的代码做你想做的事。假设您有上面的 java_test 文件。将内联属性复制到要替换 myResourceBundle 代码的文件中。

例如,

TestFile.java

public class TestFile {

    public static final String TEST_1 = "test test test";
    public static final String TEST_2 = "test 2456";
    public static final String TEST_3 = "123456";

    public static void regexTest() {

        System.out.println(myResourceBundle.getString("TEST_1"));
        System.out.println(myResourceBundle.getString("TEST_1"));
        System.out.println(myResourceBundle.getString("TEST_3"));

    }
}

好的,现在如果您使用 Eclipse(任何现代 IDE 都应该能够做到这一点),请转到编辑菜单 -> 查找/替换。在窗口中,您应该看到一个“正则表达式”复选框,选中它。现在在 Find 文本区域输入以下文本:

myResourceBundle\.getString\(\"(.+)\"\)

还有后面的参考

\1

进入替换。

现在点击“全部替换”,瞧!代码应该已根据您的需要进行内联。

现在 TestFile.java 将变为:

TestFile.java

public class TestFile {

    public static final String TEST_1 = "test test test";
    public static final String TEST_2 = "test 2456";
    public static final String TEST_3 = "123456";

    public static void regexTest() {

        System.out.println(TEST_1);
        System.out.println(TEST_1);
        System.out.println(TEST_3);

    }
}

【讨论】:

  • 这应该是您在 StackOverflow 的一个良好开端 :)。
  • 谢谢!这可以扩展到检测值是 int 还是 double 等,但我觉得 String 是最常用的属性,而且我只有大约半小时的无聊时间来修复。 :)
  • 根本看不出这有什么帮助。您的代码将属性文件转换为 java 文件。那不是我需要的。我有一个 java 代码,其中包含对需要内联的属性文件中键的字符串引用。这根本不能解决这个问题。
  • pdeva,这段代码回答了你的问题,“我在一个属性文件中有一堆字符串,我想'un-externalize',即内联到我的代码中”。您需要更具体地提出问题。
  • 你不明白内联是什么意思。我没有要求 java 代码转换器的属性文件。
【解决方案2】:

您可以使用 Eclipse“Externalize Strings”小部件。它也可以用于非外部化。选择所需的字符串并按“内部化”按钮。如果字符串之前被外部化,它将被放回并从 messages.properties 文件中删除。

【讨论】:

  • 虽然有些麻烦,但这绝对是最好的答案。
【解决方案3】:

如果您可以解释您需要如何执行此操作,那么您可能会得到正确的答案。

对您的问题的简短回答是否定的,尤其是在 Intellij 中(我对 eclipse 知之甚少)。当然,稍长但仍然不是很有用的答案是编写一个插件。 (这将获取一个属性文件列表并读取映射中的键和值,然后用 Map 中的值(对于键)执行正则表达式替换 ResourceBundle.getValue("Key")。我将编写这个插件我自己,如果你能说服我,像你这样有这个要求的人更多。)

更详细的答案是这样的。

1_ 首先,我将所有执行属性文件读取的代码重构为单个类(或称为 PropertyFileReader 的模块)。

2_ 我将创建一个属性文件阅读器模块,它遍历属性文件中的所有键,然后将这些信息存储在映射中。

4_ 我可以使用填充的值创建静态地图对象,也可以从中创建一个常量类。然后我将替换属性文件阅读器模块中的逻辑,使用地图或静态类上的get而不是属性文件读取。

5_ 一旦我确定应用程序运行正常。(通过检查我的所有单元测试是否通过),我将删除我的属性文件。

注意:如果您使用的是 spring,那么有一种简单的方法可以从属性文件列表中拆分出所有属性键值对。如果您使用弹簧,请告诉我。

【讨论】:

  • 在您描述的情况下,字符串仍将位于每次都必须查找的地图中。我正在寻找一个完整的内联,它只是将字符串放在代码中。
  • 写自己的插件怎么样。你是什么操作系统。你看的是批量查找和替换。打印出地图的内容,并使用一些文件工具批量查找和替换。
【解决方案4】:

我会推荐其他方法:将外部化字符串拆分为可本地化和不可本地化的属性文件。将一些字符串移动到另一个文件可能比将其移回源代码更容易(顺便说一句,这会损害可维护性)。

当然,您可以编写简单的(在某种程度上)Perl(或其他)脚本,它将搜索对资源包的调用并在此位置引入常量... 换句话说,我没听说过去外化机制,你需要自己动手(或者自己写一些自动化脚本)。

【讨论】:

    【解决方案5】:

    来自@potong sed 's|^\([^=]*\)=\(.*\)|s@Messages.getString("\1")@"\2"@g|;s/\\/\\\\/g' messages.properties | sed -i -f - *.java 的一个很棒的 oneliner 在你的 src 目录中运行它,看看它的魔力。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-23
      • 2010-12-23
      • 2014-05-01
      • 1970-01-01
      • 2011-05-26
      • 1970-01-01
      相关资源
      最近更新 更多