# Redmine - project management software
# Copyright (C) 2006-2015  Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

module Redmine
  module I18n
    def self.included(base)
      base.extend Redmine::I18n
    end

    def l(*args)
      case args.size
      when 1
        ::I18n.t(*args)
      when 2
        if args.last.is_a?(Hash)
          ::I18n.t(*args)
        elsif args.last.is_a?(String)
          ::I18n.t(args.first, :value => args.last)
        else
          ::I18n.t(args.first, :count => args.last)
        end
      else
        raise "Translation string with multiple values: #{args.first}"
      end
    end

    def l_or_humanize(s, options={})
      k = "#{options[:prefix]}#{s}".to_sym
      ::I18n.t(k, :default => s.to_s.humanize)
    end

    def l_hours(hours)
      hours = hours.to_f
      l((hours < 2.0 ? :label_f_hour : :label_f_hour_plural), :value => ("%.2f" % hours.to_f))
    end

    def ll(lang, str, value=nil)
      ::I18n.t(str.to_s, :value => value, :locale => lang.to_s.gsub(%r{(.+)\-(.+)$}) { "#{$1}-#{$2.upcase}" })
    end

    def format_date(date)
      return nil unless date
      options = {}
      options[:format] = Setting.date_format unless Setting.date_format.blank?
      ::I18n.l(date.to_date, options)
    end

    def format_time(time, include_date = true)
      return nil unless time
      options = {}
      options[:format] = (Setting.time_format.blank? ? :time : Setting.time_format)
      time = time.to_time if time.is_a?(String)
      zone = User.current.time_zone
      local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time)
      (include_date ? "#{format_date(local)} " : "") + ::I18n.l(local, options)
    end

    def day_name(day)
      ::I18n.t('date.day_names')[day % 7]
    end

    def day_letter(day)
      ::I18n.t('date.abbr_day_names')[day % 7].first
    end

    def month_name(month)
      ::I18n.t('date.month_names')[month]
    end

    def valid_languages
      ::I18n.available_locales
    end

    # Returns an array of languages names and code sorted by names, example:
    # [["Deutsch", "de"], ["English", "en"] ...]
    #
    # The result is cached to prevent from loading all translations files
    # unless :cache => false option is given
    def languages_options(options={})
      options = if options[:cache] == false
        valid_languages.
          select {|locale| ::I18n.exists?(:general_lang_name, locale)}.
          map {|lang| [ll(lang.to_s, :general_lang_name), lang.to_s]}.
          sort {|x,y| x.first <=> y.first }
      else
        ActionController::Base.cache_store.fetch "i18n/languages_options/#{Redmine::VERSION}" do
          languages_options :cache => false
        end
      end
      options.map {|name, lang| [name.force_encoding("UTF-8"), lang.force_encoding("UTF-8")]}
    end

    def find_language(lang)
      @@languages_lookup = valid_languages.inject({}) {|k, v| k[v.to_s.downcase] = v; k }
      @@languages_lookup[lang.to_s.downcase]
    end

    def set_language_if_valid(lang)
      if l = find_language(lang)
        ::I18n.locale = l
      end
    end

    def current_language
      ::I18n.locale
    end

    # Custom backend based on I18n::Backend::Simple with the following changes:
    # * lazy loading of translation files
    # * available_locales are determined by looking at translation file names
    class Backend
      (class << self; self; end).class_eval { public :include }

      module Implementation
        include ::I18n::Backend::Base

        # Stores translations for the given locale in memory.
        # This uses a deep merge for the translations hash, so existing
        # translations will be overwritten by new ones only at the deepest
        # level of the hash.
        def store_translations(locale, data, options = {})
          locale = locale.to_sym
          translations[locale] ||= {}
          data = data.deep_symbolize_keys
          translations[locale].deep_merge!(data)
        end

        # Get available locales from the translations filenames
        def available_locales
          @available_locales ||= ::I18n.load_path.map {|path| File.basename(path, '.*')}.uniq.sort.map(&:to_sym)
        end

        # Clean up translations
        def reload!
          @translations = nil
          @available_locales = nil
          super
        end

        protected

        def init_translations(locale)
          locale = locale.to_s
          paths = ::I18n.load_path.select {|path| File.basename(path, '.*') == locale}
          load_translations(paths)
          translations[locale] ||= {}
        end

        def translations
          @translations ||= {}
        end

        # Looks up a translation from the translations hash. Returns nil if
        # eiher key is nil, or locale, scope or key do not exist as a key in the
        # nested translations hash. Splits keys or scopes containing dots
        # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
        # <tt>%w(currency format)</tt>.
        def lookup(locale, key, scope = [], options = {})
          init_translations(locale) unless translations.key?(locale)
          keys = ::I18n.normalize_keys(locale, key, scope, options[:separator])

          keys.inject(translations) do |result, _key|
            _key = _key.to_sym
            return nil unless result.is_a?(Hash) && result.has_key?(_key)
            result = result[_key]
            result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
            result
          end
        end
      end

      include Implementation
      # Adds fallback to default locale for untranslated strings
      include ::I18n::Backend::Fallbacks
    end
  end
end
w.asciidoc?h=8.1.1'>log</a><a class='active' href='/vaadin-framework.git/tree/documentation/introduction/intro-overview.asciidoc?h=8.1.1'>tree</a><a href='/vaadin-framework.git/commit/documentation/introduction/intro-overview.asciidoc?h=8.1.1'>commit</a><a href='/vaadin-framework.git/diff/documentation/introduction/intro-overview.asciidoc?h=8.1.1'>diff</a><a href='/vaadin-framework.git/stats/documentation/introduction/intro-overview.asciidoc?h=8.1.1'>stats</a></td><td class='form'><form class='right' method='get' action='/vaadin-framework.git/log/documentation/introduction/intro-overview.asciidoc'>
<input type='hidden' name='h' value='8.1.1'/><select name='qt'>
<option value='grep'>log msg</option>
<option value='author'>author</option>
<option value='committer'>committer</option>
<option value='range'>range</option>
</select>
<input class='txt' type='search' size='10' name='q' value=''/>
<input type='submit' value='search'/>
</form>
</td></tr></table>
<div class='path'>path: <a href='/vaadin-framework.git/tree/?h=8.1.1'>root</a>/<a href='/vaadin-framework.git/tree/documentation?h=8.1.1'>documentation</a>/<a href='/vaadin-framework.git/tree/documentation/introduction?h=8.1.1'>introduction</a>/<a href='/vaadin-framework.git/tree/documentation/introduction/intro-overview.asciidoc?h=8.1.1'>intro-overview.asciidoc</a></div><div class='content'>blob: beed28ac6f47da26922757c97429d8ff7b80a20b (<a href='/vaadin-framework.git/plain/documentation/introduction/intro-overview.asciidoc?h=8.1.1'>plain</a>)
<table summary='blob content' class='blob'>
<tr><td class='linenumbers'><pre><a id='n1' href='#n1'>1</a>
<a id='n2' href='#n2'>2</a>
<a id='n3' href='#n3'>3</a>
<a id='n4' href='#n4'>4</a>
<a id='n5' href='#n5'>5</a>
<a id='n6' href='#n6'>6</a>
<a id='n7' href='#n7'>7</a>
<a id='n8' href='#n8'>8</a>
<a id='n9' href='#n9'>9</a>
<a id='n10' href='#n10'>10</a>
<a id='n11' href='#n11'>11</a>
<a id='n12' href='#n12'>12</a>
<a id='n13' href='#n13'>13</a>
<a id='n14' href='#n14'>14</a>
<a id='n15' href='#n15'>15</a>
<a id='n16' href='#n16'>16</a>
<a id='n17' href='#n17'>17</a>
<a id='n18' href='#n18'>18</a>
<a id='n19' href='#n19'>19</a>
<a id='n20' href='#n20'>20</a>
<a id='n21' href='#n21'>21</a>
<a id='n22' href='#n22'>22</a>
<a id='n23' href='#n23'>23</a>
<a id='n24' href='#n24'>24</a>
<a id='n25' href='#n25'>25</a>
<a id='n26' href='#n26'>26</a>
<a id='n27' href='#n27'>27</a>
<a id='n28' href='#n28'>28</a>
<a id='n29' href='#n29'>29</a>
<a id='n30' href='#n30'>30</a>
<a id='n31' href='#n31'>31</a>
<a id='n32' href='#n32'>32</a>
<a id='n33' href='#n33'>33</a>
<a id='n34' href='#n34'>34</a>
<a id='n35' href='#n35'>35</a>
<a id='n36' href='#n36'>36</a>
<a id='n37' href='#n37'>37</a>
<a id='n38' href='#n38'>38</a>
<a id='n39' href='#n39'>39</a>
<a id='n40' href='#n40'>40</a>
<a id='n41' href='#n41'>41</a>
<a id='n42' href='#n42'>42</a>
<a id='n43' href='#n43'>43</a>
<a id='n44' href='#n44'>44</a>
<a id='n45' href='#n45'>45</a>
<a id='n46' href='#n46'>46</a>
<a id='n47' href='#n47'>47</a>
<a id='n48' href='#n48'>48</a>
<a id='n49' href='#n49'>49</a>
<a id='n50' href='#n50'>50</a>
<a id='n51' href='#n51'>51</a>
<a id='n52' href='#n52'>52</a>
<a id='n53' href='#n53'>53</a>
<a id='n54' href='#n54'>54</a>
<a id='n55' href='#n55'>55</a>
<a id='n56' href='#n56'>56</a>
<a id='n57' href='#n57'>57</a>
<a id='n58' href='#n58'>58</a>
<a id='n59' href='#n59'>59</a>
<a id='n60' href='#n60'>60</a>
<a id='n61' href='#n61'>61</a>
<a id='n62' href='#n62'>62</a>
<a id='n63' href='#n63'>63</a>
<a id='n64' href='#n64'>64</a>
<a id='n65' href='#n65'>65</a>
<a id='n66' href='#n66'>66</a>
<a id='n67' href='#n67'>67</a>
<a id='n68' href='#n68'>68</a>
<a id='n69' href='#n69'>69</a>
<a id='n70' href='#n70'>70</a>
<a id='n71' href='#n71'>71</a>
<a id='n72' href='#n72'>72</a>
<a id='n73' href='#n73'>73</a>
<a id='n74' href='#n74'>74</a>
<a id='n75' href='#n75'>75</a>
<a id='n76' href='#n76'>76</a>
<a id='n77' href='#n77'>77</a>
<a id='n78' href='#n78'>78</a>
<a id='n79' href='#n79'>79</a>
<a id='n80' href='#n80'>80</a>
<a id='n81' href='#n81'>81</a>
<a id='n82' href='#n82'>82</a>
<a id='n83' href='#n83'>83</a>
<a id='n84' href='#n84'>84</a>
<a id='n85' href='#n85'>85</a>
<a id='n86' href='#n86'>86</a>
</pre></td>
<td class='lines'><pre><code><style>pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */</style><div class="highlight"><pre><span></span>---
title: Overview
order: 1
layout: page
---

[[intro.overview]]
= Overview

Vaadin Framework is a Java web application development framework that is
designed to make creation and maintenance of high quality web-based user
interfaces easy. Vaadin supports two different programming models: server-side
and client-side. The server-driven programming model is the more powerful one.
It lets you forget the web and program user interfaces much like you would
program a desktop application with conventional Java toolkits such as AWT,
Swing, or SWT. But easier.

While traditional web programming is a fun way to spend your time learning new
web technologies, you probably want to be productive and concentrate on the
application logic. The server-side Vaadin framework takes care of managing the
user interface in the browser and the __AJAX__ communications between the
browser and the server. With the Vaadin approach, you do not need to learn and
deal directly with browser technologies, such as HTML or JavaScript.

[[figure.intro.architecture]]
.Vaadin application architecture
image::img/architecture.png[width=100%, scaledwidth=100%]

&lt;&lt;figure.intro.architecture&gt;&gt; illustrates the basic architectures of web
applications made with Vaadin. The server-side application architecture consists
of the __server-side framework__ and a __client-side engine__. The engine runs
in the browser as JavaScript code, rendering the user interface, and delivering
user interaction to the server. The UI logic of an application runs as a Java
Servlet in a Java application server.

As the client-side engine is executed as JavaScript in the browser, no browser
plugins are needed for using applications made with Vaadin. This gives it an
edge over frameworks based on Flash, Java Applets, or other plugins. Vaadin
relies on the support of Google Web Toolkit for a wide range of browsers, so
that the developer does not need to worry about browser support.

Because HTML, JavaScript, and other browser technologies are essentially
invisible to the application logic, you can think of the web browser as only a
thin client platform. A thin client displays the user interface and communicates
user events to the server at a low level. The control logic of the user
interface runs on a Java-based web server, together with your business logic. By
contrast, a normal client-server architecture with a dedicated client
application would include a lot of application specific communications between
the client and the server. Essentially removing the user interface tier from the
application architecture makes our approach a very effective one.

Behind the server-driven development model, Vaadin makes the best use of AJAX (
__Asynchronous JavaScript and XML__, see
&lt;&lt;dummy/../../../framework/architecture/architecture-technology#architecture.technology.ajax,&quot;AJAX&quot;&gt;&gt;
for a description) techniques that make it possible to create Rich Internet
Applications (RIA) that are as responsive and interactive as desktop
applications.

In addition to the server-side Java application development, you can develop on
the client-side by making new widgets in Java, and even pure client-side
applications that run solely in the browser. The Vaadin client-side framework
includes Google Web Toolkit (GWT), which provides a compiler from Java to the
JavaScript that runs in the browser, as well a full-featured user interface
framework. With this approach, Vaadin is pure Java on both sides. (((&quot;Google Web
Toolkit&quot;)))

Vaadin uses a client-side engine for rendering the user interface of a
server-side application in the browser. All the client-server communications are
hidden well under the hood.
(((&quot;JavaScript&quot;)))
Vaadin is designed to be extensible, and you can indeed use any 3rd-party
widgets easily, in addition to the component repertoire offered in Vaadin. In
fact, you can find hundreds of add-ons in the Vaadin Directory.

Vaadin allows flexible separation between the appearance, structure, and
interaction logic of the user interface. You can design the layouts either
programmatically or declaratively, at the level of your choosing. The final
appearance is defined in __themes__ in CSS or Sass, as described in
&lt;&lt;dummy/../../../framework/themes/themes-overview.asciidoc#themes.overview,&quot;Themes&quot;&gt;&gt;.

We hope that this is enough about the basic architecture and features of Vaadin
for now. You can read more about it later in
&lt;&lt;dummy/../../../framework/architecture/architecture-overview.asciidoc#architecture.overview,&quot;Architecture&quot;&gt;&gt;,
or jump straight to more practical things in
&lt;&lt;dummy/../../../framework/application/application-overview.asciidoc#application.overview,&quot;Writing
a Server-Side Web Application&quot;&gt;&gt;.
</pre></div>
</code></pre></td></tr></table>
</div> <!-- class=content -->
<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.3</a> (<a href='https://git-scm.com/'>git 2.39.1</a>) at 2025-07-27 05:15:09 +0000</div>
</div> <!-- id=cgit -->
</body>
</html>
