accept_language 2.0.8 → 2.1.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: 0afa534a141f111edb4f47449bccb2b44795abd11512319bee75909f672133ab
4
- data.tar.gz: e90f24a3a8104eb8fff13ee15ce7660705e31565769c95e62d4fb4577ff1c816
3
+ metadata.gz: 7273e9328183e3dee11fd68a6598d82c67efbb8bab156d6d9b3424d9ed45dcca
4
+ data.tar.gz: ec31e8a4ac07501f1c481e65452f362be2d7669d93eea626977f25c3aca88dc2
5
5
  SHA512:
6
- metadata.gz: 6d098319c113b5ed61b7b57a57ce78cde8b799d9256240dc076de8626d5021ad4840f96b23b94bcba1d64dc7930e66514da17d4d55d8107c417a9c102a99925b
7
- data.tar.gz: c4695ea31539c0c94713b569e424fd2901a85a4ac67a448ef1c9cd200333fdaa1ab4bfe7429d1b7155fb2c4f4d2ffcf4218d2fee2060f9ffb6b629accc50a56e
6
+ metadata.gz: 36120af5b03b49ea9dce1d50e5c7915c62bf9b0fa09c1130516090e4e3c882b924035f963ad2dc559fda0e818633b6a3e77aba3e46b25533bc972f5dc23ca729
7
+ data.tar.gz: d11855f60c7a4a35c8f675ea5ffc4b320db5a4b40cc95e57143b3dad3c188580830ae0052ac7e934f5ae4c5f2be582db47b4e85b9513b78b4ec1fc69a97ee850
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # The MIT License
2
2
 
3
- Copyright (c) 2019-2024 Cyril Kato
3
+ Copyright (c) 2019-2026 Cyril Kato
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,148 +1,75 @@
1
- # Accept Language 🌐
1
+ # AcceptLanguage
2
2
 
3
- Web applications often need to cater to users from around the world. One of the ways they can provide a better user experience is by presenting the content in the user's preferred language. This is where the `Accept-Language` HTTP header comes into play. Sent by the client (usually a web browser), this header tells the server the list of languages the user understands, and the user's preference order.
4
-
5
- Parsing the `Accept-Language` header can be complex due to its flexible format defined in [RFC 2616](https://tools.ietf.org/html/rfc2616#section-14.4). For instance, it can specify languages, countries, and scripts with varying degrees of preference (quality values).
6
-
7
- `Accept Language` is a lightweight, thread-safe Ruby library designed to parse the `Accept-Language` header, making it easier for your application to determine the best language to respond with. It calculates the intersection of the languages the user prefers and the languages your application supports, handling all the complexity of quality values and wildcards.
8
-
9
- Whether you're building a multilingual web application or just trying to make your service more accessible to users worldwide, `Accept Language` offers a reliable, simple solution.
10
-
11
- ## Status
3
+ A lightweight, thread-safe Ruby library for parsing `Accept-Language` HTTP headers as defined in [RFC 2616](https://tools.ietf.org/html/rfc2616#section-14.4).
12
4
 
13
5
  [![Version](https://img.shields.io/github/v/tag/cyril/accept_language.rb?label=Version&logo=github)](https://github.com/cyril/accept_language.rb/tags)
14
6
  [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/cyril/accept_language.rb/main)
15
- [![Ruby](https://github.com/cyril/accept_language.rb/workflows/Ruby/badge.svg?branch=main)](https://github.com/cyril/accept_language.rb/actions?query=workflow%3Aruby+branch%3Amain)
16
- [![RuboCop](https://github.com/cyril/accept_language.rb/workflows/RuboCop/badge.svg?branch=main)](https://github.com/cyril/accept_language.rb/actions?query=workflow%3Arubocop+branch%3Amain)
7
+ ![Ruby](https://github.com/cyril/accept_language.rb/actions/workflows/ruby.yml/badge.svg?branch=main)
8
+ ![RuboCop](https://github.com/cyril/accept_language.rb/actions/workflows/rubocop.yml/badge.svg?branch=main)
17
9
  [![License](https://img.shields.io/github/license/cyril/accept_language.rb?label=License&logo=github)](https://github.com/cyril/accept_language.rb/raw/main/LICENSE.md)
18
10
 
19
- ## Why Choose Accept Language?
11
+ ## Features
20
12
 
21
- There are a myriad of tools out there, so why should you consider Accept Language for your next project? Here's why:
22
-
23
- - **Thread-Safe**: Multithreading can present unique challenges when dealing with shared resources. Our implementation is designed to be thread-safe, preventing potential concurrency issues.
24
- - **Compact and Robust**: Despite being small in size, Accept Language can handle even the trickiest cases with grace, ensuring you have a reliable tool at your disposal.
25
- - **Case-Insensitive Matching**: In line with the principle of robustness, our tool matches both strings and symbols regardless of case, providing greater flexibility.
26
- - **Independent of Framework**: While many tools require Rails, Rack, or i18n to function, Accept Language stands on its own. It works perfectly well without these dependencies, increasing its adaptability.
27
- - **BCP 47 Support**: BCP 47 defines a standard for language tags. This is crucial for specifying languages unambiguously. Accept Language complies with this standard, ensuring accurate language identification.
13
+ - Thread-safe
14
+ - No framework dependencies
15
+ - Case-insensitive matching
16
+ - BCP 47 language tag support
17
+ - Wildcard and exclusion handling
28
18
 
29
19
  ## Installation
30
20
 
31
- Add this line to your application's Gemfile:
32
-
33
21
  ```ruby
34
22
  gem "accept_language"
35
23
  ```
36
24
 
37
- And then execute:
38
-
39
- ```sh
40
- bundle install
41
- ```
42
-
43
- Or install it yourself as:
44
-
45
- ```sh
46
- gem install accept_language
47
- ```
48
-
49
25
  ## Usage
50
26
 
51
- The `Accept Language` library helps web applications serve content in the user's preferred language by parsing the `Accept-Language` HTTP header. This header indicates the user's language preferences and their priority order.
52
-
53
- ### Basic Syntax
54
-
55
- The library has two main methods:
56
-
57
- - `AcceptLanguage.parse(header)`: Parses the Accept-Language header
58
- - `match(*available_languages)`: Matches against the languages your application supports
59
-
60
27
  ```ruby
61
- AcceptLanguage.parse("fr-CH, fr;q=0.9").match(:fr, :"fr-CH") # => :"fr-CH"
28
+ AcceptLanguage.parse("en-GB, en;q=0.9").match(:en, :"en-GB")
29
+ # => :"en-GB"
62
30
  ```
63
31
 
64
- ### Understanding Language Preferences
32
+ ### Quality values
65
33
 
66
- #### Simple Language Matching
34
+ Quality values (q-values) indicate preference order from 0 to 1:
67
35
 
68
36
  ```ruby
69
- # Header: "da" (Danish is the preferred language)
70
- # Available: :en and :da
71
- AcceptLanguage.parse("da").match(:en, :da) # => :da
72
-
73
- # No match available - returns nil
74
- AcceptLanguage.parse("da").match(:fr, :en) # => nil
75
- ```
37
+ parser = AcceptLanguage.parse("da, en-GB;q=0.8, en;q=0.7")
76
38
 
77
- #### Quality Values (q-values)
78
-
79
- Q-values range from 0 to 1 and indicate preference order:
80
-
81
- ```ruby
82
- # Header: "da, en-GB;q=0.8, en;q=0.7"
83
- # Means:
84
- # - Danish (da): q=1.0 (highest priority)
85
- # - British English (en-GB): q=0.8 (second choice)
86
- # - Generic English (en): q=0.7 (third choice)
87
- AcceptLanguage.parse("da, en-GB;q=0.8, en;q=0.7").match(:en, :da) # => :da
88
- AcceptLanguage.parse("da, en-GB;q=0.8, en;q=0.7").match(:en, :"en-GB") # => :"en-GB"
39
+ parser.match(:en, :da) # => :da
40
+ parser.match(:en, :"en-GB") # => :"en-GB"
41
+ parser.match(:fr) # => nil
89
42
  ```
90
43
 
91
- #### Language Variants
44
+ ### Language variants
92
45
 
93
- The library handles specific language variants (regional or script variations):
46
+ A generic language tag matches its regional variants, but not the reverse:
94
47
 
95
48
  ```ruby
96
- # Specific variants must match exactly
97
- AcceptLanguage.parse("fr-CH").match(:fr) # => nil (Swiss French ≠ Generic French)
98
-
99
- # But generic variants can match specific ones
100
- AcceptLanguage.parse("fr").match(:"fr-CH") # => :"fr-CH"
101
-
102
- # Script variants are also supported
103
- AcceptLanguage.parse("uz-Latn-UZ").match("uz-Latn-UZ") # => "uz-Latn-UZ"
49
+ AcceptLanguage.parse("fr").match(:"fr-CH") # => :"fr-CH"
50
+ AcceptLanguage.parse("fr-CH").match(:fr) # => nil
104
51
  ```
105
52
 
106
- #### Wildcards and Exclusions
107
-
108
- The `*` wildcard matches any language, and `q=0` excludes languages:
109
-
110
- ```ruby
111
- # Accept any language but prefer German
112
- AcceptLanguage.parse("de-DE, *;q=0.5").match(:fr) # => :fr (matched by wildcard)
113
-
114
- # Accept any language EXCEPT English
115
- AcceptLanguage.parse("*, en;q=0").match(:en) # => nil (explicitly excluded)
116
- AcceptLanguage.parse("*, en;q=0").match(:fr) # => :fr (matched by wildcard)
117
- ```
53
+ ### Wildcards and exclusions
118
54
 
119
- #### Complex Example
55
+ The wildcard `*` matches any language. A q-value of 0 explicitly excludes a language:
120
56
 
121
57
  ```ruby
122
- # Header: "de-LU, fr;q=0.9, en;q=0.7, *;q=0.5"
123
- # Means:
124
- # - Luxembourg German: q=1.0 (highest priority)
125
- # - French: q=0.9 (second choice)
126
- # - English: q=0.7 (third choice)
127
- # - Any other language: q=0.5 (lowest priority)
128
- header = "de-LU, fr;q=0.9, en;q=0.7, *;q=0.5"
129
- parser = AcceptLanguage.parse(header)
130
-
131
- parser.match(:de, :"de-LU") # => :"de-LU" (exact match)
132
- parser.match(:fr, :en) # => :fr (higher q-value)
133
- parser.match(:es, :it) # => :es (matched by wildcard)
58
+ AcceptLanguage.parse("de-DE, *;q=0.5").match(:fr) # => :fr
59
+ AcceptLanguage.parse("*, en;q=0").match(:en) # => nil
60
+ AcceptLanguage.parse("*, en;q=0").match(:fr) # => :fr
134
61
  ```
135
62
 
136
- ### Case Sensitivity
63
+ ### Case sensitivity
137
64
 
138
- The matching is case-insensitive but preserves the case of the returned value:
65
+ Matching is case-insensitive but preserves the case of the available language tag:
139
66
 
140
67
  ```ruby
141
68
  AcceptLanguage.parse("en-GB").match("en-gb") # => "en-gb"
142
69
  AcceptLanguage.parse("en-gb").match("en-GB") # => "en-GB"
143
70
  ```
144
71
 
145
- ### Rails integration example
72
+ ## Rails integration
146
73
 
147
74
  ```ruby
148
75
  # app/controllers/application_controller.rb
@@ -171,15 +98,16 @@ class ApplicationController < ActionController::Base
171
98
  end
172
99
  ```
173
100
 
174
- ## Read more
101
+ ## Documentation
175
102
 
103
+ - [API Documentation](https://rubydoc.info/github/cyril/accept_language.rb/main)
176
104
  - [Language negotiation with Ruby](https://dev.to/cyri_/language-negotiation-with-ruby-5166)
177
105
  - [Rubyで言語ネゴシエーション](https://qiita.com/cyril/items/45dc233edb7be9d614e7)
178
106
 
179
107
  ## Versioning
180
108
 
181
- __AcceptLanguage__ uses [Semantic Versioning 2.0.0](https://semver.org/)
109
+ This library follows [Semantic Versioning 2.0.0](https://semver.org/).
182
110
 
183
111
  ## License
184
112
 
185
- The [gem](https://rubygems.org/gems/accept_language) is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
113
+ Available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -5,19 +5,16 @@ module AcceptLanguage
5
5
  # the optimal language choice. Handles quality values, wildcards, and language tag matching
6
6
  # according to RFC 2616 specifications.
7
7
  #
8
- # @example
9
- # Matcher.new("da" => 1.0, "en-GB" => 0.8, "en" => 0.7).call(:ug, :kk, :ru, :en) # => :en
10
- # Matcher.new("da" => 1.0, "en-GB" => 0.8, "en" => 0.7).call(:fr, :en, :"en-GB") # => :"en-GB"
8
+ # @api private
9
+ # @note This class is intended for internal use by {Parser} and should not be instantiated directly.
11
10
  class Matcher
11
+ # @api private
12
12
  WILDCARD = "*"
13
13
 
14
+ # @api private
14
15
  attr_reader :excluded_langtags, :preferred_langtags
15
16
 
16
- # Initialize a new Matcher object with the languages_range parameter representing the user's
17
- # preferred languages and their respective quality values.
18
- #
19
- # @param [Hash<String, BigDecimal>] languages_range A hash where keys represent languages and
20
- # values are the quality of preference for each language. A value of zero means the language is not acceptable.
17
+ # @api private
21
18
  def initialize(**languages_range)
22
19
  @excluded_langtags = ::Set[]
23
20
  langtags = []
@@ -34,15 +31,7 @@ module AcceptLanguage
34
31
  @preferred_langtags = langtags.compact.reverse
35
32
  end
36
33
 
37
- # Finds the optimal language match by comparing user preferences against available languages.
38
- # Handles priorities based on:
39
- # 1. Explicit quality values (q-values)
40
- # 2. Language tag specificity (exact matches preferred over partial matches)
41
- # 3. Order of preference in the original Accept-Language header
42
- #
43
- # @param [Array<String, Symbol>] available_langtags Languages supported by your application
44
- # @return [String, Symbol, nil] Best matching language or nil if no acceptable match found
45
- # @raise [ArgumentError] If any language tag is nil
34
+ # @api private
46
35
  def call(*available_langtags)
47
36
  raise ::ArgumentError, "Language tags cannot be nil" if available_langtags.any?(&:nil?)
48
37
 
@@ -72,13 +61,17 @@ module AcceptLanguage
72
61
  end
73
62
 
74
63
  def find_matching_tag(preferred_tag, available_langtags)
75
- available_langtags.find { |tag| tag.match?(/\A#{preferred_tag}/i) }
64
+ pattern = /\A#{::Regexp.escape(preferred_tag)}/i
65
+ available_langtags.find { |tag| tag.match?(pattern) }
76
66
  end
77
67
 
78
68
  def any_other_langtag(*available_langtags)
79
69
  available_langtags.find do |available_langtag|
80
70
  langtags = preferred_langtags - [WILDCARD]
81
- langtags.none? { |tag| available_langtag.match?(/\A#{tag}/i) }
71
+ langtags.none? do |tag|
72
+ pattern = /\A#{::Regexp.escape(tag)}/i
73
+ available_langtag.match?(pattern)
74
+ end
82
75
  end
83
76
  end
84
77
 
@@ -91,7 +84,10 @@ module AcceptLanguage
91
84
  end
92
85
 
93
86
  def unacceptable?(langtag)
94
- excluded_langtags.any? { |excluded_tag| langtag.match?(/\A#{excluded_tag}/i) }
87
+ excluded_langtags.any? do |excluded_tag|
88
+ pattern = /\A#{::Regexp.escape(excluded_tag)}/i
89
+ langtag.match?(pattern)
90
+ end
95
91
  end
96
92
 
97
93
  def wildcard?(value)
@@ -8,27 +8,31 @@ module AcceptLanguage
8
8
  # and handles edge cases like malformed inputs and implicit quality values.
9
9
  #
10
10
  # @example
11
- # Parser.new("da, en-GB;q=0.8, en;q=0.7")
12
- # # => #<AcceptLanguage::Parser:0x00007 @languages_range={"da"=>1.0, "en-GB"=>0.8, "en"=>0.7}>
11
+ # parser = Parser.new("da, en-GB;q=0.8, en;q=0.7")
12
+ # parser.match(:en, :da) # => :da
13
13
  #
14
- # @see https://tools.ietf.org/html/rfc2616#section-14.4 for more information on Accept-Language header fields.
14
+ # @see https://tools.ietf.org/html/rfc2616#section-14.4
15
15
  class Parser
16
+ # @api private
16
17
  DEFAULT_QUALITY = "1"
18
+ # @api private
17
19
  SEPARATOR = ","
20
+ # @api private
18
21
  SPACE = " "
22
+ # @api private
19
23
  SUFFIX = ";q="
20
-
21
- # Validates q-values according to RFC 2616:
22
- # - Must be between 0 and 1
23
- # - Can have up to 3 decimal places
24
- # - Allows both forms: .8 and 0.8
24
+ # @api private
25
25
  QVALUE_PATTERN = /\A(?:0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?|\.[0-9]{1,3})\z/
26
+ # @api private
27
+ LANGTAG_PATTERN = /\A(?:\*|[a-zA-Z]{1,8}(?:-[a-zA-Z0-9]{1,8})*)\z/
26
28
 
29
+ # @api private
30
+ # @return [Hash<String, BigDecimal>] Parsed language tags and their quality values
27
31
  attr_reader :languages_range
28
32
 
29
33
  # Initializes a new Parser instance by importing and processing the given Accept-Language header field.
30
34
  #
31
- # @param [String] field The Accept-Language header field to parse.
35
+ # @param field [String] The Accept-Language header field to parse.
32
36
  def initialize(field)
33
37
  @languages_range = import(field)
34
38
  end
@@ -36,8 +40,9 @@ module AcceptLanguage
36
40
  # Finds the best matching language from available options based on user preferences.
37
41
  # Considers quality values and language tag specificity (e.g., "en-US" vs "en").
38
42
  #
39
- # @param [Array<String, Symbol>] available_langtags Languages supported by your application
43
+ # @param available_langtags [Array<String, Symbol>] Languages supported by your application
40
44
  # @return [String, Symbol, nil] Best matching language tag or nil if no match found
45
+ #
41
46
  # @example Match against specific language options
42
47
  # parser.match("en", "fr", "de") # => "en" if English is preferred
43
48
  # @example Match with region-specific tags
@@ -48,13 +53,6 @@ module AcceptLanguage
48
53
 
49
54
  private
50
55
 
51
- # Processes the Accept-Language header field to extract language tags and their respective quality values.
52
- #
53
- # @example
54
- # import('da, en-GB;q=0.8, en;q=0.7')
55
- # # => {"da"=>1.0, "en-GB"=>0.8, "en"=>0.7}
56
- #
57
- # @return [Hash<String, BigDecimal>] A hash where keys represent language tags and values are their respective quality values.
58
56
  def import(field)
59
57
  "#{field}".delete(SPACE).split(SEPARATOR).inject({}) do |hash, lang|
60
58
  tag, quality = lang.split(SUFFIX)
@@ -72,7 +70,9 @@ module AcceptLanguage
72
70
  end
73
71
 
74
72
  def valid_tag?(tag)
75
- !tag.nil? && !tag.empty?
73
+ return false if tag.nil?
74
+
75
+ tag.match?(LANGTAG_PATTERN)
76
76
  end
77
77
  end
78
78
  end
@@ -1,44 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # AcceptLanguage is a lightweight library that parses Accept-Language HTTP headers (RFC 2616) to determine
4
- # user language preferences. It converts raw header values into a structured format for matching against
5
- # your application's supported languages.
3
+ # AcceptLanguage is a lightweight library for parsing Accept-Language HTTP headers
4
+ # as defined in RFC 2616. It determines user language preferences and matches them
5
+ # against your application's supported languages.
6
6
  #
7
- # @example
8
- # AcceptLanguage.parse("da, en-GB;q=0.8, en;q=0.7")
9
- # # => #<AcceptLanguage::Parser:0x00007 @languages_range={"da"=>1.0, "en-GB"=>0.8, "en"=>0.7}>
7
+ # @example Basic usage
8
+ # AcceptLanguage.parse("da, en-GB;q=0.8, en;q=0.7").match(:en, :da)
9
+ # # => :da
10
10
  #
11
- # @example Integration with Rails
12
- # class ApplicationController < ActionController::Base
13
- # before_action :set_locale
14
- #
15
- # private
16
- #
17
- # def set_locale
18
- # header = request.env["HTTP_ACCEPT_LANGUAGE"]
19
- # locale = AcceptLanguage.parse(header).match(*I18n.available_locales)
20
- # I18n.locale = locale || I18n.default_locale
21
- # end
22
- # end
11
+ # @example With regional variants
12
+ # AcceptLanguage.parse("fr-CH, fr;q=0.9").match(:fr, :"fr-CH")
13
+ # # => :"fr-CH"
23
14
  #
24
15
  # @see https://tools.ietf.org/html/rfc2616#section-14.4
25
16
  module AcceptLanguage
26
- # Parses an Accept-Language header field value into a Parser object, which can then be used to match
27
- # user's preferred languages against the languages your application supports.
28
- # This method accepts a string argument in the format as described in RFC 2616 Section 14.4, and returns
29
- # a Parser object which responds to the #match method.
17
+ # Parses an Accept-Language header field value.
30
18
  #
31
- # @param field [String] the Accept-Language header field value.
19
+ # @param field [String] The Accept-Language header field value
20
+ # @return [Parser] A parser object that responds to {Parser#match}
32
21
  #
33
22
  # @example
34
- # AcceptLanguage.parse("da, en-GB;q=0.8, en;q=0.7")
35
- # # => #<AcceptLanguage::Parser:0x00007 @languages_range={"da"=>1.0, "en-GB"=>0.8, "en"=>0.7}>
36
- #
37
- # @return [Parser] a Parser object that responds to #match method.
23
+ # parser = AcceptLanguage.parse("en-GB, en;q=0.9")
24
+ # parser.match(:en, :"en-GB") # => :"en-GB"
38
25
  def self.parse(field)
39
26
  Parser.new(field)
40
27
  end
41
28
  end
42
29
 
43
- # Load the Parser class
44
30
  require_relative File.join("accept_language", "parser")
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: accept_language
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.8
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-15 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2026-01-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bigdecimal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description: Parses the Accept-Language header from an HTTP request and produces a
14
28
  hash of languages and qualities.
15
29
  email: contact@cyril.email
@@ -35,14 +49,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
35
49
  requirements:
36
50
  - - ">="
37
51
  - !ruby/object:Gem::Version
38
- version: 3.2.2
52
+ version: 3.2.0
39
53
  required_rubygems_version: !ruby/object:Gem::Requirement
40
54
  requirements:
41
55
  - - ">="
42
56
  - !ruby/object:Gem::Version
43
57
  version: '0'
44
58
  requirements: []
45
- rubygems_version: 3.4.10
59
+ rubygems_version: 3.4.19
46
60
  signing_key:
47
61
  specification_version: 4
48
62
  summary: "Parser for Accept-Language request HTTP header \U0001F310"