# 标准文件格式 一个标准的 `.hytrans` 文件格式大致为以下样子 ```hytrans ## 文件头 %1.0 $ignore-first-space $lang=zh_cn |version ## 正文 hytrans.example%1 | 正文内容 hytrans.example2%3 | 另一个正文内容 hytrans.example.multiline%1 | 正文 | 可以直接换行 ``` ## 注释与空行与空字符 {#comment-and-empty} **the Hyper-Translation** 格式有着非常严格的语义要求:我们会对所有的前导空格和尾随空格严格解析——这可能会导致一些意外行为,请在使用时多加注意。 **hytrans 以 `#` 作为注释前导字符。** hytrans 只支持**单行且全行**的注释,hytrans 中的注释被定义为一行中最开始的那一个字符是空字符的行。 > *我们并没有以 `//` 作为注释前导字符的打算 —— 因为 `/` 字符将来有可能作为正文的前导字符被使用。* > > 而对于只支持单行且全行注释的解释是,*hytrans 在设计上是以每一行的前导字符来确定这一行的作用的*,这个设计可以使得解析器在格式的考虑上最小,同时也可以省去特殊情况下转义字符的麻烦。 **hytrans 的空行定义为任何以空字符起始(或没有任何字符)的行** *(尽管此处的空字符只包括 ASCII 字符表中的空格`\u0020`和制表符`\u0009`)*。所以,**任何有实际意义的行请勿使用空字符起始**,这会使得 hytrans 解析器直接丢弃掉此行。所以 hytrans 文件格式是没有缩进的——这也使得其作为翻译文件更易读且更方便控制空字符。 (所以...标准上你或许甚至可以使用一个 `tab` 或者 ` ` 来引导行以作为注释使用...) 但 hytrans 的空行(以空字符起始的行)也可能会以文件格式选项或是规范版本变更或是扩展规范而改变其*无意义*的含义。所以,考虑到兼容性,除非已经赋予了其含义,请尽量避免出现空行写法。 ```hytrans # 这是一个合法的注释 %1.0 # 这不是一个合法的注释 # 在上一行中,可能一般而言会被认为语义是:文件版本号为 [1.0],同时后面跟随了一行注释 # 但实际上,对于 hytrans 解析器来说,这一句会被解析为文件版本号为 [1.0 # 这不是一个合法的注释] ### for 语法高亮开发者 # hytrans 文件中,注释应该被看作是无意义的一行,但并不是空行 # 也就是说,看似被注释行所分割的两行,实际上应该被判断为紧邻。 # 例如以下例子,则高亮程序应该提出警告: # (关于为何要提出警告请参见 #文件头/文件版本/eg3 ) %1.0 # 无意义的一行 %hywarnings ``` 空字符(空格)也同样于空行的是,如果规范上没有声明这个空字符会被忽略,那么这个空字符就不会被忽略而会被正常录入进数据**也会影响字符串判断**,很多时候**多余的空格都会使得声明不生效** 同样要注意的是,hytrans 也不会对行尾空字符做出处理,**任何行尾空字符都会按照原样被录入** ```hytrans % 1.0 # 可能的预期:[1.0] # 实际:[ 1.0] % 1.0 % hywarnings # 可能的预期:[1.0],[hywarnings] # 实际:[ 1.0 ],[ hywarnings] # 因为 [hywarnings] 和 [ hywarnings] 并非同一个字符串(后者多了一个前导空格), # 所以这个声明并不会被认为是使用了 [hywarnings] 扩展规范! %1.0%hywarnings # 注意这个文件头声明看起来没有任何问题,但是此行的行尾实际上有两个尾随空格 # 这两个尾随空格不会在解析时被忽略,所以看起来声明了 [hywarnings] 实际上声明了 [hywarnings ] # 这同样会导致可能的声明失效 ``` **由于尾随空格通常难以被发现,在编写 hytrans 文件时应该注意检查此问题。** ## 换行符与大小写与编码 {#encoding} 对于**换行符**,hytrans 文件不对书写做特别规定(或许我们推荐使用 `LF(\n)`),——而在解析器上,解析器应该不分环境的同时支持 `LF(\n)` `CRLF(\r\n)` `CR(\r)` 三种换行符,任何一种换行符出现都将其看作是一个换行符解析~~(同时注意不要把`CRLF`解析为两个相邻换行符了)~~。 而**关于大小写**,hytrans 的所有字符都是 **`AS IS`** 解析的,这表示 hytrans 也不鼓励大小写不敏感的行为——因此, hytrans 的解析器,和标准之内的所有参数名等都是**大小写敏感**的。对于扩展规范等 hytrans 相关的字符串,标准推荐使用和 hytrans 标准相同的*小写中划线*方式,而对于数据键名,hytrans 认为这应该由程序自行发挥。 **而关于编码**问题,hytrans 目前规定在不特别声明编码的情况下,表示文件使用 `utf-8` 编码。我们也加入了一个 `$encoding` 选项用于声明文件所使用的编码(关于使用,请参见 [#文件头/文件格式附加选项](#header-extra))。 ## 文件头 {#header} hytrans 文件的最开始,可以用**一个**以 `%` 开始的行来声明文件头。 文件头包含这个文件的规范版本,扩展规范以及其版本,还可以声明文件格式选项等。 *单个文件可以声明复数次文件头,每次的声明相当于给这个文件的分页。* ### 文件版本 {#header-version} 文件头声明符号后面的一行紧随的是此 hytrans 文件的格式版本号,版本号也可以留空,一般这会表示使用最新的格式版本进行解析。 同时,版本号声明后也可以后加复数个 `%xxx` 表示同时使用了某个扩展规范。标准推荐扩展规范的名称使用 `%xxx-0.3` 的方式。 ```hytrans # 声明文件头,同时也表示使用解析器所支持的最新规范 (Not Recommend) % # 表示此文件使用 1.0 规范 (Recommend) %1.0 # 表示此文件使用 0.3.8 规范(实际上没有此版本请勿使用此版本名称),同时使用 `vscode-extra` 扩展规范的 `1.0.8` 版本(或者可以直接叫做 `vscode-extra-1.0.8` 扩展规范) %0.3.8%vscode-extra-1.0.8 # 允许同时使用多个扩展规范,也允许将标准版本号留空 %%vscode-extra-1.0.8%hywarnings-2.0 ``` ...也可以直接在版本号区域声明一个第三方规范...表示直接抛弃掉标准规范完全使用第三方规范。~~确定不用直接再造一个文件格式轮子吗,会更方便吧。~~ ```hytrans # 表示直接使用第三方规范而不使用本书籍定义的标准规范 %ultra-hytrans-1.0 ``` *注意标准并不包含任何扩展规范,扩展规范声明功能是为了提高文件在不同程序解析器,或是语法高亮中的适用性而设计的——例如,如果解析器检测到不支持的扩展规范,则可以抛出错误而不是强行解析。* hytrans 文件格式还允许在单个文件内通过声明多次文件头来达到使用多种版本/多种格式的目的(尽管这会很麻烦&.&)。 因此,**单个文件头以及版本声明以及扩展规范声明都应该在一行之内**,如果换行书写,则从新的以 `%` 开头的行会被认为是一个新的文件的开始,之前的文件头声明都会被丢弃。 ```hytrans ### 正常的文件头声明 %1.0%hywarnings # 此处的数据格式版本号为 1.0,同时包含了 hywarnings 扩展规范 %1.1 # 此处的数据格式版本号为 1.1,同时不应该包含 hywarnings 扩展规范 ### 错误的文件头声明 # 解析器会从第二个前导 % 的行开始将此行包括后面的行看作新的,基准版本为 hywarnings 的文件 # 此行之前的声明会被看作上一个文件不会影响到新的文件 # 如果你是语法高亮开发者,请为这种情况提出警告 %1.0 %hywarnings ### for 语法高亮开发者 # 考虑到一些特殊使用情况,如果两个文件头声明行中间虽然没有数据,但插入有空行 # 则可以被视为潜在的分页文件,不用提出警告 %1.0 %ultra-hytrans ``` 以 `%` 开始的文件头行并不是强制要求书写的。如果文件并未书写文件头,则解析器会以默认值来解析文件,相当于在第0行隐式声明了以下文件头: ```hytrans % ``` ### 文件格式附加选项 {#header-extra} 在文件头行的后面,可以跟随一些以 `$` 开头的行,用于表示文件格式的附加选项,可以用于让书写格式更加符合自己的书写习惯。 标准中的附加选项列表可以在 [参数选项](./header) 页面找到。与其相关的规范同样也可以在此处找到。 文件格式的附加选项必须要在一个文件的最开始,在文件头 `%` 声明之后,在任何数据之前。 如果你的文件并未声明文件头,也可以直接在最开始写上 `$` 引导行以声明附加选项——这是因为未声明文件头的文件会被看作隐式声明了默认的文件头。 ### 预定义键属性名 {#header-key-prefix} 在文件头行的后面,还可以跟随一些 `|` 开头的行 ## 正文 {#article-main} 在声明了文件头之后(或者不声明也没有问题),就可以开始写正文了。 hytrans 的正文是一个 键-值 表的数据,每一个键-值对中还可以保存一些参数,用以特殊用途。 ### 键 {#main-key} 声明键值对中的键十分简单——只需要使用任何没有特殊含义的字符起始此行,此行就会被认为是一个键值对数据的起点和键声明。 在 1.0 版本中,hytrans 中有特殊含义的字符有 | / $ % # TAB SPACE EOL,没有特殊含义但被保留使用的字符有 \ &。用这些字符之外的任意字符起始此行,都可以被解析为是键声明。 在解析器解析到键声明的时候,就意味着自此行以下到下一个键声明或下一个文件头声明都属于这个键-值对的作用域了。 *对了,再次强调一下,**注意行尾空格!*** ### 值 {#main-value} 在声明了键之后,就可以通过 `|` 前导字符来声明值了。 值可以声明多行,其中的任何字符也都会按照原样 `AS IS` 被录入进数据。也包括起始空格和行尾空格。同时目前而言,hytrans 并**不支持转义字符**,例如 `\t` 会被解析为字符串 `\t`(在大多数语言里相当于在字符串声明时写 `\\t`)。 因此,在大多数语言中可以使用的 `\u33a7\u1488\uc541` 这种转义 unicode 序列在 hytrans 标准中完全不起作用(尽管不排除未来会更新相关的选项)。所以老生常谈的是,请注意文件编码。