
当您的产品开始在具有自己的语言和文化特征的另一个国家销售时,会发生什么? 最有可能的是,本地化正等着他。 在大多数情况下,仅需要翻译资源文件,以便菜单和界面元素使用用户熟悉的语言。 但是,如果销售的基础是数据,该怎么办呢?数据很多,它们不断地大量涌入,需要定期翻译。 不仅是一种语言,而且是多种语言。
在剪辑下,您将找到有关2GIS中如何解决此问题的故事。 我将以迪拜的最后一个案例为例,但这种做法适用于任何语言。
关于阿拉伯语
整个故事始于2GIS在迪拜启动的事实,迪拜使用两种语言:阿拉伯语和英语。
数据的准确性是公司最重要的价值。 这是通过在地上制图师和专家的体力劳动来实现的。 在迪拜,当地专家和最终用户都懂英语,最初只在其中输入数据。 在成长的过程中,他们决定不停下来,而是添加阿拉伯语。
斐济
对于制图师的工作,我们拥有自己的软件。 这件事叫做斐济,是收集地图数据的主系统。
我们已经写过斐济如何帮助制图师编辑房屋和绘制道路。 经过处理和准备后从斐济上传的数据将流向最终产品,以讨好用户。 在本文中,我正在谈论的正是我们在斐济实施的用于编辑/存储/显示多语言数据的内容。
条款
在团队中,我们使用特定的词汇。 以下是四个示例↓
系统支持使用两种类型的语言:
元数据语言-显示所有用户控件的语言:UI,元数据。
数据语言-一种显示地理对象,某些目录和分类器的属性值的语言。
语言与领土相关。 区域可以具有两种语言:
该地区的主要语言是该地区正式采用的语言。
地区的其他语言是我们要发布产品的语言。 它是主要产品的补充。
语言和方言
该国不同地区采用的方言可能会有很大差异。 因此,在某些系统中,语言的核心(=基本版本)和方言是分开存储的,然后在卸载它们的词缀时才存储。 在我们看来,这种方法非常复杂,因此我们决定将每种方言都视为一种独立的语言。
与阿拉伯语言和方言有关的细微差别。 对于每种语言,您需要输入带有两个值的笔架方向标记:从左到右和从右到左。 默认情况下,笔架应从左向右移动。 如果该值是从右到左设置的,那么您需要为所有可编辑的多语言字段更改笔架的方向。 在最终产品中如何做到这一点写
在这里 。 我们必须做同样的事情。
捕捉到领土
我们的整个世界分为某些地区-这些地区可能是国家/地区,地区。 对于每个地区,我们都指定了几种语言,其中一种被认为是主要语言,其余被认为是其他语言。 翻译是从主要语言到其他语言的。
例如,在迪拜,我们将英语作为主要语言,因为它有很多数据。 阿拉伯语是可选的。
输入并更改语言
为了使制图师舒适地工作,我们在需要使用多种语言输入的地方重新设计了界面。

在这张图片中,您可以看到我们将语言划分为选项卡,其中最左侧是主要语言,然后还有其他语言。
在其他语言的选项卡中,只有那些带有标记的字段可用于编辑,这些标记需要在数据库中进行翻译。 这是一种保护措施,有助于将用户的注意力集中在必要数据的转换上。 其他所有内容均以主要语言进行编辑。

实际上,仅当制图人员本人会几种语言并且不希望借助翻译者的帮助时,才需要使用其他语言编辑数据。 对于其他所有人,都有CrowdIn。
Crowdin或流传输
因此,我们使制图人员能够以不同的语言填写数据。 但是最好将翻译任务交给专业人员。
翻译应用程序时想到的第一件事是将资源文件提供给翻译器,并在传输后将其下载回去。
在这个问题上,CrowdIn平台为我们提供了很多帮助。 它使您可以将文件重定向到专业翻译人员。 剩下的唯一事情就是将转换后的数据集成到我们的系统中。
由于数据连续不断地传给我们,因此情况变得复杂,因此我们希望连续接收翻译。
我们对系统进行了如下优化:如果在该地区的主要语言中进行了更改,我们会将更改上传并翻译为该地区的所有其他语言。 对于制图师本人进行翻译的情况,我们例外。 在这里,我们认为他了解自己在做什么,因此无需连接翻译。
对于每个目录或映射对象,我们都有一个端到端版本,该版本随每次数据更新而增加。 因此,我们可以快速获取特定版本的所有更改。
版本控制系统非常简单且高效,但存在一个重大缺点:实际上,我们只有一个队列,无法以任何方式进行管理。 我们最多只能跳过该版本。 需要切换到普通队列,例如,切换到RabitMQ或Kafka,但还没有动手。
为了快速更新内容,我们编写了一个可在三个流中工作的小型服务。
第一流(Saver)抽取出所有需要翻译的数据,并从中生成xml文件。
第二个(导出)将它们发送到CrowdIn并将它们放入所需的项目中,该项目指示我们要翻译的主要语言以及要翻译成的语言的列表。
第三个(导入)会定期轮询CrowdIn API以查找已完成转换并已100%安装的文件,然后将完成的文件导入到我们的数据库中。

没有耙子就做不到。 我们偶然发现了数据版本控制系统。
当我们下载单词的翻译时,数据的版本已更新,单词再次落入翻译中。
为了避免无休止的翻译循环,我们开始记录数据。 每个翻译的单词都有标记,从而消除了重复发送到CrowdIn的麻烦。
讲解
现在,我将告诉您CrowdIn的工作如何进行。 有多种使用该平台的方法,例如,您可以将文件上传到Git存储库,而CrowdIn本身会吸收它们。 但是我们认为通过API进行操作看起来更加方便。
CrowdIn有一个非常详细的
教程 ,但是下面我将写我们如何做到的。
我们需要获取一个API密钥,该密钥将附加到我们的每个请求中,以便系统验证我们。 我们转到项目设置中的“ API”选项卡,然后查看“ API密钥”列中写的内容。

必须在每个平台请求的末尾添加此密钥。 例如,像这样:
GET:
https://api.crowdin.com/api/project/{myLitleProject}/download/all.zip?key={project-key}
:
https://api.crowdin.com/api/project/{myLitleProject}/download/all.zip?key={project-key}
myLitleProjectasket / download /
https://api.crowdin.com/api/project/{myLitleProject}/download/all.zip?key={project-key}
project-
https://api.crowdin.com/api/project/{myLitleProject}/download/all.zip?key={project-key}
2.创建一个文件夹,我们将在其中上传文件到项目中。
var uri = $"project/{_projectName}/add-directory?key={apiKey}"; var content = new MultipartFormDataContent { { new StringContent(crowdInDirectoryPath), "name" } }; return PostAsync(uri, content);
有一点笨拙的时刻。 我们正在编写服务,如果在开始创建服务之前先检查一下是否存在我们需要的文件夹,那将是很好的选择。 CrowdIn没有检查文件夹的常规方法,因此我们发送创建请求。 如果不存在,则CrowdIn将创建它并返回代码200。如果有文件夹,它将不创建任何内容并返回代码500。
3.导出文件。 添加文件功能具有很多选项和参数,如何读取以及在何处。 以下是我们如何使用xml文件加载数据的示例。
例子我们使用以下结构将要转换的所有数据放入xml文件。
<LocalizableDocument> <LocalizableValues> <LocalizableValue> … <Attributes> <LocalizableAttributeValue> <AttributeName/> <Value/> </LocalizableAttributeValue> </Attributes> </LocalizableValue> </LocalizableValues> </LocalizableDocument>
为了使CrowdIn解析文件中需要翻译的数据,需要指定它。 为此,您需要编写一个translatable_elements参数数组,其中包含文档中必要元素的路径。 在我们的例子中,它看起来像这样:
var uri = $"project/{_projectName}/add-file?key={apiKey}"; var content = new MultipartFormDataContent { { new StringContent("/LocalizableDocument/LocalizableValues/LocalizableValue/Attributes/LocalizableAttributeValue/Value"), "translatable_elements[0]" } }; foreach (var filePath in filePaths) { var fileName = Path.GetFileName(filePath); var fileStream = File.OpenRead(filePath); var fileContent = new StreamContent(fileStream); content.Add(fileContent, $"files[{_crowdInDirectoryPath}/{fileName}]", fileName); } return PostAsync(uri, content);
请注意:文档指出CrowdIn一次最多可以咀嚼20个文件,而一个文件的大小不应超过100 MB。
4.我们找出我们已完全翻译的文件。 我们使用针对特定语言的命令来执行此操作。
var uri = $"project/{_projectName}/language-status?key={apiKey}"; var content = new MultipartFormDataContent {{ new StringContent(langCode), "language" } }; return PostAsync(uri, content);
该平台将向我们返回如下内容:
<item> <node_type>directory</node_type> <id>29812</id> <name>Version 1.0</name> <files> <item> <node_type>file</node_type> <id>29827</id> <name>strings.xml</name> <node_type>file</node_type> <phrases>7</phrases> <translated>0</translated> <approved>0</approved> <words>32</words> <words_translated>0</words_translated> <words_approved>0</words_approved> </item> </files> </item>
在这里,我们对值<translated />和<approved />感兴趣。 第一个显示此文件中已翻译行的百分比,第二个显示如果除翻译者之外,审阅者还参与工作流的批准值的百分比。 根据我们的工作流程,例如,在100,我们会考虑翻译和批准文档。 现在可以将该文件导入回给我们。
5.将文件导入回我们的系统。
这是通过简单的GET请求完成的。
https://api.crowdin.com/api/project/{_projectName}/export-file?file={_crowdInDirectoryPath}/{fileName}&language={langCode}&key={project-key}
生成的文件将反序列化,并将数据导入到我们的系统中。
而不是结论
一般来说,仅此而已。 当然,我们仍然需要改进斐济地图上的签名显示,以便根据制图员现在统治的地区以正确的语言显示签名。 必须与其他系统达成共识,我们将如何向他们提供多语言数据,但这是另一回事了。
结果,我们本着“开机忘了”的精神接受了服务。 制图人员输入数据,翻译人员进行翻译,行长满意,该服务在必要时上传数据,我们无需考虑我们的系统如何以多种语言工作就解决了更为紧迫的问题。