Skip to content

Commit 94e3083

Browse files
committed
Merge branch 'i18n' of https://github.com/rails-taiwan/railsbridge-docs into rails-taiwan-i18n
2 parents 5dc65a7 + cafcdb3 commit 94e3083

13 files changed

+134
-62
lines changed

Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ gem 'coderay'
1313
gem "deckrb", "~> 0.5.2"
1414
gem "sass"
1515
gem "redcarpet"
16+
gem "i18n", "~> 0.6.9"
1617

1718
group :development do
1819
gem "wrong", "~> 0.7.0"

Gemfile.lock

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ DEPENDENCIES
101101
erector (~> 0.10.0)
102102
eventmachine (~> 1.0.3)
103103
files (~> 0.3.0)
104+
i18n (~> 0.6.9)
104105
nokogiri
105106
rack-codehighlighter
106107
rack-test

README.md

+26-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,32 @@ Then open <http://localhost:9292> in a web browser, and verify that you can navi
3333
To serve sites from "sites/en", use `rake run` or a vanilla deploy.
3434

3535
To server sites from another locale (say, "es" or Spanish)...
36-
* Locally, use the SITE_LOCALE environment variable: `SITE_LOCALE=es rake run`
37-
* On a server, make the server respond to a locale subdomain: `http://es.railsbridge.org`
38-
* Or to temporarily test, use a `locale` or `l` parameter: `http://docs.railsbridge.org/?l=es` (note that in this mode, links are not rewritten, so if they fail you will have to manually add the parameter again)
36+
37+
### Run Localized Site Locally
38+
39+
$ SITE_LOCALE=es rake run
40+
41+
The server listens on `0.0.0.0:9292`.
42+
43+
Now you have to setup subdomain for the site. If you have Pow, run:
44+
45+
$ echo 9292 > ~/.pow/railsbridge # works for any subdomain
46+
47+
If you don't have Pow, add the following line to `/etc/hosts`:
48+
49+
127.0.0.1 es.railsbridge.dev # works for single subdomain
50+
51+
Now you can access `http://es.railsbridge.dev:9292` for debugging.
52+
53+
### Running on a Server
54+
55+
Just make sure the server responds to a locale subdomain: `http://es.railsbridge.org`
56+
57+
### Temporary Testing
58+
59+
Use a `locale` or `l` parameter: `http://docs.railsbridge.org/?l=es`.
60+
61+
Note that in this mode, links are not rewritten, so if they fail you will have to manually add the parameter again.
3962

4063
## Contributing
4164

app.rb

+32-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
require 'sinatra'
22
require 'digest/md5'
33
require 'erector'
4+
require 'i18n'
5+
require 'i18n/backend/fallbacks'
46

57
#require 'wrong'
68
#include Wrong::D
@@ -22,15 +24,28 @@
2224
class InstallFest < Sinatra::Application # todo: use Sinatra::Base instead, with more explicit config
2325
include Erector::Mixin
2426

27+
# Set available locales in Array of Strings; this is also used when
28+
# checking availability in dynamic locale assigment, so must be as Strings.
29+
AVAILABLE_LOCALES = %w(en es)
30+
31+
configure do
32+
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
33+
I18n.load_path = Dir[File.join(settings.root, 'locales', '*.yml')]
34+
I18n.backend.load_translations
35+
36+
I18n.available_locales = AVAILABLE_LOCALES
37+
I18n.enforce_available_locales = true
38+
I18n.default_locale = :en
39+
end
40+
2541
def initialize
2642
super
2743
@here = File.expand_path(File.dirname(__FILE__))
2844
@default_sites = {en: "docs", es: "hola"}
29-
@default_locale = "en"
3045
end
3146

32-
attr_reader :here, :default_locale
33-
attr_writer :default_site, :default_locale
47+
attr_reader :here
48+
attr_writer :default_site
3449

3550
# todo: test
3651
# returns the most-specific hostname component, e.g. "foo" for "foo.example.com"
@@ -42,7 +57,7 @@ def default_site
4257
if host && sites.include?(site = subdomain)
4358
site
4459
else
45-
@default_sites[locale.to_sym]
60+
@default_sites[I18n.locale.to_sym] # no symbol DoS because it's whitelisted
4661
end
4762
end
4863

@@ -55,7 +70,7 @@ def site_dir
5570
end
5671

5772
def sites_dir
58-
Site.sites_dir(locale)
73+
Site.sites_dir(I18n.locale)
5974
end
6075

6176
def sites
@@ -68,11 +83,18 @@ def redirect_sites
6883
}
6984
end
7085

71-
def locale
86+
before do
87+
begin
88+
I18n.locale = dynamic_locale
89+
rescue I18n::InvalidLocale
90+
I18n.locale = I18n.default_locale
91+
end
92+
end
93+
94+
def dynamic_locale
7295
(params && (params[:locale] or params[:l])) or
73-
(host && subdomain =~ /^..$/ && subdomain) or # note: only allows 2-char locales for now -- should check against a list of locales
74-
(ENV['SITE_LOCALE']) or
75-
default_locale
96+
(host && AVAILABLE_LOCALES.include?(subdomain) && subdomain) or
97+
(ENV['SITE_LOCALE'])
7698
end
7799

78100
def src
@@ -103,7 +125,7 @@ def render_page
103125
doc_path: doc_path,
104126
back: params[:back],
105127
src: src,
106-
locale: locale,
128+
locale: I18n.locale,
107129
}
108130

109131
case ext

lib/contents.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def content
228228
toc_list(mark_open_and_closed(hierarchy)[:items])
229229

230230
unless orphans.empty?
231-
h1 "Other Pages"
231+
h1 I18n.t("general.other_pages")
232232
ul do
233233
orphans.each { |orphan| toc_link orphan }
234234
end
@@ -237,7 +237,7 @@ def content
237237
if has_collapsables(hierarchy)
238238
span class: "expand-all" do
239239
i class: "fa fa-arrows-alt"
240-
text "Expand All"
240+
text I18n.t("general.expand_all")
241241
end
242242
end
243243
end

lib/doc_page.rb

+8-3
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,15 @@ def body_content
121121
doc_content
122122
}
123123
if @back
124+
# Encode page name and fragment name separately so that
125+
# the fragment indicator '#' won't be escaped.
126+
page_name, fragment = @back.split('#')
127+
back_url = [URI.escape(page_name), URI.escape(fragment)].join('#')
128+
124129
div.back {
125-
text "Back to "
126-
a(class: "back", href: URI.escape(@back, URI::PATTERN::RESERVED)) do
127-
text Titleizer.title_for_page(@back.split('#').first)
130+
text I18n.t("general.back_to") + " "
131+
a(class: "back", href: back_url) do
132+
text Titleizer.title_for_page(page_name)
128133
end
129134
}
130135
end

lib/site.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class Site
55
@@project_root = File.dirname(@@here)
66

77
def self.sites_dir locale = "en"
8-
sites_dir = File.join(["sites", locale].compact)
8+
sites_dir = File.join(["sites", locale.to_s].compact)
99
File.expand_path(sites_dir, @@project_root)
1010
end
1111

lib/step.rb

+22-35
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,13 @@ def insert file
6363

6464
## steps
6565

66-
@@header_sections = {
67-
steps:"Steps",
68-
explanation:"Explanation",
69-
overview:"Overview",
70-
discussion:"Discussion Items",
71-
hints:"Hints",
72-
challenge:"Challenge(s)",
73-
tools_and_references:"Tools and References",
74-
requirements:"Requirements to advance",
75-
}
76-
77-
@@header_sections.each do |type, header|
78-
define_method type do |&block|
66+
%w[
67+
steps explanation overview discussion hints challenge
68+
tools_and_references requirements
69+
].each do |type|
70+
define_method type.to_sym do |&block|
7971
div :class => type do
80-
h1 header
72+
h1 I18n.t(type, :scope => "header_section")
8173
blockquote do
8274
block.call if block
8375
end
@@ -92,7 +84,8 @@ def step name = nil, options = {}
9284
div :class => "step", :title => name do
9385
h1 do
9486
widget BigCheckbox
95-
prefix "Step #{num}" + (!name.nil? ? ': ' : '')
87+
prefix I18n.t("general.step_title", :num => num) +
88+
(!name.nil? ? I18n.t("general.step_title_suffix") : '')
9689
text name
9790
end
9891
_render_inner_content &Proc.new if block_given?
@@ -101,7 +94,7 @@ def step name = nil, options = {}
10194

10295

10396
def link name, options = {}
104-
options = {caption: LINK_CAPTION}.merge(options)
97+
options = {caption: I18n.t("captions.link")}.merge(options)
10598
p :class => "link" do
10699
text options[:caption]
107100
text " "
@@ -114,7 +107,7 @@ def link_without_toc name
114107
end
115108

116109
def _escaped str
117-
URI.escape(str, URI::PATTERN::RESERVED)
110+
URI.escape(str)
118111
end
119112

120113
def simple_link name, options={}
@@ -135,8 +128,9 @@ def simple_link name, options={}
135128
def next_step name
136129
div :class => "step next_step" do
137130
h1 do
138-
prefix "Next Step:"
131+
prefix I18n.t("general.next_step")
139132
end
133+
# FIXME: Translate with i18n. Currently it is hard to get site_name.
140134
link name
141135
end
142136
end
@@ -150,7 +144,7 @@ def option name
150144
num = next_step_number
151145
a(:name => "step#{current_anchor_num}")
152146
h1 :class => "option" do
153-
span "Option #{num}: "
147+
span I18n.t("general.option", :num => num)
154148
text name
155149
end
156150
_render_inner_content &Proc.new if block_given?
@@ -175,7 +169,7 @@ def section text
175169

176170
def verify text = nil
177171
div :class=> "verify" do
178-
h1 "Verify #{text}"
172+
h1 I18n.t("general.verify", :text => text)
179173
blockquote do
180174
yield
181175
end
@@ -184,7 +178,7 @@ def verify text = nil
184178

185179
def goals
186180
div :class => "goals" do
187-
h1 "Goals"
181+
h1 I18n.t("general.goals")
188182
ul do
189183
yield
190184
end
@@ -255,15 +249,8 @@ def error_box(error)
255249

256250
## special
257251

258-
# todo: i18n
259-
TERMINAL_CAPTION = "Type this in the terminal:"
260-
IRB_CAPTION = "Type this in irb:"
261-
RESULT_CAPTION = "Expected result:"
262-
FUZZY_RESULT_CAPTION = "Approximate expected result:"
263-
LINK_CAPTION = "Go on to"
264-
265252
def console(commands)
266-
console_with_message(TERMINAL_CAPTION, commands)
253+
console_with_message(I18n.t('captions.terminal'), commands)
267254
end
268255

269256
def console_with_message(message, commands)
@@ -284,21 +271,21 @@ def source_code_with_message(text, *args)
284271

285272
def irb msg
286273
div :class => "console" do
287-
span IRB_CAPTION
274+
span I18n.t("captions.irb")
288275
pre msg
289276
end
290277
end
291278

292279
def type_in_file filename, msg
293280
div do
294-
span "Type this in the file #{filename}:"
281+
span I18n.t("general.type_in_file", :filename => filename)
295282
source_code :ruby, msg
296283
end
297284
end
298285

299286
def further_reading
300287
div :class => "further-reading" do
301-
h1 "Further Reading"
288+
h1 I18n.t("general.further_reading")
302289
blockquote do
303290
yield
304291
end
@@ -307,15 +294,15 @@ def further_reading
307294

308295
def result text
309296
div :class => "result" do
310-
span RESULT_CAPTION
297+
span I18n.t("captions.result")
311298
pre text.strip_heredoc
312299
end
313300
end
314301

315302
def fuzzy_result fuzzed_text
316303
fuzzed_text = fuzzed_text.strip_heredoc
317304
div :class => "result fuzzy-result" do
318-
span FUZZY_RESULT_CAPTION
305+
span I18n.t("captions.fuzzy_result")
319306
remaining_text = fuzzed_text
320307
pre do
321308
while match = remaining_text.match(/(.*?){FUZZY}(.*?){\/FUZZY}(.*)/m)
@@ -325,7 +312,7 @@ def fuzzy_result fuzzed_text
325312
end
326313
text remaining_text
327314
end
328-
div "The greyed-out text may differ and is not important.", :class => 'fuzzy-hint'
315+
div I18n.t("general.fuzzy_hint"), :class => 'fuzzy-hint'
329316
end
330317
end
331318

locales/en.yml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
en:
2+
captions:
3+
terminal: "Type this in the terminal:"
4+
irb: "Type this in irb:"
5+
result: "Expected result:"
6+
fuzzy_result: "Approximate expected result:"
7+
link: "Go on to"
8+
9+
general:
10+
type_in_file: "Type this in the file %{filename}:"
11+
further_reading: "Further Reading"
12+
fuzzy_hint: "The greyed-out text may differ and is not important."
13+
step_title: "Step %{num}"
14+
step_title_suffix: ": "
15+
next_step: "Next Step:"
16+
option: "Option %{num}: "
17+
verify: "Verify %{text}"
18+
goals: "Goals"
19+
expand_all: "Expand All"
20+
other_pages: "Other Pages"
21+
back_to: "Back to"
22+
23+
header_section:
24+
steps: "Steps"
25+
explanation: "Explanation"
26+
overview: "Overview"
27+
discussion: "Discussion Items"
28+
hints: "Hints"
29+
challenge: "Challenge(s)"
30+
tools_and_references: "Tools and References"
31+
requirements: "Requirements to advance"

0 commit comments

Comments
 (0)