Custom translation function in Rails - ruby-on-rails

I have an application that I'm currently localizing to Arabic but Im facing a small problem.
In the English version of the website, I display some sizes as follows 10x15 15x18 etc, and they are stored in the database as such.
In my Arabic version I want to display instead 10*15 15*18 etc.
Currently, I have a string replace function in one of the models as follows:
if I18n.locale == :ar
size.sub! 'x', '*'
end
but I'm sure that I shouldn't have code like that in a model. How can I do this using the usual I18n ways?

x in database is internal for your storage means, so strictly speaking for english you also should have size.sub! 'x', 'x' (which does nothing, because symbol is the same, but it changes it's meaning).
You're correct that symbol belongs to locale. Locales support variables in translations:
en:
some_size: "%{width}x%{height}"
ar:
some_size: "%{width}*%{height}"
I18n.t('some_size', width: size.split('x').first, height: size.split('x').second)
(to make the last expression more tidy - you can have width/height or size_hash and use splats)

Related

Are There Any Rails Modules or Classes Which Provide Frozen HTML Content Type Strings?

Ive been searching through source for a while, and it appears to me that there are no given Rails tools for retrieving the String representation of various HTML content types. Ive also found this to be a very difficult concept to search for in general.
What I want is something like this:
Mime::Mimes::CONTENT_TYPE_JSON = 'application/json'.freeze
or, Mime::Mimes::CONTENT_TYPES[:json] etc.
...because I want to do a lot of things like some_value == 'application/json' or some_value = 'application/json' etc.
I want to use the expression "application/json" often, and I dont want to create new String instances for something that is pretty well within the domain of web application development. Ive thought of creating my own app consts or vars so I dont have to allocate HTML Content Type strings more than once, but also feel this should just be available for me in any web application framework (at least, those written in languages where every string is a new memory allocation).
Is there a better tool or resource within the Rails 5 source that I am missing that allows easy retrieval of content type strings? Do I have to get a gem / create my own for this?
Note: Im away of how heavy of an "optimization" this may appear to be. Let's then entertain this query from a position of being pragmatic about organizational style, for a project that requires elimination of any duplication of domain-specific string literals, and to keep them symbolized or as some frozen const. Let's pretend its a personal project for the sheer joy of experimenting with such style!
There is a shorthand for it:
Mime[:json]
Mime#[] -
https://github.com/rails/rails/blob/e2efc667dea886e71c33e3837048e34b7a1fe470/actionpack/lib/action_dispatch/http/mime_type.rb#L41
which uses
Mime::Type#lookup_by_extension -
https://github.com/rails/rails/blob/e2efc667dea886e71c33e3837048e34b7a1fe470/actionpack/lib/action_dispatch/http/mime_type.rb#L149
If you want to get the actual content type you might need to call a #to_s on it:
Mime[:json].to_s
Creating a new module to facilitate simple storage and retrieval using the ActionPack Mime::Type system would work as follows:
# Build hash of type name to value, e.g., { xml: "application/xml" }
CONTENT_TYPES = {}.tap do |simple_content_types_hash|
# Get each registered Mime Type
Mime::EXTENSION_LOOKUP.each do |mime|
simple_content_type_hash[mime.first.to_sym] = mime.last.instance_variable_get("#string").freeze
end
end.freeze
Note: the above is untested, its just a generalization of what I am looking for. Thanks to #Fire-Dragon-DoL for the tip.
This could be added via an initializer, patched into an existing module, or into a new helper module.

Prevent Ruby from changing & to &?

I need to display some superscript and subscript characters in my webpage title. I have a helper method that recognizes the pattern for a subscript or superscript, and converts it to &sub2; or ²
However, when it shows up in the rendered page's file, it shows up in the source code as:
&sub2;
Which is not right. I have it set up to be:
<% provide(:title, raw(format_title(#hash[:page_title]))) %>
But the raw is not working. Any help is appreciated.
Method:
def format_title(name)
label = name
if label.match /(_[\d]+_)+|(~[\d]+~)+/
label = label.gsub(/(_([\d]+)_)+/, '&sub\2;')
label = label.gsub(/(~([\d]+)~)+/, '&sup\2;')
label.html_safe
else
name
end
end
I have even tried:
str.gsub(/&/, '&')
but it gives back:
&amp;sub2;
You can also achieve this with Rails I18n.
<%= t(:page_title_html, scope: [:title]) %>
And in your respective locale file. (title.en.yml most probably):
title:
page_title: "Title with ²"
Here is a chart for HTML symbols regarding subscript and superscripts.
For more information check Preventing HTML character entities in locale files from getting munged by Rails3 xss protection
Update:
In case you need to load the page titles dynamically, first, you'll have to install a gem like Page Title Helper.
You can follow the guide in the gem documentation.
There are two of issues with your example, one is of matter and the other is just a coincidence.
The first issue is you are trying to use character entities that do not actually exist. Specifically, there are only ¹, ² and ³ which provide 1, 2 and 3 superscript symbols respectively. There is no such character entity as &sup4; nor any other superscript digits. There are though bare codepoints for other digits which you can use but this would require a more involved code.
More importantly, there are no subscript character entities at all in HTML5 character entities list. All subscript digits are bare codepoints. Therefore it makes no sense to replace anything with &sub2; or any other "subscript" digit.
The reason you didn't see your example working is due to the test string you chose. Supplying anything with underscores, like _2_mystring will be properly replaced with &sub2;. As &sub2; character entity is non-existent, the string will appear as is, creating an impression that raw method somehow doesn't work.
Try to use ~2~mystring and it will be replaced with the superscript character entity ² and will be rendered correctly. This illustrates that your code correct, but the basic assumption about character entities is not.

using 18n and I18n:Alchemy in rails in order to translate a text value according to the locale

In my application, there is a field credit_debit that has two string values: 'credit' and 'debit'.
These two terms should be shown in a localized form to the user, so that when the app is using an italian locale they should be translated into 'avere' and 'dare'.
I could write my own setter/getter method for the credit_debit field and handle this issue inside it, but maybe I could leverage the I18n architecture to do so in a way that is consistent with the rest of the localization. If it's possible, how can I implement this?
Can't see the problem if you're already using i18n localization.
Just use the field as a key for i18n (with a prefix if you like)
t("prefix_#{credit_debit}")
and just define the strings for both your locales.
So in your en locale:
prefix_credit: credit
prefix_debit: debit
And in your it locale:
prefix_credit: avere
prefix_debit: dare

Should I use unique ids or the whole sentences when localizing software?

I need to translate a website to a couple languages, and I've already read how to do it:
Mark strings for translation
Generate messages file
Translate messages file
The problem is, if I use whole sentences as the message ids, in english, for example, then if later I decide to modify the text, I'll have to change it in the code and on each message file . Or I could just change the english translation, but then my english message file will look weird, with translations from english to english which do not match.
Example:
Original: "I don't know what to do."
Translation: "I'm not sure what to do."
An alternative is to use unique message ids such as:
Original: "INDECISION_MESSAGE"
Translation: "I'm not sure what to do."
The advantage is that I can change translations without changing the id and things will still be consistent. But then there is no easy way for a translator to know what the message should be like as there is no context except by looking at the code.
What would you use?
In PHP people normally use the first approach you mentioned. In ASP.NET the second.
I think it's more of a personal taste and a matter of the framework that you use.
Personally I prefer the second option. Since you normally already have the ID/translation pair somewhere in a list, the translator can just take that list to translate.
What framework do you use?

Symfony/Doctrine: Fallback to default culture for i18n content

I am building a multilingual website with Symfon 1.4/Doctrine, having English language defined as primary.
Content translation in other languages are added gradually, and there will very often be situations when translation of the content requested will be unavailable in requested language. I want to display the requested content in English in those cases.
Is this achievable at global level, e.g. for all the i18n content?
As pointed by Grad van Horck, this works fine by default for interface translation.
What I need is the same functionality for content stored in DB (models having "actAs i18n" behavior).
The default way allows perfectly for this. Just make sure all your texts are in English by default, and translate them where needed. So just do <?php echo __('Hello'); ?>, and then translate it if you want. If a translation can't be found, it just falls back at it's 'original'.
To do the same in your database, you'd probably be best of copying the i18n behaviour (Template/Listener) and add your own bit of logic to fall back on English.
It's possible to set the default culture on sfDoctrineRecord (see http://trac.symfony-project.org/ticket/5458)
sfDoctrineRecord::setDefaultCulture('nl'); // default = 'en'
This changes the i18n fallback when the translation isn't available in the database.

Resources