Page MenuHomePhorge

D168.1775811387.diff
No OneTemporary

Authored By
Unknown
Size
18 KB
Referenced Files
None
Subscribers
None

D168.1775811387.diff

diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,18 @@
## Development
-$ cd larus
-$ mix deps.get
-$ mix phoenix.server
+ $ cd larus
+ $ mix deps.get
+ $ npm install
+ $ mix phoenix.server
+
+## l10n
+
+Add supported locales to `larus/config/config.exs`.
+
+Extract strings:
+
+ $ mix gettext.extract
+
+Merge in new translated strings:
+
+ $ mix gettext.merge priv/gettext/ --locale de
diff --git a/larus/config/config.exs b/larus/config/config.exs
--- a/larus/config/config.exs
+++ b/larus/config/config.exs
@@ -14,6 +14,9 @@
pubsub: [name: Larus.PubSub,
adapter: Phoenix.PubSub.PG2]
+config :larus, Larus.Gettext,
+ locales: ~w(en de nl)
+
# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
diff --git a/larus/lib/blank.ex b/larus/lib/blank.ex
new file mode 100644
--- /dev/null
+++ b/larus/lib/blank.ex
@@ -0,0 +1,67 @@
+defmodule Blank do
+ @moduledoc """
+ Tools around checking and handling undefined or blank data.
+ """
+
+ @doc """
+ Returns `true` if data is considered blank/empty.
+ """
+ def blank?(data) do
+ Blank.Protocol.blank?(data)
+ end
+
+ @doc """
+ Returns `true` if data is not considered blank/empty.
+ """
+ def present?(data) do
+ !blank?(data)
+ end
+
+ @doc """
+ Returns the provided `data` if valid of the `default` value if not.
+ """
+ def default_to(data, default) do
+ if blank?(data), do: default, else: data
+ end
+end
+
+defprotocol Blank.Protocol do
+ @moduledoc """
+ Provides only one single method definition `blank?/1`
+ """
+
+ @doc """
+ Returns `true` if data is considered blank/empty.
+ """
+ def blank?(data)
+end
+
+# Integers are never blank
+defimpl Blank.Protocol, for: Integer do
+ def blank?(_), do: false
+end
+
+defimpl Blank.Protocol, for: BitString do
+ def blank?(""), do: true
+ def blank?(_), do: false
+end
+
+# Just empty list is blank
+defimpl Blank.Protocol, for: List do
+ def blank?([]), do: true
+ def blank?(_), do: false
+end
+
+defimpl Blank.Protocol, for: Map do
+ # Keep in mind we could not pattern match on %{} because
+ # it matches on all maps. We can however check if the size
+ # is zero (and size is a fast operation).
+ def blank?(map), do: map_size(map) == 0
+end
+
+# Just the atoms false and nil are blank
+defimpl Blank.Protocol, for: Atom do
+ def blank?(false), do: true
+ def blank?(nil), do: true
+ def blank?(_), do: false
+end
\ No newline at end of file
diff --git a/larus/lib/larus/plug/locale.ex b/larus/lib/larus/plug/locale.ex
new file mode 100644
--- /dev/null
+++ b/larus/lib/larus/plug/locale.ex
@@ -0,0 +1,64 @@
+defmodule Larus.Plug.Locale do
+ require Logger
+
+ import Plug.Conn
+
+ def init(default) do
+ default
+ end
+
+ def call(conn, default) do
+ locale = conn.params["locale"]
+
+ if locale in Larus.Gettext.supported_locales do
+ conn |> assign_locale! locale
+ else
+ locale = List.first(extract_locale(conn)) || default
+
+ conn |> assign_locale! locale
+ end
+ end
+
+ defp assign_locale!(conn, value) do
+ Logger.debug "Assigning locale #{inspect value}"
+ Gettext.put_locale(Larus.Gettext, value)
+ conn
+ |> assign(:locale, value)
+ end
+
+ defp extract_locale(conn) do
+ if Blank.present? conn.params["locale"] do
+ [conn.params["locale"] | extract_accept_language(conn)]
+ else
+ extract_accept_language(conn)
+ end
+ # Filter for only known locales
+ |> Enum.filter(fn locale -> Enum.member?(Larus.Gettext.supported_locales, locale) end)
+ end
+
+ defp extract_accept_language(conn) do
+ case conn |> get_req_header("accept-language") do
+ [value|_] ->
+ value
+ |> String.split(",")
+ |> Enum.map(&parse_language_option/1)
+ |> Enum.sort(&(&1.quality > &2.quality))
+ |> Enum.map(&(&1.tag))
+ _ ->
+ []
+ end
+ end
+
+ defp parse_language_option(string) do
+ captures = ~r/^(?<tag>[\w\-]+)(?:;q=(?<quality>[\d\.]+))?$/i
+ |> Regex.named_captures(string)
+
+ quality = case Float.parse(captures["quality"] || "1.0") do
+ {val, _} -> val
+ _ -> 1.0
+ end
+
+ %{tag: captures["tag"], quality: quality}
+ end
+
+end
diff --git a/larus/priv/gettext/de/LC_MESSAGES/default.po b/larus/priv/gettext/de/LC_MESSAGES/default.po
new file mode 100644
--- /dev/null
+++ b/larus/priv/gettext/de/LC_MESSAGES/default.po
@@ -0,0 +1,23 @@
+## `msgid`s in this file come from POT (.pot) files.
+##
+## Do not add, change, or remove `msgid`s manually here as
+## they're tied to the ones in the corresponding POT file
+## (with the same domain).
+##
+## Use `mix gettext.extract --merge` or `mix gettext.merge`
+## to merge POT files into PO files.
+msgid ""
+msgstr ""
+"Language: de\n"
+
+#: web/templates/page/index.html.eex:2
+msgid "Welcome to %{name}"
+msgstr ""
+
+#: web/views/layout_view.ex:9
+msgid "Larus flying high."
+msgstr ""
+
+#: web/views/layout_view.ex:13
+msgid "[YOUR TITLE HERE]"
+msgstr ""
diff --git a/larus/priv/gettext/errors.pot b/larus/priv/gettext/de/LC_MESSAGES/errors.po
copy from larus/priv/gettext/errors.pot
copy to larus/priv/gettext/de/LC_MESSAGES/errors.po
--- a/larus/priv/gettext/errors.pot
+++ b/larus/priv/gettext/de/LC_MESSAGES/errors.po
@@ -1,45 +1,42 @@
-## This file is a PO Template file. `msgid`s here are often extracted from
-## source code; add new translations manually only if they're dynamic
-## translations that can't be statically extracted. Run `mix
-## gettext.extract` to bring this file up to date. Leave `msgstr`s empty as
-## changing them here as no effect; edit them in PO (`.po`) files instead.
+## `msgid`s in this file come from POT (.pot) files.
+##
+## Do not add, change, or remove `msgid`s manually here as
+## they're tied to the ones in the corresponding POT file
+## (with the same domain).
+##
+## Use `mix gettext.extract --merge` or `mix gettext.merge`
+## to merge POT files into PO files.
+msgid ""
+msgstr ""
+"Language: de\n"
-## From Ecto.Changeset.cast/4
msgid "can't be blank"
msgstr ""
-## From Ecto.Changeset.unique_constraint/3
msgid "has already been taken"
msgstr ""
-## From Ecto.Changeset.put_change/3
msgid "is invalid"
msgstr ""
-## From Ecto.Changeset.validate_format/3
msgid "has invalid format"
msgstr ""
-## From Ecto.Changeset.validate_subset/3
msgid "has an invalid entry"
msgstr ""
-## From Ecto.Changeset.validate_exclusion/3
msgid "is reserved"
msgstr ""
-## From Ecto.Changeset.validate_confirmation/3
msgid "does not match confirmation"
msgstr ""
-## From Ecto.Changeset.no_assoc_constraint/3
msgid "is still associated to this entry"
msgstr ""
msgid "are still associated to this entry"
msgstr ""
-## From Ecto.Changeset.validate_length/3
msgid "should be %{count} character(s)"
msgid_plural "should be %{count} character(s)"
msgstr[0] ""
@@ -70,7 +67,6 @@
msgstr[0] ""
msgstr[1] ""
-## From Ecto.Changeset.validate_number/3
msgid "must be less than %{count}"
msgid_plural "must be less than %{count}"
msgstr[0] ""
diff --git a/larus/priv/gettext/default.pot b/larus/priv/gettext/default.pot
new file mode 100644
--- /dev/null
+++ b/larus/priv/gettext/default.pot
@@ -0,0 +1,24 @@
+## This file is a PO Template file.
+##
+## `msgid`s here are often extracted from source code.
+## Add new translations manually only if they're dynamic
+## translations that can't be statically extracted.
+##
+## Run `mix gettext.extract` to bring this file up to
+## date. Leave `msgstr`s empty as changing them here as no
+## effect: edit them in PO (`.po`) files instead.
+msgid ""
+msgstr ""
+"Language: INSERT LANGUAGE HERE\n"
+
+#: web/templates/page/index.html.eex:2
+msgid "Welcome to %{name}"
+msgstr ""
+
+#: web/views/layout_view.ex:9
+msgid "Larus flying high."
+msgstr ""
+
+#: web/views/layout_view.ex:13
+msgid "[YOUR TITLE HERE]"
+msgstr ""
diff --git a/larus/priv/gettext/en/LC_MESSAGES/default.po b/larus/priv/gettext/en/LC_MESSAGES/default.po
new file mode 100644
--- /dev/null
+++ b/larus/priv/gettext/en/LC_MESSAGES/default.po
@@ -0,0 +1,23 @@
+## `msgid`s in this file come from POT (.pot) files.
+##
+## Do not add, change, or remove `msgid`s manually here as
+## they're tied to the ones in the corresponding POT file
+## (with the same domain).
+##
+## Use `mix gettext.extract --merge` or `mix gettext.merge`
+## to merge POT files into PO files.
+msgid ""
+msgstr ""
+"Language: en\n"
+
+#: web/templates/page/index.html.eex:2
+msgid "Welcome to %{name}"
+msgstr ""
+
+#: web/views/layout_view.ex:9
+msgid "Larus flying high."
+msgstr ""
+
+#: web/views/layout_view.ex:13
+msgid "[YOUR TITLE HERE]"
+msgstr ""
diff --git a/larus/priv/gettext/errors.pot b/larus/priv/gettext/errors.pot
--- a/larus/priv/gettext/errors.pot
+++ b/larus/priv/gettext/errors.pot
@@ -3,7 +3,6 @@
## translations that can't be statically extracted. Run `mix
## gettext.extract` to bring this file up to date. Leave `msgstr`s empty as
## changing them here as no effect; edit them in PO (`.po`) files instead.
-
## From Ecto.Changeset.cast/4
msgid "can't be blank"
msgstr ""
diff --git a/larus/priv/gettext/nl/LC_MESSAGES/default.po b/larus/priv/gettext/nl/LC_MESSAGES/default.po
new file mode 100644
--- /dev/null
+++ b/larus/priv/gettext/nl/LC_MESSAGES/default.po
@@ -0,0 +1,23 @@
+## `msgid`s in this file come from POT (.pot) files.
+##
+## Do not add, change, or remove `msgid`s manually here as
+## they're tied to the ones in the corresponding POT file
+## (with the same domain).
+##
+## Use `mix gettext.extract --merge` or `mix gettext.merge`
+## to merge POT files into PO files.
+msgid ""
+msgstr ""
+"Language: nl\n"
+
+#: web/templates/page/index.html.eex:2
+msgid "Welcome to %{name}"
+msgstr ""
+
+#: web/views/layout_view.ex:9
+msgid "Larus flying high."
+msgstr ""
+
+#: web/views/layout_view.ex:13
+msgid "[YOUR TITLE HERE]"
+msgstr "[UW TITEL HIER]"
diff --git a/larus/priv/gettext/errors.pot b/larus/priv/gettext/nl/LC_MESSAGES/errors.po
copy from larus/priv/gettext/errors.pot
copy to larus/priv/gettext/nl/LC_MESSAGES/errors.po
--- a/larus/priv/gettext/errors.pot
+++ b/larus/priv/gettext/nl/LC_MESSAGES/errors.po
@@ -1,45 +1,42 @@
-## This file is a PO Template file. `msgid`s here are often extracted from
-## source code; add new translations manually only if they're dynamic
-## translations that can't be statically extracted. Run `mix
-## gettext.extract` to bring this file up to date. Leave `msgstr`s empty as
-## changing them here as no effect; edit them in PO (`.po`) files instead.
+## `msgid`s in this file come from POT (.pot) files.
+##
+## Do not add, change, or remove `msgid`s manually here as
+## they're tied to the ones in the corresponding POT file
+## (with the same domain).
+##
+## Use `mix gettext.extract --merge` or `mix gettext.merge`
+## to merge POT files into PO files.
+msgid ""
+msgstr ""
+"Language: nl\n"
-## From Ecto.Changeset.cast/4
msgid "can't be blank"
msgstr ""
-## From Ecto.Changeset.unique_constraint/3
msgid "has already been taken"
msgstr ""
-## From Ecto.Changeset.put_change/3
msgid "is invalid"
msgstr ""
-## From Ecto.Changeset.validate_format/3
msgid "has invalid format"
msgstr ""
-## From Ecto.Changeset.validate_subset/3
msgid "has an invalid entry"
msgstr ""
-## From Ecto.Changeset.validate_exclusion/3
msgid "is reserved"
msgstr ""
-## From Ecto.Changeset.validate_confirmation/3
msgid "does not match confirmation"
msgstr ""
-## From Ecto.Changeset.no_assoc_constraint/3
msgid "is still associated to this entry"
msgstr ""
msgid "are still associated to this entry"
msgstr ""
-## From Ecto.Changeset.validate_length/3
msgid "should be %{count} character(s)"
msgid_plural "should be %{count} character(s)"
msgstr[0] ""
@@ -70,7 +67,6 @@
msgstr[0] ""
msgstr[1] ""
-## From Ecto.Changeset.validate_number/3
msgid "must be less than %{count}"
msgid_plural "must be less than %{count}"
msgstr[0] ""
diff --git a/larus/web/controllers/page_controller.ex b/larus/web/controllers/page_controller.ex
--- a/larus/web/controllers/page_controller.ex
+++ b/larus/web/controllers/page_controller.ex
@@ -1,7 +1,7 @@
defmodule Larus.PageController do
- use Larus.Web, :controller
+ use Larus.Web, :controller
- def index(conn, _params) do
- render conn, "index.html"
- end
+ def index(conn, _params) do
+ render conn, "index.html"
+ end
end
diff --git a/larus/web/gettext.ex b/larus/web/gettext.ex
--- a/larus/web/gettext.ex
+++ b/larus/web/gettext.ex
@@ -1,24 +1,36 @@
defmodule Larus.Gettext do
- @moduledoc """
- A module providing Internationalization with a gettext-based API.
+ @moduledoc """
+ A module providing Internationalization with a gettext-based API.
- By using [Gettext](http://hexdocs.pm/gettext),
- your module gains a set of macros for translations, for example:
+ By using [Gettext](http://hexdocs.pm/gettext),
+ your module gains a set of macros for translations, for example:
- import Larus.Gettext
+ import Larus.Gettext
- # Simple translation
- gettext "Here is the string to translate"
+ # Simple translation
+ gettext "Here is the string to translate"
- # Plural translation
- ngettext "Here is the string to translate",
- "Here are the strings to translate",
- 3
+ # Plural translation
+ ngettext "Here is the string to translate",
+ "Here are the strings to translate",
+ 3
- # Domain-based translation
- dgettext "errors", "Here is the error message to translate"
+ # Domain-based translation
+ dgettext "errors", "Here is the error message to translate"
- See the [Gettext Docs](http://hexdocs.pm/gettext) for detailed usage.
- """
- use Gettext, otp_app: :larus
+ See the [Gettext Docs](http://hexdocs.pm/gettext) for detailed usage.
+ """
+ use Gettext, otp_app: :larus
+
+ def supported_locales do
+ known = Gettext.known_locales(Larus.Gettext)
+ allowed = config[:locales]
+
+ Set.intersection(Enum.into(known, HashSet.new), Enum.into(allowed, HashSet.new))
+ |> Set.to_list
+ end
+
+ defp config do
+ Application.get_env(:larus, __MODULE__)
+ end
end
diff --git a/larus/web/router.ex b/larus/web/router.ex
--- a/larus/web/router.ex
+++ b/larus/web/router.ex
@@ -7,6 +7,7 @@
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
+ plug Larus.Plug.Locale, "en"
end
pipeline :api do
diff --git a/larus/web/templates/layout/app.html.eex b/larus/web/templates/layout/app.html.eex
--- a/larus/web/templates/layout/app.html.eex
+++ b/larus/web/templates/layout/app.html.eex
@@ -1,35 +1,22 @@
<!DOCTYPE html>
-<html lang="en">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <meta name="description" content="">
- <meta name="author" content="">
+<!--[if lt IE 9]> <html class="lt-ie9"> <![endif]-->
+<!--[if gt IE 8]><!--> <html lang="<%= assigns[:locale] %>"> <!--<![endif]-->
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="description" content="<%= description %>">
+ <meta name="author" content="<%= author %>">
+ <title><%= title %></title>
+ </head>
- <title>Hello Larus!</title>
- <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
- </head>
+ <body>
+ <div id="space">
+ <%= render @view_module, @view_template, assigns %>
+ </div>
- <body>
- <div class="container">
- <header class="header">
- <nav role="navigation">
- <ul class="nav nav-pills pull-right">
- <li><a href="http://www.phoenixframework.org/docs">Get Started</a></li>
- </ul>
- </nav>
- <span class="logo"></span>
- </header>
-
- <p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
- <p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
-
- <main role="main">
- <%= render @view_module, @view_template, assigns %>
- </main>
-
- </div> <!-- /container -->
- <script src="<%= static_path(@conn, "/js/app.js") %>"></script>
- </body>
+ <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
+ <script src="<%= static_path(@conn, "/js/app.js") %>"></script>
+ </body>
</html>
diff --git a/larus/web/templates/page/index.html.eex b/larus/web/templates/page/index.html.eex
--- a/larus/web/templates/page/index.html.eex
+++ b/larus/web/templates/page/index.html.eex
@@ -1,36 +1,2 @@
-<div class="jumbotron">
- <h2><%= gettext "Welcome to %{name}", name: "Phoenix!" %></h2>
- <p class="lead">A productive web framework that<br />does not compromise speed and maintainability.</p>
-</div>
-
-<div class="row marketing">
- <div class="col-lg-6">
- <h4>Resources</h4>
- <ul>
- <li>
- <a href="http://phoenixframework.org/docs/overview">Guides</a>
- </li>
- <li>
- <a href="http://hexdocs.pm/phoenix">Docs</a>
- </li>
- <li>
- <a href="https://github.com/phoenixframework/phoenix">Source</a>
- </li>
- </ul>
- </div>
-
- <div class="col-lg-6">
- <h4>Help</h4>
- <ul>
- <li>
- <a href="http://groups.google.com/group/phoenix-talk">Mailing list</a>
- </li>
- <li>
- <a href="http://webchat.freenode.net/?channels=elixir-lang">#elixir-lang on freenode IRC</a>
- </li>
- <li>
- <a href="https://twitter.com/elixirphoenix">@elixirphoenix</a>
- </li>
- </ul>
- </div>
+<div id="view">
</div>
diff --git a/larus/web/views/layout_view.ex b/larus/web/views/layout_view.ex
--- a/larus/web/views/layout_view.ex
+++ b/larus/web/views/layout_view.ex
@@ -1,3 +1,15 @@
defmodule Larus.LayoutView do
- use Larus.Web, :view
+ use Larus.Web, :view
+
+ def author do
+ "Kolab Systems AG"
+ end
+
+ def description do
+ gettext "Larus flying high."
+ end
+
+ def title do
+ gettext "[YOUR TITLE HERE]"
+ end
end

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 10, 8:56 AM (1 d, 5 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18855459
Default Alt Text
D168.1775811387.diff (18 KB)

Event Timeline