mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 21:21:19 +08:00
FEATURE: Support for localized themes (#6848)
- Themes can supply translation files in a format like `/locales/{locale}.yml`. These files should be valid YAML, with a single top level key equal to the locale being defined. For now these can only be defined using the `discourse_theme` CLI, importing a `.tar.gz`, or from a GIT repository. - Fallback is handled on a global level (if the locale is not defined in the theme), as well as on individual keys (if some keys are missing from the selected interface language). - Administrators can override individual keys on a per-theme basis in the /admin/customize/themes user interface. - Theme developers should access defined translations using the new theme prefix variables: JavaScript: `I18n.t(themePrefix("my_translation_key"))` Handlebars: `{{theme-i18n "my_translation_key"}}` or `{{i18n (theme-prefix "my_translation_key")}}` - To design for backwards compatibility, theme developers can check for the presence of the `themePrefix` variable in JavaScript - As part of this, the old `{{themeSetting.setting_name}}` syntax is deprecated in favour of `{{theme-setting "setting_name"}}`
This commit is contained in:
102
spec/lib/theme_javascript_compiler_spec.rb
Normal file
102
spec/lib/theme_javascript_compiler_spec.rb
Normal file
@ -0,0 +1,102 @@
|
||||
require 'rails_helper'
|
||||
|
||||
require_dependency 'theme_javascript_compiler'
|
||||
|
||||
describe ThemeJavascriptCompiler do
|
||||
|
||||
let(:theme_id) { 22 }
|
||||
|
||||
describe ThemeJavascriptCompiler::RawTemplatePrecompiler do
|
||||
# For the raw templates, we can easily render them serverside, so let's do that
|
||||
|
||||
let(:compiler) { described_class.new(theme_id) }
|
||||
|
||||
let(:helpers) {
|
||||
<<~JS
|
||||
Handlebars.registerHelper('theme-prefix', function(themeId, string) {
|
||||
return `theme_translations.${themeId}.${string}`
|
||||
})
|
||||
Handlebars.registerHelper('theme-i18n', function(themeId, string) {
|
||||
return `translated(theme_translations.${themeId}.${string})`
|
||||
})
|
||||
Handlebars.registerHelper('theme-setting', function(themeId, string) {
|
||||
return `setting(${themeId}:${string})`
|
||||
})
|
||||
Handlebars.registerHelper('dummy-helper', function(string) {
|
||||
return `dummy(${string})`
|
||||
})
|
||||
JS
|
||||
}
|
||||
|
||||
let(:mini_racer) {
|
||||
ctx = MiniRacer::Context.new
|
||||
ctx.eval(File.open("#{Rails.root}/vendor/assets/javascripts/handlebars.js").read)
|
||||
ctx.eval(helpers)
|
||||
ctx
|
||||
}
|
||||
|
||||
def render(template)
|
||||
compiled = compiler.compile(template)
|
||||
mini_racer.eval "Handlebars.template(#{compiled.squish})({})"
|
||||
end
|
||||
|
||||
it 'adds the theme id to the helpers' do
|
||||
# Works normally
|
||||
expect(render("{{theme-prefix 'translation_key'}}")).
|
||||
to eq('theme_translations.22.translation_key')
|
||||
expect(render("{{theme-i18n 'translation_key'}}")).
|
||||
to eq('translated(theme_translations.22.translation_key)')
|
||||
expect(render("{{theme-setting 'setting_key'}}")).
|
||||
to eq('setting(22:setting_key)')
|
||||
|
||||
# Works when used inside other statements
|
||||
expect(render("{{dummy-helper (theme-prefix 'translation_key')}}")).
|
||||
to eq('dummy(theme_translations.22.translation_key)')
|
||||
end
|
||||
|
||||
it 'works with the old settings syntax' do
|
||||
expect(render("{{themeSetting.setting_key}}")).
|
||||
to eq('setting(22:setting_key)')
|
||||
|
||||
# Works when used inside other statements
|
||||
expect(render("{{dummy-helper themeSetting.setting_key}}")).
|
||||
to eq('dummy(setting(22:setting_key))')
|
||||
end
|
||||
end
|
||||
|
||||
describe ThemeJavascriptCompiler::EmberTemplatePrecompiler do
|
||||
# For the Ember (Glimmer) templates, serverside rendering is not trivial,
|
||||
# so check the compiled JSON against known working output
|
||||
let(:compiler) { described_class.new(theme_id) }
|
||||
|
||||
def statement(template)
|
||||
compiled = compiler.compile(template)
|
||||
data = JSON.parse(compiled)
|
||||
block = JSON.parse(data["block"])
|
||||
block["statements"]
|
||||
end
|
||||
|
||||
it 'adds the theme id to the helpers' do
|
||||
expect(statement("{{theme-prefix 'translation_key'}}")).
|
||||
to eq([[1, [27, "theme-prefix", [22, "translation_key"], nil], false]])
|
||||
expect(statement("{{theme-i18n 'translation_key'}}")).
|
||||
to eq([[1, [27, "theme-i18n", [22, "translation_key"], nil], false]])
|
||||
expect(statement("{{theme-setting 'setting_key'}}")).
|
||||
to eq([[1, [27, "theme-setting", [22, "setting_key"], nil], false]])
|
||||
|
||||
# Works when used inside other statements
|
||||
expect(statement("{{dummy-helper (theme-prefix 'translation_key')}}")).
|
||||
to eq([[1, [27, "dummy-helper", [[27, "theme-prefix", [22, "translation_key"], nil]], nil], false]])
|
||||
end
|
||||
|
||||
it 'works with the old settings syntax' do
|
||||
expect(statement("{{themeSetting.setting_key}}")).
|
||||
to eq([[1, [27, "theme-setting", [22, "setting_key"], [["deprecated"], [true]]], false]])
|
||||
|
||||
# Works when used inside other statements
|
||||
expect(statement("{{dummy-helper themeSetting.setting_key}}")).
|
||||
to eq([[1, [27, "dummy-helper", [[27, "theme-setting", [22, "setting_key"], [["deprecated"], [true]]]], nil], false]])
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Reference in New Issue
Block a user