【问题标题】:Searching for value but replacing sibling with xslt搜索值但用 xslt 替换兄弟
【发布时间】:2017-04-10 18:41:07
【问题描述】:

我有一个 XLIFF 文件,用于将 iPhone 应用程序翻译成另一种语言。

它是这样的:

<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   version="1.2"
   xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
 <file original="kWallet/Base.lproj/BonusProgram.storyboard"
         source-language="de"
         datatype="plaintext"
         target-language="en">
      <header>
         <tool tool-id="com.apple.dt.xcode"
               tool-name="Xcode"
               tool-version="8.2.1"
               build-num="8C1002"/>
      </header>
      <body>
         <trans-unit id="VNf-SH-yf4.normalTitle">
            <source>Nicht mehr teilnehmen</source>
            <target>Nicht mehr teilnehmen</target>
            <note>Class = "UIButton"; normalTitle = "Nicht mehr teilnehmen"; ObjectID = "VNf-SH-yf4";</note>
         </trans-unit>
         <trans-unit id="bks-T0-HXe.normalTitle">
            <source>Teilnehmen</source>
            <target>Teilnehmen</target>
            <note>Class = "UIButton"; normalTitle = "Teilnehmen"; ObjectID = "bks-T0-HXe";</note>
         </trans-unit>
         <trans-unit id="inq-dy-gMC.title">
            <source>Bonus</source>
            <target>Bonus</target>
            <note>Class = "UITabBarItem"; title = "Bonus"; ObjectID = "inq-dy-gMC";</note>
         </trans-unit>
         <trans-unit id="mub-0G-Dk1.title">
            <source>Bonus Program</source>
            <target>Bonus Program</target>
            <note>Class = "UINavigationItem"; title = "Bonus Program"; ObjectID = "mub-0G-Dk1";</note>
         </trans-unit>
         <trans-unit id="rAv-9a-ssv.title">
            <source>Bonus</source>
            <target>Bonus</target>
            <note>Class = "UINavigationItem"; title = "Bonus"; ObjectID = "rAv-9a-ssv";</note>
         </trans-unit>
      </body>
  </file>
</xliff>

现在我需要做以下事情:

我已经将翻译保存在以下格式的文本文件中: "source" = "target",例如"Im App Store anzeigen" = "Show in App Store"

/* Show in App Store Text */
"Im App Store anzeigen" = "Show in App Store";

所以我要创建一个脚本,它读取我的文本文件并在每一行之后调用 xslt 转换,将 2 个值传递给它。

现在我需要了解如何使用 xslt 解决转换问题。基本上它需要搜索&lt;source&gt; == "Nicht mehr teilnehmen",然后用我要传递给xslt转换器的第二个值替换它的&lt;target&gt;兄弟(在本例中为"Stop participating"

我认为这应该很容易,但不幸的是,我没有足够的 xslt 经验来自己解决这个问题。感谢您的帮助。

【问题讨论】:

  • 出现各种问题。每个源语言字符串是唯一的吗?或者,相同的源语言字符串是否可以在多个不同的地方多次出现,甚至可能使用不同的目标语言字符串?另外,文本文件中的字符串是否可以包含引号,如果可以,是否进行了转义?
  • 另外,我很好奇您的工作流程。 XLIFF 是本地化数据的行业标准文件格式,如今大多数 CAT 工具都支持 XLIFF 进行直接处理。您的工作流程是什么,例如,您的 XLIFF 的源文本同时包含 &lt;source&gt;&lt;target&gt;,而您的实际本地化数据则以某种单独的文本格式存储?
  • 每个源语言字符串可以出现多次,也需要多次替换。确实会出现引号,都像这样转义\"string\"
  • @EiríkrÚtlendi 问题是,在 XLIFF 之前,Xcode 只使用普通的属性文件(例如 en.strings)。我们在这些文件中已经有了这些英文翻译,但是当 xcode 生成新的 XLIFF 文件时,它不会处理那些 .strings 文件中已经存在的翻译。因此,在最好的情况下,我只需将所有翻译从 .strings 移动到 .xliff 一次
  • 源-目标字符串是否都是一对一匹配的?或者一个源字符串可以等同于多个不同的目标字符串?

标签: xml xslt search replace


【解决方案1】:

如果您能够使用 XSLT 2.0 或更高版本,则以下方法将起作用。这里的三个不同特性在 XSLT 1.0 中不存在。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"

    exclude-result-prefixes="xs"
    version="2.0"

    xpath-default-namespace="urn:oasis:names:tc:xliff:document:1.2">
    <!-- Note the `xpath-default-namespace` line here: this is only allowed in XSLT 2.0 and newer.
        The input XLIFF file itself specifies this URI as the unprefixed namespace for the whole file.
        If we don't specify this as the XPath default namespace, we have to specify element names
        in ugly workaround syntax, such as `*[local-name() = 'xliff']`. -->

    <!-- Parameter for feeding in the path to your translated-pairs text file. -->
    <xsl:param name="transfile-path" select="'DEFAULTPATH'"/>
    <!-- Sample path format: 'file:///C:/Users/[USERNAME]/AppData/Local/Temp/transdata.txt' -->

    <!-- Variable containing whole content of your translated-pairs text file. Replace the file path as appropriate.
        The `unparsed-text` XPath function is required to load plain text (as opposed to parsable XML).
        This function is only available in XSLT 2.0 or newer. -->
    <xsl:variable name="transfile" select="unparsed-text($transfile-path)"/>

    <!-- Newline: this might need adjusting, depending on the newline format in your text file. -->
    <xsl:variable name="newline" select="'&#xD;&#xA;'"/>

    <xsl:template match="/xliff|file|body|trans-unit">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="header|source|note">
        <xsl:copy-of select="."/>
    </xsl:template>

    <xsl:template match="target">
        <xsl:copy>
            <!-- This variable tokenizes the $transfile content by newline,
                then grabs the first line where the source matches the current <target> element text
                (wrapped with double-quotes, just in case),
                then chops off the source portion and stores just the target portion, but with the last " on the end.
                The `tokenize` XPath function requires XSLT 2.0 or newer. -->
            <xsl:variable name="target-string" select="substring-after(tokenize($transfile, $newline)
                [contains(., concat('&quot;', current(), '&quot;'))][1], '&quot; = &quot;')"/>

            <!-- Output the target string, minus that last "  -->
            <xsl:value-of select="substring($target-string, 1, string-length($target-string) - 1)"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

使用包含您指定格式的翻译对的简单文本文件,以上内容对我有用。我试图包含信息丰富的 cmets 来了解代码的作用。

警告

这假设您的数据是完全一对一的。所以"Fussbodenschleifmaschinenverleih" 可能会在您的翻译对文本文件中出现十四次,但它总是 并且only 被翻译为相同的目标字符串。 :)

旁注

如果您或您的团队可以访问CAT tool,许多此类工具包括"alignment" feature 或配套应用程序,它可以获取您所描述的双语数据,并生成翻译记忆库。根据您的设置,这可能会更容易进行。

更新

根据 gasparuff 的 cmets,以下是您从 &lt;source&gt; 元素而不是直接从 &lt;target&gt; 元素中查找源文本的方法。这涉及对先前代码的单一更改:

        <xsl:variable name="target-string" select="substring-after(tokenize($transfile, $newline)
            [contains(., concat('&quot;', current()/../source, '&quot;'))][1], '&quot; = &quot;')"/>
        <!-- The previous version had `current()`, as in, the content of the current
            context element, which is here the <target> element.  I changed that above to
            `current()/../source` to instead get the text from the sibling <source>
            element.  .. here evaluates to the parent of the current <target>, and then
            we look for the <source> child of that parent.  This is often safer than 
            using preceding-sibling::source, or following-sibling::source, since we
            often cannot say 100% that the element we're looking for is *before* the
            current context element, or *after* it. -->

【讨论】:

  • 感谢您的宝贵意见,但不幸的是,我得到的只是一个空结果:-(。.strings 文件中的翻译都以分号结尾(抱歉,忘了提及),所以我用这个替换了换行变量:` `。另外,我不知道我是否正确调用了 xslt。我正在使用 Oxygen立即使用 XML 编辑器。
  • 好的,现在可以了。但我发现它在&lt;target&gt; 标签中搜索键。这暂时有效,但您是否有一个解决方案,脚本在 &lt;source&gt; 标记中查找内容,然后用新字符串替换 &lt;target&gt; 标记?
  • @gasparuff,您的示例输入 XML 在 &lt;source&gt;&lt;target&gt; 元素中都有源文本。如果您的示例输入 XML 是您工作数据的准确表示,我们永远不需要查看 &lt;source&gt; 元素的内容,因为源文本已经在输入 &lt;target&gt; 元素中。我们只需要将&lt;target&gt; 中的源文本替换为文本文件中的目标文本。如果您的示例输入 XML 具有误导性,那就是另一个问题了。 :)
  • 你是对的,你的答案是正确的:-)。虽然我没有考虑过字符串文件中的一个翻译被更改并且 xliff 文件需要更新的情况。这实际上不应该发生,但我仍然很想知道如何完成这样的事情,也许将来有一天我会需要它:D
猜你喜欢
  • 1970-01-01
  • 2013-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-13
  • 1970-01-01
相关资源
最近更新 更多