route_translator 16.0.1 → 16.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a47bd0c7cfd26fdd5874b1bfd7c56236c4c371f9ba21387256f8e95ee6942dc7
4
- data.tar.gz: fd3faf20805afd09e770705d8110612e1c7d68de652149a3bfb38ddd179d035d
3
+ metadata.gz: ce208e97dd68df337f8bd665d8e922f7a1bd0560757ac722e44c51caeabb5d35
4
+ data.tar.gz: c78dd9a7520d839c5066afe290dafe7d1fa6166473de0567109c5c74b613b19b
5
5
  SHA512:
6
- metadata.gz: 4e5c88d328fdf31d1cc173c92d4d2c5a95048f1ba2d6113e9845a992b1263f2ce47e71b706192a24485dc49257a3f38a5c225b0176af95a5fed78c56a14d4018
7
- data.tar.gz: 72b6b0f9613be540c41f1fe7570c0e5773e870a929c33783d9762a7122a2f530f01a8d49d7abc778e821d601fea697cf9813a07b0c7858638687a1317b03e6a4
6
+ metadata.gz: 7798fd662c28bb906c3ad125b61d616e5894557623657a8bda16ab6b0a54b2fea202fd36f214d2a4b51704ddeeba41ea1785747d892c6ba5f1cf3d08b66821e7
7
+ data.tar.gz: c26787fa838f3a1a315fb46b5168c34ecb720cfb09521f5d0783f27834ace2f41bbcea989eaf4fe59489b2b1ba959d7396b3db4e1ff19e93067d8420e19b07d3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 16.2.0 / 2026-07-29
4
+
5
+ * [ENHANCEMENT] Short-circuit host locale detection by checking `available_locales.include?` before the regex match, avoiding unnecessary regex compilation and matching for unavailable locales.
6
+
7
+ ## 16.1.0 / 2026-07-28
8
+
9
+ * [ENHANCEMENT] Speed up drawing localized routes. `Translator.translate_name` asked the route set for `named_routes.names` (a freshly allocated array of every name defined so far) and scanned it linearly, once per route per locale. It now uses the `NamedRouteCollection#key?` hash lookup.
10
+ * [ENHANCEMENT] Speed up drawing localized routes. `Translator::RouteHelpers.add` fetched `named_route_collection.helper_names` on every route, allocating an array of every helper defined so far and scanning it, to guard a `push` that could not take effect. `helper_names` builds a fresh array on every call, so the push was discarded, and it returns Strings while the pushed value is a Symbol, so the `include?` guard never matched either. Removing both leaves behavior unchanged.
11
+
3
12
  ## 16.0.1 / 2026-04-05
4
13
 
5
14
  * [ENHANCEMENT] Optimize host locale detection ([#354](https://github.com/enriclluelles/route_translator/pull/354))
data/README.md CHANGED
@@ -273,7 +273,7 @@ end
273
273
  | `disable_fallback` | Create routes only for locales that have translations. For example, if we have `/examples` and a translation is not provided for `es`, the route helper of `examples_es` will not be created. Useful when one uses this with a locale route constraint, so non-`es` routes can return a `404` on a Spanish website | `false` |
274
274
  | `force_locale` | Force the locale to be added to all generated route paths, even for the default locale | `false` |
275
275
  | `generate_unlocalized_routes` | Add translated routes without deleting original unlocalized versions. **Note:** Autosets `force_locale` to `true` | `false` |
276
- | `generate_unnamed_unlocalized_routes` | Add the behavior of `force_locale`, but with a named default route which behaves as if `generate_unlocalized_routes` was `true`. `root_path` will redirect to `/en` or `/es`, depending on the value of `I18n.locale` | `false` |
276
+ | `generate_unnamed_unlocalized_routes` | Adds per-locale named routes plus the original unlocalized mapping as an unnamed action route; it does not redirect. Like `force_locale`, it still shows the locale segment even for the default locale (for example, `/en/...`). Flat helpers (`people_path`) still dispatch to the per-locale variant via `I18n.locale`. Safe for legacy bare paths; avoid in multi-locale SEO setups unless you handle canonical URLs or redirects yourself, since both bare and locale-prefixed paths serve the same action. See [#110](https://github.com/enriclluelles/route_translator/issues/110) | `false` |
277
277
  | `hide_locale` | Force the locale to be hidden on generated route paths | `false` |
278
278
  | `host_locales` | Set `I18n.locale` based on `request.host`. Useful for apps accepting requests from more than one domain. The key is a host pattern (supports wildcards for domains, subdomains, and TLDs), and the value is the locale symbol or string to use. See below for more details and examples. | `{}` |
279
279
  | `locale_param_key` | The param key used to set the locale to the newly generated routes | `:locale` |
@@ -321,6 +321,11 @@ This is to avoid odd behaviour brought about by route conflicts and because `hos
321
321
 
322
322
  NOTE: locale from parameters has priority over the one from hosts.
323
323
 
324
+ **Security note:** Host patterns are treated as trusted configuration.
325
+ Never pass user input into `host_locales` keys — the wildcard `*` is
326
+ translated to a non-greedy `.*?` regex, which can expose your application
327
+ to ReDoS if an attacker controls the pattern.
328
+
324
329
  ### Translations for similar routes with different namespaces
325
330
 
326
331
  If you have routes that (partially) share names in one locale, but must be translated differently in another locale, for example:
@@ -9,6 +9,10 @@ module RouteTranslator
9
9
  @lambdas ||= {}
10
10
  end
11
11
 
12
+ # Host patterns come from configuration, not user input.
13
+ # Treating them as trusted avoids a ReDoS vector — the
14
+ # gsub introduces non-greedy `.*?` wildcards, which are
15
+ # safe against backtracking only under that assumption.
12
16
  def regex_for(host_string)
13
17
  escaped = Regexp.escape(host_string).gsub(/\\\*|\\\./, '\\*' => '.*?', '\\.' => '\.?')
14
18
  Regexp.new("^#{escaped}$", Regexp::IGNORECASE)
@@ -21,7 +25,7 @@ module RouteTranslator
21
25
  available_locales = I18n.available_locales
22
26
 
23
27
  RouteTranslator.config.host_locales.find do |pattern, locale|
24
- host&.match?(regex_for(pattern)) && available_locales.include?(locale&.to_sym)
28
+ available_locales.include?(locale&.to_sym) && host&.match?(regex_for(pattern))
25
29
  end&.last&.to_sym
26
30
  end
27
31
 
@@ -15,14 +15,10 @@ module RouteTranslator
15
15
  # I18n.locale = :fr
16
16
  # people_path -> people_fr_path
17
17
  def add(old_name, named_route_collection)
18
- helper_list = named_route_collection.helper_names
19
-
20
18
  %w[path url].each do |suffix|
21
19
  helper_container = named_route_collection.send(:"#{suffix}_helpers_module")
22
20
  new_helper_name = :"#{old_name}_#{suffix}"
23
21
 
24
- helper_list.push(new_helper_name) unless helper_list.include?(new_helper_name)
25
-
26
22
  helper_container.__send__(:define_method, new_helper_name) do |*args|
27
23
  __send__(Translator.route_name_for(args, old_name, suffix, self), *args)
28
24
  end
@@ -14,12 +14,12 @@ module RouteTranslator
14
14
  args_hash&.fetch(:locale, nil)
15
15
  end
16
16
 
17
- def translate_name(name, locale, named_routes_names)
17
+ def translate_name(name, locale, named_routes)
18
18
  return if name.blank?
19
19
 
20
20
  translated_name = "#{name}_#{locale.to_s.underscore}"
21
21
 
22
- translated_name if named_routes_names.exclude?(translated_name.to_sym)
22
+ translated_name unless named_routes.key?(translated_name)
23
23
  end
24
24
 
25
25
  def translate_options(options, locale)
@@ -67,7 +67,7 @@ module RouteTranslator
67
67
  translated_path = translate_path(route.path, locale, route.scope)
68
68
  next unless translated_path
69
69
 
70
- translated_name = translate_name(route.name, locale, route.route_set.named_routes.names)
70
+ translated_name = translate_name(route.name, locale, route.route_set.named_routes)
71
71
  translated_options_constraints = translate_options_constraints(route.options_constraints, locale)
72
72
  translated_options = translate_options(route.options, locale)
73
73
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RouteTranslator
4
- VERSION = '16.0.1'
4
+ VERSION = '16.2.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: route_translator
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.0.1
4
+ version: 16.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geremia Taglialatela
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  - !ruby/object:Gem::Version
91
91
  version: '0'
92
92
  requirements: []
93
- rubygems_version: 4.0.9
93
+ rubygems_version: 4.0.16
94
94
  specification_version: 4
95
95
  summary: Translate your Rails routes in a simple manner
96
96
  test_files: []