如何使用Globalize将翻译存储在数据库中

by Anastasia

由Anastasia

如何使用Globalize将翻译存储在数据库中 (How to store translations inside a database with Globalize)

In one of my previous articles, I talked about the process of internationalizing Rails applications. That article explained all I18n basics, but it was revolving around placing all translations inside YAML files. There is nothing wrong with this approach, but unfortunately it does not always work.

在之前的一篇文章中,我谈到了Rails应用程序国际化的过程。 那篇文章解释了所有I18n基础知识,但围绕着将所有翻译内容放入YAML文件中展开。 这种方法没有错,但是不幸的是,它并不总是有效。

Suppose your website has lots of user-generated content which should be adapted for different languages. I propose that you store your translations inside the database. Why will YAML files not work in this case?

假设您的网站上有许多用户生成的内容,这些内容应适用于不同的语言。 我建议您将翻译存储在数据库中。 为什么在这种情况下YAML文件不起作用?

  • The content itself may be quite large and it would be inconvenient to store it inside a file

    内容本身可能很大,将它存储在文件中会很不方便
  • The content is dynamic and users should be able to create translated versions themselves, without the help of the site’s developer

    内容是动态的,用户应该能够自己创建翻译版本,而无需网站开发人员的帮助

It appears that the I18n module allows you to define a custom backend that, for instance, may be powered by ActiveRecord. Luckily, there is no need to craft your own solution as there is already an existing one: Globalize. Globalize is a battle-tested library characterized as “Rails I18n de-facto standard library for ActiveRecord model/data translation.” With its help you can easily translate model attributes, scope them, introduce fallbacks, and so on.

看来,I18n模块允许您定义一个自定义后端 ,例如,可以由ActiveRecord提供支持。 幸运的是,由于已经存在一个解决方案,因此无需设计自己的解决方案: Globalize 。 Globalize是经过实践检验的库,其特征是“用于ActiveRecord模型/数据转换的Rails I18n实际标准库”。 借助它的帮助,您可以轻松地转换模型属性,对其进行范围划分,引入后备等等。

So, in this article we are going to talk about Globalize and see it in action by creating a sample Rails application. Shall we start?

因此,在本文中,我们将讨论Globalize,并通过创建示例Rails应用程序来了解它的实际作用。 我们可以开始了吗?

准备申请 (Preparing the Application)

Let’s get started by generating a new Rails app:

让我们开始生成一个新的Rails应用程序:

rails new GlobalizeSample

I’ll assume you are using Rails 5.2.1 for this demo but still the described concepts apply to earlier versions as well.

我假设您在此演示中使用Rails 5.2.1 ,但所描述的概念仍然适用于早期版本。

Let’s suppose we are building an international online shop showcasing various products. These products will be added by the administrator, and so we can’t know what the content will be ahead of the game. This means that the traditional method of using YAML files to store translations won’t work. Our content manager will have access to the CMS only, and we would rather not give them access to the source code of the app (I shudder to think about it!).

假设我们正在建立一个展示各种产品的国际网上商店 。 这些产品将由管理员添加,因此我们不知道游戏前会包含哪些内容。 这意味着使用YAML文件存储翻译的传统方法将不起作用。 我们的内容管理器将只能访问CMS,而我们不希望他们访问应用程序的源代码(我不禁要考虑!)。

But, fear not, in the next section we will overcome this problem easily. For now, however, let’s take care of the basics.

但是,不用担心,在下一节中,我们将轻松克服此问题。 但是,现在让我们来了解一些基础知识。

管理产品 (Administering Products)

Utilize code generator and create a new scaffold for the Product:

利用代码生成器并为Product创建一个新的支架:

rails g scaffold Product title:string description:text

This should create a model, controller, routes, and views for the products. Don’t forget to run the migration:

这应该为产品创建模型,控制器,路线和视图。 不要忘记运行迁移:

rails db:migrate

Now start the server:

现在启动服务器:

rails s

Visit the http://localhost:3000/products path and make sure that you are able to add, modify, and delete the products.

访问http://localhost:3000/products路径,并确保您能够添加,修改和删除产品。

切换语言 (Switching the Language)

In order to see the Globalize library in action, we will need a way to switch the app’s locale. I won’t cover this process in detail (as we have a separate article on the topic) so let’s do it quickly.

为了查看Globalize库的运行情况,我们需要一种方法来切换应用的语言环境。 我不会详细介绍此过程(因为我们有关于该主题单独文章 ),所以让我们快速进行。

First, add the list of supported locales to the config/application.rb:

首先,将支持的语言环境列表添加到config/application.rb

# ... config.i18n.available_locales = [:en, :ru]

I will be supporting English and Russian, but you may choose any other languages.

我将支持英语和俄语,但您可以选择其他任何语言。

Next, tweak the config/routes.rb and wrap the product resource with a scope. Also, while we are here, add a root route:

接下来,调整config/routes.rb并使用范围包装产品资源。 另外,当我们在这里时,添加一条根路由:

scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do # <== add this resources :products root 'products#index' # <== add this end # <== add this

After that, modify the application_controller.rb file:

之后,修改application_controller.rb文件:

# ... before_action :set_locale private def set_locale I18n.locale = extract_locale || I18n.default_locale end def extract_locale parsed_locale = params[:locale] I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil end def default_url_options { locale: I18n.locale } end

This code will set the locale on every request while making sure the chosen language is actually supported. Also, it will add a locale GET param to each link generated with the link_to helper.

该代码将在每个请求上设置语言环境,同时确保实际支持所选语言。 另外,它将为使用link_to帮助程序生成的每个链接添加一个locale GET参数。

Lastly, add two links to the application layout:

最后,添加两个指向应用程序布局的链接:

<!-- views/layouts/application.html.erb --> <ul> <li><%= link_to 'English', root_path(locale: :en) %></li> <li><%= link_to 'Русский', root_path(locale: :ru) %></li> </ul>

To ensure that this new feature works, add translation for the Products page title:

为确保此新功能正常运行,请为“产品”页面标题添加翻译:

# config/locales/en.yml en: products: index: title: Our Products
# config/locales/ru.yml ru: products: index: title: Наши продукты

Now simply utilize these translations inside the views/products/index.html.erb:

现在,只需在views/products/index.html.erb内部利用这些翻译:

<!-- ... --> <h1><%= t '.title' %></h1> <!-- ... -->

Note that we can take advantage of the “lazy lookup” because the translation keys were named in the proper way.

请注意,我们可以利用“惰性查找”功能,因为转换键是以正确的方式命名的。

Translate other static content as necessary, then reload the server, and make sure that the locale can be properly switched. Great!

根据需要转换其他静态内容,然后重新加载服务器,并确保可以正确切换语言环境。 大!

全球化,艰苦全球化! (Globalize, Globalize it Hard!)

定义翻译属性 (Defining Attributes For Translation)

Okay, the ground work is done and we may proceed to the next part. Before Globalize can get into the game, it should be added to the Gemfile:

好的,基础工作已经完成,我们可以继续进行下一部分。 在Globalize进入游戏之前,应将其添加到Gemfile

# ... gem 'globalize', git: 'https://github.com/globalize/globalize'

At the time of writing this article, the stable version was not yet compatible with Rails 5.2, so we have to install directly from the master branch. Also note that the latest stable does not support ActiveRecord 4.1 and below, therefore refer to the documentation to learn which Globalize version to use for older AR.

在撰写本文时,该稳定版本尚未与Rails 5.2兼容,因此我们必须直接从master分支进行安装。 另请注意,最新的稳定器不支持ActiveRecord 4.1及更低版本,因此请参考文档以了解用于较旧的AR的哪个Globalize版本。

Next, you have to decide which model attributes will be translated with Globalize. We are going to translate both :title and :description so list them in the model in the following way:

接下来,您必须决定要使用Globalize转换哪些模型属性。 我们将同时翻译:title:description因此可以通过以下方式在模型中列出它们:

# models/products.rb # ... translates :title, :description

This will allow you to store store translations inside the database per locale. To make it work, however, you also need to create a special translation table.

这将使您可以按语言环境在数据库内部存储商店翻译。 为了使其工作,您还需要创建一个特殊的转换表

翻译表 (Translation Table)

So, if you are creating a new model and a migration, things are as simple as using a create_translation_table! method as explained here. Our case is a bit more complex, because we already have a products table with some data. Therefore it is required to move these data to the translation table. Start by generating a new migration:

因此,如果您要创建新模型并进行迁移,那么事情就像使用create_translation_table!一样简单create_translation_table! 此处解释的方法。 我们的情况要复杂一些,因为我们已经有一个包含一些数据的products表。 因此,需要将这些数据移到转换表中。 首先生成一个新的迁移:

rails g migration translate_products

Now flesh it out with the following code:

现在用以下代码充实它:

# db/migrate/xyz_translate_products.rb class TranslateProducts < ActiveRecord::Migration[5.2] def change reversible do |dir| # <=== 1 dir.up do Product.create_translation_table!({ # <=== 2 title: :string, # <=== 3 description: :text }, { migrate_data: true, # <=== 4 remove_source_columns: true # <=== 5 }) end dir.down do Product.drop_translation_table! migrate_data: true # <=== 6 end end end end

I’ve pinpointed the main things to note about this code:

我已经确定了有关此代码的主要注意事项:

  1. This is going to be a reversible migration.

    这将是可逆的迁移。
  2. We are creating a translation table for the Product.

    我们正在为Product创建一个转换表。

  3. Carefully list all the fields that should be translated as well as their types. As you recall, these fields were passed to the translates method inside the model.

    仔细列出所有应翻译的字段及其类型。 您还记得,这些字段已传递给模型内部的translates方法。

  4. Don’t forget to provide the migrate_data option that should preserve your original database records.

    别忘了提供应保留原始数据库记录的migrate_data选项。

  5. remove_source_columns will ensure that the original columns (:title and :description) will be removed from the products table. You may also perform this step later in a separate migration.

    remove_source_columns将确保从products表中删除原始列( :title:description )。 您也可以稍后在单独的迁移中执行此步骤。

  6. That’s the action to perform when the migration is rolled back. Data should be preserved as well.

    这是回滚迁移时要执行的操作。 数据也应保留。

Run the migration:

运行迁移:

rails db:migrate

After this command finishes its job, you will see a new product_translations table:

该命令完成工作后,您将看到一个新的product_translations表:

As you see, there is a product_id column that establishes relation to the product, and also a locale field to denote which language this translation is for. When you migrate your original data, it will be associated with the app’s default locale (which is English in our case). Override this behavior by using a with_locale method, for example:

如您所见,这里有一个product_id列,该列建立与产品的关系,还有一个locale字段,表示此翻译的语言。 迁移原始数据时,原始数据将与应用程序的默认语言环境(在我们的示例中为英语)相关联。 通过使用with_locale方法覆盖此行为,例如:

I18n.with_locale(:ru) do Post.create_translation_table!(...) end

If you need to add more translated fields to the table later, utilize an add_translation_fields! method as shown in this example. Also, don’t forget to define these new fields in the model.

如果以后需要在表中添加更多翻译字段,请使用add_translation_fields! 方法如本例所示 。 另外,不要忘记在模型中定义这些新字段。

试试吧! (Try It!)

At this point Globalize is integrated into our application and ready to get rolling! Perform the following steps to see it in action:

此时,Globalize已集成到我们的应用程序中,随时可以开始使用! 执行以下步骤以查看实际效果:

  • Reload your server and try to create a new product: its title and description will be provided for the currently set locale only (English in my case).

    重新加载服务器并尝试创建新产品:仅针对当前设置的语言环境提供标题和描述(本例为英文)。
  • Switch to Russian locale and make sure that both title and description are missing for the new product.

    切换到俄语语言环境,并确保新产品的标题和描述均丢失。
  • Edit this product and enter values for the Russian version of the product.

    编辑此产品,并输入该产品俄语版本的值。

As a result you should see two translations being stored inside the product_translations table:

结果,您应该看到两个翻译存储在product_translations表中:

Great job!

很好!

更多全球化功能 (Some More Globalize Features)

后备 (Fallbacks)

What happens if Globalize cannot find translated attributes for the given locale? As we’ve seen in the previous section, by default it will return blank values (which are actually nils). However, it is possible to enable I18n fallbacks and display attribute values from another locale. To achieve that, just turn fallbacks on inside the config/application.rb file:

如果Globalize找不到给定语言环境的翻译属性,会发生什么? 如上一节所述,默认情况下它将返回空白值(实际上为nil )。 但是,可以启用I18n后备并显示其他语言环境的属性值。 为此,只需在config/application.rb文件中启用后备:

# ... config.i18n.fallbacks = true

Now when the translated attribute is nil, Globalize will try to load values from another locale. To make sure this feature is working, reload the server, create a new product, and then switch to another language. The title and description should fallback to another locale.

现在,当转换后的属性为nil ,Globalize将尝试从另一个语言环境加载值。 为确保此功能正常工作,请重新加载服务器,创建新产品,然后切换到另一种语言。 标题和描述应回退到其他语言环境。

If you would like to employ fallbacks when the translation values are also blank (not nil), set the fallbacks_for_empty_translations option to true:

如果您希望在转换值也为空白(而不是nil )时采用回退,请将fallbacks_for_empty_translations选项设置为true

# models/product.rb # ... translates :title, :description, fallbacks_for_empty_translations: true

Also note that it is possible to define a custom fallback chain globally in the following way:

还请注意,可以通过以下方式全局定义自定义后备链:

# somewhere in an initializer Globalize.fallbacks = {:en => [:de, :ru]}
范围和背景 (Scope and Context)

Globalize provides a special model scope called with_translations that can be used to load translation for a given language. In this example we are loading all translations for the English locale only:

全球化提供了一个特殊的模型范围,称为with_translations ,可用于加载给定语言的翻译。 在此示例中,我们仅加载英语语言环境的所有翻译:

Product.with_translations('en')

On top of that, it is possible to display translation for a desired locale in your views. To achieve that, use a with_locale method:

最重要的是,可以在视图中显示所需语言环境的翻译。 为此,请使用with_locale方法:

<% Globalize.with_locale(:en) do %> <!-- render your stuff here... --> <% end %>
插补 (Interpolation)

What’s interesting is that Globalize even supports interpolation in the translated attributes. It works in the same way as interpolation in YAML translation files:

有趣的是,Globalize甚至支持在转换的属性中进行插值。 它的工作方式与YAML转换文件中的插值相同:

product.title = "Product for %{someone}" product.title someone: "John" # => "Product for John"

So, the placeholder here is %{someone}. To provide its value, simply pass a hash to the proper model attribute. Really convenient!

因此,此处的占位符为%{someone} 。 要提供其值,只需将哈希传递给适当的model属性即可。 真的很方便!

结论 (Conclusion)

In this section we have seen how to store translations inside database with the help of Globalize solution. We have discussed its basics, seen how to install and configure it, how to migrate data properly, how to define translations, provide fallbacks and utilize scopes. All in all, we have covered nearly everything Globalize has to offer, and so you may now apply these concepts into practice! Also don’t forget that Globalize can safely play with YAML files, so you can mix and match these approaches as you see fit.

在本节中,我们已经看到了如何借助Globalize解决方案将翻译存储在数据库中。 我们已经讨论了其基础知识,了解了如何安装和配置它,如何正确迁移数据,如何定义翻译,提供后备功能和利用范围。 总而言之,我们几乎涵盖了Globalize提供的所有内容,因此您现在可以将这些概念付诸实践! 同样不要忘记Globalize可以安全地处理YAML文件,因此您可以根据需要混合和匹配这些方法。

Which solution do you utilize to internationalize user-generated content? Would you give Globalize a go? Share your thoughts in the comments section!

您使用哪种解决方案来国际化用户生成的内容? 您愿意放弃全球化吗? 在评论部分分享您的想法!

Lokalise让您的生活更轻松 (Make Your Life Easier With Lokalise)

Supporting multiple languages on a big website may become a serious pain. You must make sure that all the keys are translated for each and every locale. Luckily, there is a solution to this problem: the Lokalise platform that makes working with the localization files much simpler. Let me guide you through the initial setup which is nothing complex really.

在大型网站上支持多种语言可能会变得很痛苦。 您必须确保为每个语言环境翻译了所有键。 幸运的是,有一个解决此问题的方法:使用Lokalise平台可以更轻松地处理本地化文件 。 让我指导您完成初始设置,这实际上并不复杂。

  • To get started, grab your free trial

    首先, 请免费试用

  • Create a new project, give it some name, and set English as a base language

    创建一个新项目,为其命名,并将英语设置为基本语言
  • Click “Upload Language Files”

    点击“上传语言文件”
  • Upload translation files for all your languages

    上传所有语言的翻译文件
  • Proceed to the project, and edit your translations as needed

    进入项目,并根据需要编辑翻译
  • You may also contact professional translator to do the job for you

    您也可以联系专业翻译为您完成工作
  • Next simply download your files back

    接下来只需将文件下载回来
  • Profit!

    利润!

Lokalise has many more features including support for dozens of platforms and formats, and even the possibility to upload screenshots in order to read texts from them. So, stick with Lokalise and make your life easier!

Lokalise具有更多功能,包括对数十种平台和格式的支持,甚至可以上传屏幕截图以从中读取文本。 因此,坚持使用Lokalise,让您的生活更轻松!

Originally published at blog.lokalise.co on November 16, 2018.

最初于2018年11月16日发布在blog.lokalise.co

翻译自: https://www.freecodecamp.org/news/how-to-store-translations-inside-a-database-with-globalize-63cd033e29e6/

Globalize 是利用官方 Unicode CLDR JSON 数据来进行国际化和本地化的 JavaScript 库。浏览器支持:Chrome: (Current - 1) or CurrentFirefox: (Current - 1) or CurrentSafari: 5.1 Opera: 12.1x, (Current - 1) or CurrentIE 8 (needs ES5 polyfill), IE9 文件结构:├── bower.json (metadata file) ├── CONTRIBUTING.md (doc file) ├── dist/ (consumable files, the built files) ├── external/ (external dependencies, eg. cldr.js, QUnit, RequireJS) ├── Gruntfile.js (Grunt tasks) ├── LICENSE.txt (license file) ├── package.json (metadata file) ├── README.md (doc file) ├── src/ (source code) │   ├── build/ (build helpers, eg. intro, and outro) │   ├── common/ (common function helpers across modules) │   ├── core.js (core module) │   ├── date/ (date source code) │   ├── date.js (date module) │   ├── message.js (message module) │   ├── number.js (number module) │   ├── number/ (number source code) │   ├── plural.js (plural module) │   ├── plural/ (plural source code) │   └── util/ (basic JavaScript helpers polyfills, eg array.map) └── test/ (unit and functional test files)     ├── fixtures/ (CLDR fixture data)     ├── functional/ (functional tests)     ├── functional.html     ├── functional.js     ├── unit/ (unit tests)     ├── unit.html     └── unit.js 标签:Globalize
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值