Introduction
Lexical.Localization is a localization class library for .NET.
Warning
This project is outdated and replaced by re-designed Avalanche.Localization.
Deployment features
- Dependency Injection
- File providers
- Control over how assets are organized
Interoperability
- Microsoft.Extensions.Localization.Abstractions
- Microsoft.Extensions.Logger.Abstractions
- Microsoft.Extensions.DependencyInjection.Abstractions
- ResourceManager
File types
- Language Strings
- Localization of binary assets for gfx and audio resources
File formats
- .ini
- .json
- .xml
- .resx
- .resources
Other features
- Best practice recommendations
- Dynamic and non-dynamic use
- Inlined language strings
- Automatic inlined string scanning
- Build tool, T4 script, command line tool
- Formatting strings
- Cache
- Singletons
- Loggers
- File format conversion tools
Translator features
- Live reloading of localization files
- Unicode CLDR Plural Rules
- Multiple pluralized arguments per string
- Optional pluralization cases
Links
Contents:
- Tutorial
- IAsset
- IStringAsset
- ILine
- ILineFactory
- ILineRoot
- ILineFormat
- LineComparer
- IFileReader
- Plurality
- ICulturePolicy
- IStringFormat
Tutorial
Format and Values
ILine is a localization line. It can be embedded with a default string.
ILine line = LineRoot.Global.Type("MyClass").Key("hello").Format("Hello, {0}.");
Values are provided with .Value(object[]).
Console.WriteLine(line.Value("Corellia Melody"));
Providing .Format() and .Value() is equivalent to String.Format().
Console.WriteLine(LineRoot.Global.Format("It is now {0:d} at {0:t}").Value(DateTime.Now));
Console.WriteLine(String.Format("It is now {0:d} at {0:t}", DateTime.Now));
.Formulate($string) appends interpolated strings. It's equivalent to appending .Format() and .Value() parts.
DateTime time = DateTime.Now;
Console.WriteLine(LineRoot.Global.Key("Time").Formulate($"It is now {time:d} at {time:t}"));
Enumeration localization strings are searched with key "Assembly:asm:Type:enumType:Key:enumCase".
Permissions permissions = Permissions.Add | Permissions.Modify | Permissions.Remove;
Console.WriteLine( LineRoot.Global.Key("Permission").Formulate($"User permissions {permissions}") );
[Flags]
public enum Permissions { Add = 1, Remove = 2, Modify = 4 }
Culture
The format culture can be enforced with .Culture(CultureInfo), without changing the thread-local culture variable.
Console.WriteLine(LineRoot.Global.Format("It is now {0:d} at {0:t}").Culture("sv").Value(DateTime.Now));
Console.WriteLine(LineRoot.Global.Format("It is now {0:d} at {0:t}").Culture("de").Value(DateTime.Now));
Inlining
Default strings can be inlined for multiple cultures.
ILine line = LineRoot.Global
.Key("hello")
.Format("Hello, {0}.")
.Inline("Culture:fi", "Hei, {0}")
.Inline("Culture:de", "Hallo, {0}");
Console.WriteLine(line.Value("Corellia Melody"));
And inlined with different plurality cases.
ILine line = LineRoot.Global.PluralRules("Unicode.CLDR35")
.Type("MyClass").Key("Cats")
.Format("{cardinal:0} cat(s)")
.Inline("N:zero", "no cats")
.Inline("N:one", "a cat")
.Inline("N:other", "{0} cats");
for (int cats = 0; cats <= 2; cats++)
Console.WriteLine(line.Value(cats));
And with permutations of different cultures and plurality cases.
ILine line = LineRoot.Global.PluralRules("Unicode.CLDR35")
.Type("MyClass").Key("Cats")
.Format("{0} cat(s)")
.Inline("Culture:en", "{cardinal:0} cat(s)")
.Inline("Culture:en:N:zero", "no cats")
.Inline("Culture:en:N:one", "a cat")
.Inline("Culture:en:N:other", "{0} cats")
.Inline("Culture:fi", "{cardinal:0} kissa(a)")
.Inline("Culture:fi:N:zero", "ei kissoja")
.Inline("Culture:fi:N:one", "yksi kissa")
.Inline("Culture:fi:N:other", "{0} kissaa");
// Print with plurality and to culture "en"
for (int cats = 0; cats <= 2; cats++)
Console.WriteLine(line.Culture("en").Value(cats));
Files
Localization assets can be read from files and placed into the global LineRoot.Global.
IAsset asset = LineReaderMap.Default.FileAsset("PluralityExample0a.xml");
LineRoot.Builder.AddAsset(asset).Build();
ILine line = LineRoot.Global.Key("Cats").Format("{0} cat(s)");
// Print with plurality
for (int cats = 0; cats <= 2; cats++)
Console.WriteLine(line.Culture("fi").Value(cats));
PluralityExample0a.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N"
xmlns="urn:lexical.fi"
PluralRules="Unicode.CLDR35">
<!-- Fallback string, for "" culture -->
<Key:Cats>{0} cat(s)</Key:Cats>
<!-- Translator added strings for "en" -->
<Key:Cats Culture="en">
{cardinal:0} cat(s)
<N:zero>no cats</N:zero>
<N:one>a cat</N:one>
<N:other>{0} cats</N:other>
</Key:Cats>
<!-- Translator added strings for "fi" -->
<Key:Cats Culture="fi">
{cardinal:0} kissa(a)
<N:zero>ei kissoja</N:zero>
<N:one>yksi kissa</N:one>
<N:other>{0} kissaa</N:other>
</Key:Cats>
</Localization>
Or, assets can be loaded and placed into a new ILineRoot.
csharp
IAsset asset = LineReaderMap.Default.FileAsset("PluralityExample0a.xml");
ILineRoot root = new LineRoot(asset, new CulturePolicy());
ILine line = root.Key("Cats").Format("{0} cat(s)");
IAsset is an abstraction to localization lines and localized resources.
Implementing classes can be provided within code.
csharp
List<ILine> lines = new List<ILine> {
LineAppender.Default.Type("MyClass").Key("Hello").Format("Hello, {0}"),
LineAppender.Default.Type("MyClass").Key("Hello").Culture("fi").Format("Hei, {0}"),
LineAppender.Default.Type("MyClass").Key("Hello").Culture("de").Format("Hallo, {0}")
};
IAsset asset = new StringAsset().Add(lines).Load();
ILineRoot root = new LineRoot(asset, new CulturePolicy());
ILine line = root.Type("MyClass").Key("Hello");
Console.WriteLine(line.Value("Corellia Melody"));
## Logging
Loggers can be appended to ILine for debugging purposes.
csharp
ILine root = LineRoot.Global.Logger(Console.Out, LineStatusSeverity.Ok);
ILine line = root.Type("MyClass").Key("hello").Format("Hello, {0}.");
Console.WriteLine(line.Value("Corellia Melody"));
## StringFormat
Different string formats, such as C#'s String.Format, are supported. IStringFormat is an abstraction to string formats.
csharp
ILine line1a = LineRoot.Global.Key("Cats").Format("{0} cat(s)");
IString string1 = CSharpFormat.Default.Parse("{0} cat(s)");
ILine line1b = LineRoot.Global.Key("Cats").String(string1);
ILine line2a = LineRoot.Global.Key("Ok").Text("{in braces}");
IString string2 = TextFormat.Default.Parse("{in braces}");
ILine line2b = LineRoot.Global.Key("Ok").String(string2);
## Culture Policy
ICulturePolicy determines which culture to apply.
csharp
ICulturePolicy culturePolicy = new CulturePolicy().SetToCurrentThreadUICulture();
ILine root = new LineRoot(null, culturePolicy: culturePolicy);
## Resolving string
ILine.ResolveString() returns more information about the string resolve process than ILine.ToString().
csharp
LineString resolved_string = line.Value("Corellia Melody").ResolveString();
Console.WriteLine(resolved_string.Status);
## String Localizer
StringLocalizerRoot.Global is same root as LineRoot.Global with the difference, that parts derived from it implement IStringLocalizer and IStringLocalizerFactory.
csharp
ILine line = StringLocalizerRoot.Global.Type("MyClass").Key("hello").Format("Hello, {0}.");
IStringLocalizer localizer = line.AsStringLocalizer();
IStringLocalizerFactory localizerFactory = line.AsStringLocalizerFactory();
New StringLocalizerRoot can also be constructed.
csharp
ILineRoot root = new StringLocalizerRoot(null, new CulturePolicy());
ILine line = root.Type("MyClass").Key("hello").Format("Hello, {0}.");
IStringLocalizer localizer = line.AsStringLocalizer();
IStringLocalizerFactory localizerFactory = line.AsStringLocalizerFactory();
IStringLocalizer reference can be adapted from regular LineRoot as well, but causes an additional heap object to be instantiated.
csharp
ILine line = LineRoot.Global.Type("MyClass").Key("hello").Format("Hello, {0}.");
IStringLocalizer localizer = line.AsStringLocalizer();
IStringLocalizerFactory localizerFactory = line.AsStringLocalizerFactory();
## Example Class
Keys can be placed in static references if the singleton LineRoot.Global is used.
csharp
public class MyClass
{
/// <summary>
/// Localization root for this class.
/// </summary>
static ILine localization = LineRoot.Global.Assembly("MyLibrary").Type<MyClass>();
/// <summary>
/// Localization key "Ok" with a default string, and couple of inlined strings for two cultures.
/// </summary>
static ILine ok = localization.Key("Success")
.Text("Success")
.fi("Onnistui")
.sv("Det funkar");
/// <summary>
/// Localization key "Error" with a default string, and couple of inlined ones for two cultures.
/// </summary>
static ILine error = localization.Key("Error")
.Format("Error (Code=0x{0:X8})")
.fi("Virhe (Koodi=0x{0:X8})")
.sv("Sönder (Kod=0x{0:X8})");
public void DoOk()
{
Console.WriteLine(ok);
}
public void DoError()
{
Console.WriteLine(error.Value(0x100));
}
public void DoExample()
{
string msg = "";
Console.WriteLine(localization.Key("Msg").Formulate($"You received a message: \"{msg}\""));
}
}
## Links
* Website
* Github
* Nuget
* Slack
# IAsset
Asset is a class that manages localization sources.
Sources are typically files, embedded resources, and plain code.
csharp
// Language string source
Dictionary<string, string> src = new Dictionary<string, string> { { "en:hello", "Hello World!" } };
// Create Asset
IAsset asset = new StringAsset(src, LineParameterPrinter.Default);
IAsset is the root interface for assets. It serves as a signal that the implementing class has further asset features.
There are more specific interfaces such as IStringAsset and IBinaryAsset which
retrieve language strings and binary resources.
Asset interfaces are not called directly but used instead by calling extension methods of IAsset.
csharp
// Create key
ILine key = new LineRoot().Key("hello").Culture("en");
// Resolve string - Call to StringAssetExtensions.GetString()
IString str = asset.GetLine(key).GetString();
# Asset Composition
AssetComposition is the default class. It unifies a group of assets into one asset, typically so that they can be assigned to ILineRoot.
csharp
// Create individual assets
IAsset asset_1 = new StringAsset(new Dictionary<string, string> { { "Culture:en:Key:hello", "Hello World!" } }, LineFormat.Parameters);
IAsset asset_2 = new ResourceStringDictionary(new Dictionary<string, byte[]> { { "Culture:en:Key:Hello.Icon", new byte[] { 1, 2, 3 } } }, LineFormat.Parameters);
// Create composition asset
IAssetComposition asset_composition = new AssetComposition(asset_1, asset_2);
// Assign the composition to root
ILineRoot root = new LineRoot(asset_composition, new CulturePolicy());
IAssetComposition is the interface for classes that composes IAsset components.
csharp
/// <summary>
/// Composition of <see cref="IAsset"/> components.
/// </summary>
public interface IAssetComposition : IAsset, IList<IAsset>
{
/// <summary>
/// Set to new content.
/// </summary>
/// <param name="newContent"></param>
/// <exception cref="InvalidOperationException">If compostion is readonly</exception>
void CopyFrom(IEnumerable<IAsset> newContent);
/// <summary>
/// Get component assets that implement T.
/// </summary>
/// <param name="recursive">if true, visits children recursively</param>
/// <typeparam name="T"></typeparam>
/// <returns>enumerable or null</returns>
IEnumerable<T> GetComponents<T>(bool recursive) where T : IAsset;
}
Asset Builder
AssetBuilder is a factory class that constructs new instances of IAsset. Asset builder is populated with IAssetSources which participate to the build process.
This example shows how to create asset builder, add asset sources, and then to build an asset.
// Create dictionary of strings
Dictionary<string, string> strings = new Dictionary<string, string> { { "en:hello", "Hello World!" } };
// Create IAssetSource that adds cache
IAssetSource assetSource_0 = new AssetCacheSource(c => c.AddResourceCache().AddStringsCache().AddCulturesCache());
// Create IAssetSource that static reference of IAsset (string dictionary)
IAssetSource assetSource_1 = new AssetFactory(new StringAsset(strings, LineParameterPrinter.Default) );
// Create AssetBuilder
IAssetBuilder builder = new AssetBuilder(assetSource_0, assetSource_1);
// Instantiate IAsset
IAsset asset = builder.Build();
// Create string key
ILine key = new LineRoot().Key("hello").Culture("en");
// Request value
IString value = asset.GetLine( key ).GetString();
// Print result
Console.WriteLine(value);
There are extension methods for convenience.
// Create AssetBuilder
IAssetBuilder builder = new AssetBuilder();
// Add IAssetSource that adds cache
builder.AddCache();
// Add IAssetSource that adds strings
builder.AddStrings(strings, LineParameterPrinter.Default);
Asset builders and asset sources are used with Dependency Injection. Asset sources are added to IServiceCollection to participate in constructing in new assets. Asset builder makes the new asset when requested by ServiceProvider. The calling assembly must have nuget dependency to Microsoft.Extensions.DependencyInjection.Abstractions.
// Initialize service collection
IServiceCollection serviceCollection = new ServiceCollection();
// Add IAssetBuilder, an instruction to construct one later
serviceCollection.AddSingleton<IAssetBuilder, AssetBuilder>();
// Add IAssetSource, that will construct cache cache
serviceCollection.AddSingleton<IAssetSource>(new AssetCacheSource(o => o.AddResourceCache().AddStringsCache().AddCulturesCache()));
// Add IAssetSource, that adds strings
Dictionary<string, string> strings = new Dictionary<string, string> { { "en:hello", "Hello World!" } };
serviceCollection.AddSingleton<IAssetSource>(new AssetFactory(new StringAsset(strings, LineParameterPrinter.Default)));
// Add delegate to forward IAsset request to IAssetBuilder
serviceCollection.AddSingleton<IAsset>(s => s.GetService<IAssetBuilder>().Build());
// Create service scope
using (ServiceProvider serviceScope = serviceCollection.BuildServiceProvider())
{
// Construct new asset
IAsset asset = serviceScope.GetService<IAsset>();
// Create string key
ILine key = new LineRoot().Key("hello").Culture("en");
// Request string
IString value = asset.GetLine(key).GetString();
// Print result
Console.WriteLine(value);
}
Extension method AddLexicalLocalization() adds IAsset, ILineRoot, ICultureProvider and IAssetBuilder services to IServiceCollection.
// Initialize service collection
IServiceCollection serviceCollection = new ServiceCollection();
// Add IAssetBuilder, ILineRoot and ICulturePolicy to service collection
serviceCollection.AddLexicalLocalization(
addStringLocalizerService: false,
addCulturePolicyService: false,
useGlobalInstance: false,
addCache: true);
// Add dictionary of strings
Dictionary<string, string> strings = new Dictionary<string, string> { { "en:hello", "Hello World!" } };
serviceCollection.AddSingleton<IAssetSource>(new AssetFactory(new StringAsset(strings, LineParameterPrinter.Default)));
// Create service scope
using (ServiceProvider serviceScope = serviceCollection.BuildServiceProvider())
{
// Construct new asset
IAsset asset = serviceScope.GetService<IAsset>();
// Create string key
ILine key = new LineRoot().Key("hello").Culture("en");
// Request string
IString value = asset.GetLine(key).GetString();
// Print result
Console.WriteLine(value);
}
IAssetBuilder is the interface for factory class(es) that instantiate IAssets.
csharp
/// <summary>
/// Builder that can create <see cref="IAsset"/> instance(s).
///
/// For dependency injection.
/// </summary>
public interface IAssetBuilder
{
/// <summary>
/// List of asset sources that can construct assets.
/// </summary>
IList<IAssetSource> Sources { get; }
/// <summary>
/// Build language strings.
/// </summary>
/// <returns></returns>
IAsset Build();
}
IAssetSource is the interface for sources that contribute asset(s) to the built result.
csharp
/// <summary>
/// Source of assets. Adds resources to builder's list.
/// </summary>
public interface IAssetSource
{
/// <summary>
/// Source adds its <see cref="IAsset"/>s to list.
/// </summary>
/// <param name="list">list to add provider(s) to</param>
/// <returns>self</returns>
void Build(IList<IAsset> list);
/// <summary>
/// Allows source to do post build action and to decorate already built asset.
///
/// This allows a source to provide decoration such as cache.
/// </summary>
/// <param name="asset"></param>
/// <returns>asset or component</returns>
IAsset PostBuild(IAsset asset);
}
Asset Cache
AssetCache is used for caching the requests in cases where asset implementation needs better performance. Asset cache works as a decorator layer that forwards requests to its source and then stores the results.
Asset cache needs to be populated with IAssetCacheParts which each handle caching for a specific interface.
// Create asset
var source = new Dictionary<string, string> { { "Culture:en:Key:hello", "Hello World!" } };
IAsset asset = new StringAsset(source, LineFormat.Parameters);
// Create cache
IAssetCache asset_cached = new AssetCache(asset);
// Adds feature to cache IBinaryAsset specific requests
asset_cached.Add(new AssetCachePartResources(asset_cached.Source, asset_cached.Options));
// Adds feature to cache IStringAsset specific requests
asset_cached.Add(new AssetCachePartStrings(asset_cached.Source, asset_cached.Options));
// Adds feature to cache IAssetCultureEnumerable specific requests
asset_cached.Add(new AssetCachePartCultures(asset_cached.Source, asset_cached.Options));
// Assign the cached asset
LineRoot.Global.Asset = asset_cached;
There are extension methods for convenience.
// Create cache decorator
IAssetCache asset_cached = new AssetCache(asset).AddResourceCache().AddStringsCache().AddCulturesCache();
And then there is one extension method CreateCache() that wraps the asset into a cache and adds the default cache parts.
// Decorate with cache
IAssetCache asset_cached = asset.CreateCache();
IAssetCache is the interface for cache implementatations. It is a composition of cache parts.
/// <summary>
/// Asset cache is decorator that caches requests of source object.
///
/// The interface is used as signal for extension methods.
/// </summary>
public interface IAssetCache : IAssetComposition
{
/// <summary>
/// Source asset.
/// </summary>
IAsset Source { get; }
/// <summary>
/// Cache options.
/// </summary>
AssetCacheOptions Options { get; }
}
/// <summary>
/// Part that addresses a feature (an interface) to cache.
/// </summary>
public interface IAssetCachePart : IAsset
{
}
Caching options
AssetCacheOptions carries a key-value map of caching parameters.
// Create asset
var source = new Dictionary<string, string> { { "Culture:en:Key:hello", "Hello World!" } };
IAsset asset = new StringAsset(source, LineFormat.Parameters);
// Create cache
IAssetCache asset_cached = asset.CreateCache();
// Configure options
asset_cached.Options.SetCloneKeys(true);
asset_cached.Options.SetCacheStreams(true);
asset_cached.Options.SetMaxResourceCount(1024);
asset_cached.Options.SetMaxResourceSize(1024 * 1024);
asset_cached.Options.SetMaxResourceTotalSize(1024 * 1024 * 1024);
// Assign the asset with cache decoration
LineRoot.Global.Asset = asset_cached;
Table of Asset cache option's keys
Key | Method | Default | Description |
---|---|---|---|
CloneKeys | .SetCloneKeys(bool) | true | Should cache create clones of keys, or should it use the keys that come from requests in its cache structures. |
CacheStreams | .SetCacheStreams(bool) | true | Should IBinaryAsset#OpenStream requests be cached. |
MaxResourceCount | .SetMaxResourceCount(int) | 2147483647 | Maximum number of resources to cache. |
MaxResourceSize | .SetMaxResourceSize(int) | 4096 | Maximum size of a resource. |
MaxResourceTotalSize | .SetMaxResourceTotalSize(int) | 1048576 | Maximum total number of bytes to reserve for all cached resources. |
Note
It is implementation specific whether option is supported or not. Some cache options may not be used.
Clearing Cache
IAsset.Reload() clears caches and reloads assets from their configured sources.
// Create asset
var source = new Dictionary<string, string> { { "Culture:en:Key:hello", "Hello World!" } };
IAsset asset = new StringAsset(source, LineFormat.Parameters);
// Cache it
asset = asset.CreateCache();
// Issue a request which will be cached.
ILine key = new LineRoot().Key("hello");
IString value = asset.GetLine( key.Culture("en") ).GetString();
Console.WriteLine(value);
// Clear cache
asset.Reload();
Links
- IAssetComposition
- AssetComposition
- IAssetBuilder
- IAssetSource
- AssetBuilder
- AssetSource Passes IAsset to to builder.
- AssetCacheSource Adds cache to the built asset.
- ResourceManagerStringLocalizerAsset Adapts location of .resources file to IAsset.
- ResourceManagerStringLocalizerAssetSource Adapts location of .resources file to IAssetSource.
- IAssetCache
- AssetCache
IStringAsset
StringAsset is language string container. Asset is populated from different IEnumeration sources, which become effective when Load() is called.
The default way is to add a reader IEnumerable<ILine>.
var source = new List<ILine> {
LineAppender.Default.Type("MyController").Key("hello").Format("Hello World!"),
LineAppender.Default.Type("MyController").Key("hello").Culture("en").Format("Hello World!"),
LineAppender.Default.Type("MyController").Key("hello").Culture("de").Format("Hallo Welt!")
};
// Keys can be filtered
ILine filterKey = LineAppender.Default.Culture("de");
IAsset asset = new StringAsset().Add(source, "{Culture:}[Type:][Key]").Load();
foreach (var _key in asset.GetLines(filterKey))
Console.WriteLine(_key.Print(LineFormat.ParametersInclString));
Some source have keys as strings that cannot be parsed into a structured key. These assets can be added as .Add(IEnumerable<KeyValuePair<string, string>>, ILineFormat).
An instance of ILineFormatPrinter must be provided to convert requesting keys to strings that can used to match the key in the source asset. These values use CSharpFormat string format.
// Create localization source
var source = new Dictionary<string, string> {
{ "MyController:hello", "Hello World!" },
{ "en:MyController:hello", "Hello World!" },
{ "de:MyController:hello", "Hallo Welt!" }
};
// Create asset with string source
IAsset asset = new StringAsset().Add(source, "{Culture:}[Type:][Key]").Load();
StringAsset can import key-string pairs as well. .Add(IEnumerable<KeyValuePair<ILine, string>>, ILineFormat keyPolicy) adds language string source with ILine based keys.
// Create localization source
var source = new Dictionary<ILine, string> {
{ new LineRoot().Type("MyController").Key("hello"), "Hello World!" },
{ new LineRoot().Type("MyController").Key("hello").Culture("en"), "Hello World!" },
{ new LineRoot().Type("MyController").Key("hello").Culture("de"), "Hallo Welt!" }
};
// Create asset with string source
IAsset asset = new StringAsset().Add(source).Load();
Keys can be enumerated with GetAllKeys().
// Extract all keys
foreach (var _key in asset.GetUnformedLines(null))
Console.WriteLine(_key);
ILine
ILine is a set of interfaces for broad variety of features. Lines can carry hints, key references and strings and binary resources. They can be implemented with one class, but are are typically used as compositions of smaller classes that form linked lists.
ILine key = LineRoot.Global.PluralRules("Unicode.CLDR35").Key("Key").Format("Hello, {0}");
Or constructed to span a tree structure (trie).
ILineRoot root = new LineRoot();
ILine hint1 = root.PluralRules("Unicode.CLDR35");
ILine section1 = hint1.Section("Section2");
ILine section1_1 = hint1.Section("Section1.1");
ILine key1_1_1 = section1_1.Key("Key1");
ILine key1_1_2 = section1_1.Key("Key2");
ILine value1_1_1 = key1_1_1.Format("Hello, {0}");
// ...
Parts
.Asset(IAsset) adds extra asset as line part.
IAsset resourceAsset = new ResourceDictionary( new Dictionary<ILine, byte[]>() );
ILine line = LineRoot.Global.Asset(resourceAsset);
.Logger(ILogger) adds logger as line part.
ILine line = LineRoot.Global.Logger(Console.Out, LineStatusSeverity.Ok);
.CulturePolicy(ICulturePolicy) adds a culture policy that determines which culture is active in a given execution context.
ICulturePolicy culturePolicy = new CulturePolicy().SetToCurrentCulture();
ILine line = LineRoot.Global.CulturePolicy(culturePolicy);
Hints
Hints are line parts that can be appended from localization file as well as from ILine.
Hints.ini
[PluralRules:Unicode.CLDR35]
Key:Error:FormatProvider:docs.CustomFormat,docs = Error, (Date = {0:DATE})
Key:Ok:StringFormat:Lexical.Localization.StringFormat.TextFormat,Lexical.Localization = OK {C# format is not in use here}.
.StringFormat(IStringFormat) and .StringFormat(string) add a string format, that determines the way the consequtive "String" parameters are parsed.
ILine line1 = LineRoot.Global.StringFormat(TextFormat.Default).String("Text");
ILine line2 = LineRoot.Global.StringFormat("Lexical.Localization.StringFormat.TextFormat,Lexical.Localization")
.String("Text");
.PluralRules(IPluralRules) and .PluralRules(string) add plural rules that determine how plurality are used in further line parts.
IPluralRules pluralRules = PluralRulesResolver.Default.Resolve("Unicode.CLDR35");
ILine line1 = LineRoot.Global.PluralRules(pluralRules);
ILine line2 = LineRoot.Global.PluralRules("Unicode.CLDR35");
ILine line3 = LineRoot.Global.PluralRules("[Category=cardinal,Case=one]n=1[Category=cardinal,Case=other]true");
.FormatProvider(IFormatProvider) and .FormatProvider(string) add a custom format provider that provides special format handling.
IFormatProvider customFormat = new CustomFormat();
ILine line1 = LineRoot.Global.FormatProvider(customFormat).Format("{0:DATE}").Value(DateTime.Now);
ILine line2 = LineRoot.Global.FormatProvider("docs.CustomFormat,docs").Format("{0:DATE}").Value(DateTime.Now);
public class CustomFormat : IFormatProvider, ICustomFormatter
{
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (format == "DATE" && arg is DateTime time)
{
return time.Date.ToString();
}
return null;
}
public object GetFormat(Type formatType)
=> formatType == typeof(ICustomFormatter) ? this : default;
}
.StringResolver(IStringResolver) adds IStringResolver as line part.
ResolveSource[] resolveSequence =
new ResolveSource[] { ResolveSource.Inline, ResolveSource.Asset, ResolveSource.Line };
IStringResolver stringResolver = new StringResolver(Resolvers.Default, resolveSequence);
ILine line = LineRoot.Global.StringResolver(stringResolver);
.StringResolver(string) adds assembly qualified class name to IStringResolver.
ILine line = LineRoot.Global.StringResolver("Lexical.Localization.StringFormat.StringResolver");
.BinaryResolver(IBinaryResolver) adds IBinaryResolver as line part.
ResolveSource[] resolveSequence =
new ResolveSource[] { ResolveSource.Inline, ResolveSource.Asset, ResolveSource.Line };
IBinaryResolver BinaryResolver = new BinaryResolver(Resolvers.Default, resolveSequence);
ILine line = LineRoot.Global.BinaryResolver(BinaryResolver);
.BinaryResolver(string) adds assembly qualified class name to IBinaryResolver.
ILine line = LineRoot.Global.BinaryResolver("Lexical.Localization.Binary.BinaryResolver");
Canonically compared keys
Key parts give ILines hash-equal comparison information. Key parts are used to match the line to a corresponding line of another culture in localization files.
Canonically compared key parts are compared so that the position of occurance is relevant.
.Key(string) appends "Key" key part.
ILine line = LineRoot.Global.Key("Ok");
.Section(string) appends "Section" key part.
ILine line = LineRoot.Global.Section("Resources").Key("Ok");
.Location(string) appends "Location" key part.
ILine line = LineRoot.Global.Location(@"c:\dir");
.BaseName(string) appends "BaseName" key part.
ILine line = LineRoot.Global.BaseName("docs.Resources");
Non-canonically compared keys
Non-canonically compared key parts are compared so that the position doesn't matter. The first occurance of each type is considered effective, rest are ignored.
.Assembly(Assembly) and .Assembly(string) append "Assembly" key.
Assembly asm = typeof(ILine_Examples).Assembly;
ILine line1 = LineRoot.Global.Assembly(asm);
ILine line2 = LineRoot.Global.Assembly("docs");
.Culture(CultureInfo) and .Culture(string) append "Culture" key.
CultureInfo culture = CultureInfo.GetCultureInfo("en");
ILine line1 = LineRoot.Global.Culture(culture);
ILine line2 = LineRoot.Global.Culture("en");
.Type<T>(), .Type(Type) and .Type(string) append "Type" key.
ILine line1 = LineRoot.Global.Type<ILine_Examples>();
ILine line2 = LineRoot.Global.Type(typeof(ILine_Examples));
Strings
.String(IString) appends preparsed default string value.
IString str = CSharpFormat.Default.Parse("ErrorCode = 0x{0:X8}");
ILine line = LineRoot.Global.Key("Error").String(str);
.String(string) appends "String" hint. This needs preceding "StringFormat" part in order to determine the way to parse. If "StringFormat" is not provided, then C# format is used as default.
ILine line = LineRoot.Global.Key("Error").StringFormat(CSharpFormat.Default).String("ErrorCode = 0x{0:X8}");
.Format(string) appends C# String formulation value.
ILine line = LineRoot.Global.Key("Error").Format("ErrorCode = 0x{0:X8}");
.Format($interpolated_string) appends formulation and value using string interpolation.
int code = 0x100;
ILine line = LineRoot.Global.Key("Error").Format($"ErrorCode = 0x{code:X8}");
.Text(string) appends plain text "String" value.
ILine line = LineRoot.Global.Key("Hello").Text("Hello World");
.ResolveString() resolves the string in current executing context. The result struct is LineString.
ILine line = LineRoot.Global.Key("Error").Format("ErrorCode={0}").Value(0x100);
LineString result = line.ResolveString();
Inlining
Code can be automatically scanned for inlined strings and exported to localization files.
They can be used as templates for further translation process.
This way the templates don't need to be manually updated as the code evolves.
.Inline(string subkey, string text) appends an inlined sub-line.
ILine line = LineRoot.Global.Section("Section").Key("Success")
.Format("Success") // Add inlining to the root culture ""
.Inline("Culture:en", "Success") // Add inlining to culture "en"
.Inline("Culture:fi", "Onnistui") // Add inlining to culture "fi"
.Inline("Culture:sv", "Det funkar"); // Add inlining to culture "sv"
.en(string) appends inlined value for that culture "en".
ILine line = LineRoot.Global.Section("Section").Key("Success")
.Format("Success") // Add inlining to the root culture ""
.en("Success") // Add inlining to culture "en"
.fi("Onnistui") // Add inlining to culture "fi"
.sv("Det funkar"); // Add inlining to culture "sv"
It's recommended to put inlined lines to variables for better performance. Inline allocates a Dictionary internally.
class MyController__
{
static ILine localization = LineRoot.Global.Assembly("docs").Type<MyControllerB>();
static ILine Success = localization.Key("Success").Format("Success").sv("Det funkar").fi("Onnistui");
public string Do()
{
return Success.ToString();
}
}
Enumerations
Enumerables can be localized just as any other type.
[Flags]
enum CarFeature
{
// Fuel Type
Electric = 0x0001,
Petrol = 0x0002,
NaturalGas = 0x0003,
// Door count
TwoDoors = 0x0010,
FourDoors = 0x0020,
FiveDoors = 0x0030,
// Color
Red = 0x0100,
Black = 0x0200,
White = 0x0300,
}
.Assembly<T>() and .Type<T>() appends "Assembly" and "Type" keys to refer to an enumeration type.
ILine carFeature = LineRoot.Global.Assembly("docs").Type<CarFeature>().Format("{0}");
.InlineEnum<T>() inlines every case of enum for culture "". It applies [Description] attribute when available.
ILine carFeature = LineRoot.Global.Assembly("docs").Type<CarFeature>().InlineEnum<CarFeature>().Format("{0}");
Enum localization strings can be supplied from files. (See CarFeatures.ini)
IAssetSource assetSource = LineReaderMap.Default.FileAssetSource(@"ILine\CarFeature.ini");
LineRoot.Builder.AddSource(assetSource).Build();
A single enum case can be matched with .Key(case).
Console.WriteLine(carFeature.Key(CarFeature.Petrol));
Console.WriteLine(carFeature.Key(CarFeature.Petrol).Culture("fi"));
Console.WriteLine(carFeature.Key(CarFeature.Petrol).Culture("sv"));
The result of the example above.
Petrol
Bensiini
Bensin
If enum value contains multiple cases, it must be resolved with inside a formulated string. Localization strings for the refered enum value are matched against keys "Assembly:asm:Type:enumtype:Key:case" from the IAsset. Inlined strings only apply with ILine instance that contains the inlinings.
CarFeature features = CarFeature.Petrol | CarFeature.FiveDoors | CarFeature.Black;
Console.WriteLine(carFeature.Value(features));
The result of the example above.
Petrol, FiveDoors, Black
Bensiini, Viisiovinen, Musta
Bensin, Femdörras, Svart
.InlineEnum(enumCase, culture, text) inlines culture specific texts to the ILine reference.
ILine carFeature = LineRoot.Global.Assembly("docs").Type<CarFeature>()
.InlineEnum<CarFeature>()
.InlineEnum(CarFeature.Electric, "fi", "Sähkö")
.InlineEnum(CarFeature.Petrol, "fi", "Bensiini")
.InlineEnum(CarFeature.NaturalGas, "fi", "Maakaasu")
.InlineEnum(CarFeature.TwoDoors, "fi", "Kaksiovinen")
.InlineEnum(CarFeature.FourDoors, "fi", "Neliovinen")
.InlineEnum(CarFeature.FiveDoors, "fi", "Viisiovinen")
.InlineEnum(CarFeature.Red, "fi", "Punainen")
.InlineEnum(CarFeature.Black, "fi", "Musta")
.InlineEnum(CarFeature.White, "fi", "Valkoinen")
.Format("{0}");
If placeholder format is "{enum:|}" then the printed string uses "|" as separator. "{enum: |}" prints with " | ".
Console.WriteLine(carFeature.Formulate($"{CarFeature.Petrol | CarFeature.Black:|}").Culture("fi"));
Console.WriteLine(carFeature.Formulate($"{CarFeature.Petrol | CarFeature.Black: |}").Culture("fi"));
Bensiini|Musta
Bensiini | Musta
Inlines placed in an ILine instance are applicable in another ILine instances, if the .Value() is supplied as ILine with inlinings and not as Enum.
ILine carFeature = LineRoot.Global.Assembly("docs").Type<CarFeature>().InlineEnum<CarFeature>()
.InlineEnum(CarFeature.Electric, "de", "Elektroauto")
.InlineEnum(CarFeature.Petrol, "de", "Benzinwagen")
.InlineEnum(CarFeature.NaturalGas, "de", "Erdgasauto")
.InlineEnum(CarFeature.TwoDoors, "de", "Zweitürig")
.InlineEnum(CarFeature.FourDoors, "de", "Viertürig")
.InlineEnum(CarFeature.FiveDoors, "de", "Fünftürige")
.InlineEnum(CarFeature.Red, "de", "Rot")
.InlineEnum(CarFeature.Black, "de", "Schwartz")
.InlineEnum(CarFeature.White, "de", "Weiß")
.Format("{0}");
ILine message = LineRoot.Global.Assembly("docs").Type("MyClass").Key("Msg")
.Format("Your car has following features: {0}")
.de("Ihr Auto hat folgende Eigenschaften: {0}");
CarFeature features = CarFeature.Petrol | CarFeature.Red | CarFeature.TwoDoors;
// Inlined enum strings don't work as Enum (unless tool is used)
Console.WriteLine(message.Value(features).Culture("de"));
// But works when ILine reference is used.
Console.WriteLine(message.Value(carFeature.Value(features)).Culture("de"));
Ihr Auto hat folgende Eigenschaften: Petrol, TwoDoors, Red
Ihr Auto hat folgende Eigenschaften: Benzinwagen, Zweitürig, Rot
However, if Lexical.Localization.Tool is used in the build process, then inlined strings are available as enums too. Tool picks up the inlined strings and places them into localization file.
Ihr Auto hat folgende Eigenschaften: Benzinwagen, Zweitürig, Rot
Ihr Auto hat folgende Eigenschaften: Benzinwagen, Zweitürig, Rot
Files that supply enumeration localization should use key in format of "Assembly:asm:Type:enumtype:Key:case".
CarFeatures.ini example file
[Assembly:docs:Type:docs.CarFeature:Culture:sv]
// Fuel Type
Key:Electric = El
Key:Petrol = Bensin
Key:NaturalGas = Naturgas
// Door count
Key:TwoDoors = Tvådörras
Key:FourDoors = Fyrdörras
Key:FiveDoors = Femdörras
// Color
Key:Red = Röd
Key:Black = Svart
Key:White = Vit
[Culture:sv]
Assembly:docs:Type:MyClass:Key:Msg = Din bil har: {0}
[Assembly:docs:Type:docs.CarFeature:Culture:fi]
// Fuel Type
Key:Electric = Sähkö
Key:Petrol = Bensiini
Key:NaturalGas = Maakaasu
// Door count
Key:TwoDoors = Kaksiovinen
Key:FourDoors = Neliovinen
Key:FiveDoors = Viisiovinen
// Color
Key:Red = Punainen
Key:Black = Musta
Key:White = Valkoinen
[Culture:fi]
Assembly:docs:Type:MyClass:Key:Msg = Autosi ominaisuudet: {0}
Resources
.ResolveBytes() resolves the line to bytes in the current executing context. The result struct is LineResourceBytes.
ILine line = LineRoot.Global.Key("Error").Binary(new byte[] { 1, 2, 3 });
LineBinaryBytes result = line.ResolveBytes();
.ResolveStream() resolves the line to string in the current executing context. The result struct is LineResourceStream.
ILine line = LineRoot.Global.Key("Error").Binary(new byte[] { 1, 2, 3 });
using (LineBinaryStream result = line.ResolveStream())
{
}
Use in classes
If class is designed to support dependency injection without string localizers, the constructors should take in argument ILine<T> and possibly ILineRoot. See more in Best Practices. Constructor argument ILine<T> helps the Dependency Injection to assign the localization so that it is scoped in to correct typesection.
class MyController
{
ILine localization;
public MyController(ILine<MyController> localization)
{
this.localization = localization;
}
public MyController(ILineRoot localizationRoot)
{
this.localization = localizationRoot.Assembly("docs").Type<MyController>();
}
public void Do()
{
string str = localization.Key("Success").en("Success").fi("Onnistui").ToString();
}
}
If class is designed to use static instance and without dependency injection, localization reference can be acquired from LineRoot.
class MyControllerB
{
static ILine localization = LineRoot.Global.Assembly("docs").Type<MyControllerB>();
public void Do()
{
string str = localization.Key("Success").en("Success").fi("Onnistui").ToString();
}
}
ILineFactory
ILineFactory constructs ILine parts.
csharp
/// <summary>
/// Line factory can append new parts to <see cref="ILine"/>s.
/// Appended parts are typically immutable, and form a linked list or a trie.
/// </summary>
public interface ILineFactory
{
}
/// <summary>
/// Policy for <see cref="ILineFactoryCollection"/>.
/// </summary>
public enum LineFactoryAddPolicy
{
/// <summary>
/// If appender with same key exists, throw <see cref="InvalidOperationException"/>.
/// </summary>
ThrowIfExists,
/// <summary>
/// If appender with same key exists, overwrite the previous appender.
/// </summary>
OverwriteIfExists,
/// <summary>
/// If appender with same key exists, ignore the new appender. Don't throw.
/// </summary>
IgnoreIfExists
}
/// <summary>
/// Collection of line factories
/// </summary>
public interface ILineFactoryCollection
{
/// <summary>
/// Add line factory to collection.
/// </summary>
/// <param name="lineFactory"></param>
/// <param name="policy"></param>
ILineFactoryCollection Add(ILineFactory lineFactory, LineFactoryAddPolicy policy = LineFactoryAddPolicy.ThrowIfExists);
}
/// <summary>
/// Enumerable of line factory's component factories.
/// </summary>
public interface ILineFactoryEnumerable : IEnumerable<ILineFactory>
{
}
/// <summary>
/// Zero argument line factory.
/// </summary>
/// <typeparam name="Intf">the interface type of the line part that can be appended </typeparam>
public interface ILineFactory<Intf> : ILineFactory where Intf : ILine
{
/// <summary>
/// Append new <see cref="ILine"/> to <paramref name="previous"/>.
/// </summary>
/// <param name="factory"></param>
/// <param name="previous"></param>
/// <param name="line">create output</param>
/// <returns>true if part was created</returns>
/// <exception cref="LineException">If append failed due to unexpected reasons</exception>
bool TryCreate(ILineFactory factory, ILine previous, out Intf line);
}
/// <summary>
/// One argument line part factory.
/// </summary>
/// <typeparam name="Intf">the part type</typeparam>
/// <typeparam name="A0"></typeparam>
public interface ILineFactory<Intf, A0> : ILineFactory where Intf : ILine
{
/// <summary>
/// Append new <see cref="ILine"/> to <paramref name="previous"/>.
/// </summary>
/// <param name="factory"></param>
/// <param name="previous"></param>
/// <param name="a0"></param>
/// <param name="line">create output</param>
/// <returns>true if part was created</returns>
/// <exception cref="LineException">If append failed due to unexpected reason</exception>
bool TryCreate(ILineFactory factory, ILine previous, A0 a0, out Intf line);
}
/// <summary>
/// Two argument line part factory.
/// </summary>
/// <typeparam name="Intf">the part type</typeparam>
/// <typeparam name="A0"></typeparam>
/// <typeparam name="A1"></typeparam>
public interface ILineFactory<Intf, A0, A1> : ILineFactory where Intf : ILine
{
/// <summary>
/// Append new <see cref="ILine"/> to <paramref name="previous"/>.
/// </summary>
/// <param name="factory"></param>
/// <param name="previous"></param>
/// <param name="a0"></param>
/// <param name="a1"></param>
/// <param name="line">create output</param>
/// <returns>true if part was created</returns>
/// <exception cref="LineException">If append failed due to unexpected reason</exception>
bool TryCreate(ILineFactory factory, ILine previous, A0 a0, A1 a1, out Intf line);
}
/// <summary>
/// Three argument line part factory.
/// </summary>
/// <typeparam name="Intf">the part type</typeparam>
/// <typeparam name="A0"></typeparam>
/// <typeparam name="A1"></typeparam>
/// <typeparam name="A2"></typeparam>
public interface ILineFactory<Intf, A0, A1, A2> : ILineFactory where Intf : ILine
{
/// <summary>
/// Append new <see cref="ILine"/> to <paramref name="previous"/>.
/// </summary>
/// <param name="factory"></param>
/// <param name="previous"></param>
/// <param name="a0"></param>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <param name="line">create output</param>
/// <returns>true if part was created</returns>
/// <exception cref="LineException">If append failed due to unexpected reason</exception>
bool TryCreate(ILineFactory factory, ILine previous, A0 a0, A1 a1, A2 a2, out Intf line);
}
/// <summary>
/// Adapts to different <see cref="ILineFactory"/> types.
/// </summary>
public interface ILineFactoryCastable : ILineFactory
{
/// <summary>
/// Get factory for part type <typeparamref name="Intf"/>.
/// </summary>
/// <typeparam name="Intf"></typeparam>
/// <returns>factory or null</returns>
ILineFactory<Intf> Cast<Intf>() where Intf : ILine;
/// <summary>
/// Get factory for part type <typeparamref name="Intf"/>.
/// </summary>
/// <typeparam name="Intf"></typeparam>
/// <typeparam name="A0">argument 0 type</typeparam>
/// <returns>factory or null</returns>
ILineFactory<Intf, A0> Cast<Intf, A0>() where Intf : ILine;
/// <summary>
/// Get factory for part type <typeparamref name="Intf"/>.
/// </summary>
/// <typeparam name="Intf"></typeparam>
/// <typeparam name="A0">argument 0 type</typeparam>
/// <typeparam name="A1">argument 1 type</typeparam>
/// <returns>factory or null</returns>
ILineFactory<Intf, A0, A1> Cast<Intf, A0, A1>() where Intf : ILine;
/// <summary>
/// Get factory for part type <typeparamref name="Intf"/>.
/// </summary>
/// <typeparam name="Intf"></typeparam>
/// <typeparam name="A0">argument 0 type</typeparam>
/// <typeparam name="A1">argument 1 type</typeparam>
/// <typeparam name="A2">argument 2 type</typeparam>
/// <returns>factory or null</returns>
ILineFactory<Intf, A0, A1, A2> Cast<Intf, A0, A1, A2>() where Intf : ILine;
}
/// <summary>
/// Appender can append new <see cref="ILine"/>s.
/// </summary>
public interface ILineFactoryByArgument : ILineFactory
{
/// <summary>
/// Create line (part) with <paramref name="arguments"/>.
/// </summary>
/// <param name="factory"></param>
/// <param name="previous"></param>
/// <param name="arguments">Line construction arguments</param>
/// <param name="line">create output</param>
/// <returns>true if part was created</returns>
/// <exception cref="LineException">If append failed due to unexpected reason</exception>
bool TryCreate(ILineFactory factory, ILine previous, ILineArgument arguments, out ILine line);
}
/// <summary>
/// Line factory that has an assigned resolver.
/// </summary>
public interface ILineFactoryResolver : ILineFactory
{
/// <summary>
/// (optional) Type and parameter resolver
/// </summary>
IResolver Resolver { get; set; }
}
/// <summary>
/// Line factory that has parameter infos assigned
/// </summary>
public interface ILineFactoryParameterInfos : ILineFactory
{
/// <summary>
/// (optional) Associated parameter infos.
/// </summary>
IParameterInfos ParameterInfos { get; set; }
}
ILineAppendable is interface ILine parts that can be appended.
csharp
/// <summary>
/// A line where new <see cref="ILine"/> can be appended.
/// </summary>
public interface ILineAppendable : ILine
{
/// <summary>
/// (Optional) part constructor. If null, the caller should follow to <see cref="ILinePart.PreviousPart"/> for appender.
/// </summary>
ILineFactory Appender { get; set; }
}
Implementation | Description |
---|---|
LineAppender.Default | Resolves parameter values into instances. |
LineAppender.NonResolving | Doesn't resolve parameter values into instances. |
StringLocalizerAppender.Default | Resolves parameter values into instances. |
StringLocalizerAppender.NonResolving | Doesn't resolve parameter values into instances. |
LineFactoryComposition | Collection of component ILineFactory parts. |
ILineFactory is used for appending and constructing ILine parts.
The two main factories are LineAppender.NonResolving and LineAppender.Default.
They produce lines that are equally usable, but with differences in terms of performance at
usage-time and at construction-time.
LineAppender.NonResolving appends parts to ILine as string based parameters. It doesn't resolve parameters into respective instances at instantion time. The user of the ILine, must evaluate the parameters into respective instances. This is most suitable for constructing hash-equals compatible keys.
ILine key = LineAppender.NonResolving.Type("ILineFactory_Examples").Key("Hello");
IString str = asset.GetLine(key).GetString();
LineAppender.Default appends parts to ILine and resolves values into respective instances. For example, calling .PluralRules(string) causes the rules to be constructed and cached into the IResolver that is associated with the ILineFactory. This is most suitable for constructing lines that are used by assets, as the referenced instances are already available.
ILine localization = LineAppender.Default
.PluralRules("[Category=cardinal,Case=one]n=1[Category=cardinal,Case=other]true")
.Assembly("docs")
.Culture("en")
.Type<ILineFactory_Examples>();
List<ILine> lines = new List<ILine>
{
localization.Key("OK").Text("Successful"),
localization.Key("Error").Format("Failed (ErrorCode={0})")
};
IAsset asset = new StringAsset().Add(lines);
ILines are associated with an ILineFactory. This factory can be replaced in middle of line with .SetAppender(ILineFactory).
IStringLocalizer localizer =
LineRoot.Global.Type("Hello").SetAppender(StringLocalizerAppender.Default).Key("Ok")
as IStringLocalizer;
New custom appenders can be added to line with .AddAppender(ILineFactory). Note that this makes a whole new copy of the previous ILineFactory.
ILine line = LineRoot.Global.AddAppender(new MyAppender()).Key("Ok");
class MyAppender : ILineFactory<ILineCanonicalKey, string, string>
{
public bool TryCreate(
ILineFactory factory,
ILine previous,
string parameterName,
string parameterValue,
out ILineCanonicalKey line)
{
line = new LineCanonicalKey(factory, previous, parameterName, parameterValue);
return true;
}
}
ILineRoot
ILineRoot is an interface for root implementations. Root is the place where asset (the localization provider) is tied to key (localization consumer).
LineRoot is the default implementation. It's constructed with an asset and a culture policy.
// Create localization source
var source = new Dictionary<string, string> {
{ "Culture:en:Type:MyController:Key:hello", "Hello World!" }
};
// Create asset
IAsset asset = new StringAsset(source, LineFormat.Parameters);
// Create culture policy
ICulturePolicy culturePolicy = new CulturePolicy();
// Create root
ILineRoot root = new LineRoot(asset, culturePolicy);
Further keys are constructed from root.
// Construct key
ILine key = root.Type("MyController").Key("Hello");
Now that key is associated with an asset and a culture provider, it can provide strings and resources.
// Set active culture for this root
(root.FindCulturePolicy() as ICulturePolicyAssignable).SetCultures("en", "");
// Provide string
string str = key.ToString();
Note, that root is not mandatory, keys can be constructed with null as previous key. These keys cannot be used as providers, only as references.
// Create reference
ILine key = LineAppender.NonResolving.Section("Section").Key("Key");
// Retreieve with reference
IString str = asset.GetLine(key).GetString();
String Localizer
StringLocalizerRoot is an alternative root implementation. Every key, that is constructed from this class, implements localization interfaces IStringLocalizer and IStringLocalizerFactory.
StringLocalizerRoot is constructed with an asset and a culture policy, just as LineRoot.
// Create localization source
var source = new List<ILine> {
LineFormat.Parameters.Parse("Culture:en:Type:MyController:Key:hello").Format("Hello World!")
};
// Create asset
IAsset asset = new StringAsset(source);
// Create culture policy
ICulturePolicy culturePolicy = new CulturePolicy();
// Create root
ILineRoot root = new StringLocalizerRoot(asset, culturePolicy);
Keys can be type-casted to IStringLocalizer.
// Assign as IStringLocalizer, use "MyController" as root.
IStringLocalizer stringLocalizer = root.Section("MyController").AsStringLocalizer();
And to IStringLocalizerFactory.
// Assign as IStringLocalizerFactory
IStringLocalizerFactory stringLocalizerFactory = root as IStringLocalizerFactory;
// Adapt to IStringLocalizer
IStringLocalizer<MyController> stringLocalizer2 =
stringLocalizerFactory.Create(typeof(MyController))
as IStringLocalizer<MyController>;
Key can be assigned for a type .Type(Type) and then casted to IStringLocalizer<Type>.
// Assign to IStringLocalizer for the class MyController
IStringLocalizer<MyController> stringLocalizer =
root.Type(typeof(MyController)).AsStringLocalizer<MyController>();
Also after type casting to IStringLocalizerFactory with .Create(Type).
// Assign as IStringLocalizerFactory
IStringLocalizerFactory stringLocalizerFactory = root as IStringLocalizerFactory;
// Create IStringLocalizer for the class MyController
IStringLocalizer<MyController> stringLocalizer =
stringLocalizerFactory.Create(typeof(MyController)) as IStringLocalizer<MyController>;
Culture can be locked in with .Culture(string).
// Create IStringLocalizer and assign culture
IStringLocalizer stringLocalizer =
root.Culture("en").Type<MyController>().AsStringLocalizer();
And also after type casting to IStringLocalizer with .WithCulture(CultureInfo).
// Assign as IStringLocalizerFactory
IStringLocalizerFactory stringLocalizerFactory = root as IStringLocalizerFactory;
// Create IStringLocalizer and assign culture
IStringLocalizer stringLocalizer = stringLocalizerFactory.Create(typeof(MyController))
.WithCulture(CultureInfo.GetCultureInfo("en"));
Global static root
Localized strings can be considered as constants because they are used the same way as regular strings.
Lexical.Localization introduces a global static root LineRoot.Global.
// Create key from global root
ILine key = LineRoot.Global.Type("MyController").Key("Hello");
Assets are added to the global root with LineRoot.Builder.
// Create localization source
var source = new Dictionary<string, string> {
{ "Culture:en:Type:MyController:Key:hello", "Hello World!" }
};
// Create asset
IAsset asset = new StringAsset(source, LineFormat.Parameters);
// Assets are added to global static builder. It must be (re-)built after adding.
LineRoot.Builder.AddAsset(asset).Build();
If assets are initialized in concurrent environment then please lock with LineRoot.Builder.
// If ran in multi-threaded initialization, lock to LineRoot.Builder.
lock (LineRoot.Builder) LineRoot.Builder.AddAsset(asset).Build();
StringLocalizerRoot is the same root as LineRoot, but has extra feature of implementing IStringLocalizer and IStringLocalizerFactory. The calling assembly, however, needs to import NuGet Microsoft.Extensions.Localization.Abstractions.
// StringLocalizerRoot is root for IStringLocalizer interoperability
IStringLocalizerFactory stringLocalizerFactory = StringLocalizerRoot.Global;
They share the same assets, and the root instances are interchangeable. Assets can be added to either root.
// LineRoot and StringLocalizerRoot are interchangeable. They share the same asset(s).
LineRoot.Builder.AddAsset(asset).Build();
IStringLocalizer<MyController> stringLocalizer = StringLocalizerRoot.Global.Type<MyController>().AsStringLocalizer<MyController>();
LineRoot.GlobalDynamic returns dynamic instance for the static root.
// Dynamic instance is acquired with LineRoot.GlobalDynamic
dynamic key_ = LineRoot.GlobalDynamic.Section("Section").Key("Key");
Links
ILineFormat
ILineFormat is root interface for ILine and String converters.
csharp
/// <summary>
/// Line format makes conversions between <see cref="ILine"/> and <see cref="String"/>.
///
/// Class that implements to this interface should implement one or both of the following interfaces:
/// <list type="bullet">
/// <item><see cref="ILineFormatPrinter"/></item>
/// <item><see cref="ILinePattern"/></item>
/// </list>
///
/// The decision on what types are instantiated is a configuration decision of the implementing class.
/// </summary>
public interface ILineFormat
{
}
ILineFormatPrinter prints ILines as Strings.
csharp
/// <summary>
/// Converts <see cref="ILine"/> to string.
/// </summary>
public interface ILineFormatPrinter : ILineFormat
{
/// <summary>
/// Print <paramref name="line"/> as <see cref="String"/>.
///
/// The decision on what types are instantiated is a configuration decision of the implementing class.
/// </summary>
/// <param name="line"></param>
/// <returns>full name string</returns>
string Print(ILine line);
}
ILineFormatParser parses Strings into ILine.
csharp
/// <summary>
/// Parses string into <see cref="ILine"/>.
/// </summary>
public interface ILineFormatParser : ILineFormat
{
/// <summary>
/// Parse string into <see cref="ILine"/>.
///
/// The decision on what types are instantiated is a configuration decision of the implementing class.
/// </summary>
/// <param name="str">key as string</param>
/// <returns>Arguments that can be used for constructing or appending to a line</returns>
/// <exception cref="LineException">If parse failed</exception>
IEnumerable<ILineArgument> ParseArgs(string str);
/// <summary>
/// Parse string into key.
/// </summary>
/// <param name="str"></param>
/// <param name="args">Arguments that can be used for constructing or appending to a line</param>
/// <returns>true if parse was successful</returns>
bool TryParseArgs(string str, out IEnumerable<ILineArgument> args);
}
Class | ILineFormatPrinter | ILineFormatParser |
---|---|---|
LineFormat | ☑ | ☑ |
LinePattern | ☑ | ☑ |
LineParameterPrinter | ☑ | ☐ |
LineFormat
LineFormat is an ILineFormat class that prints and parses keys into strings using the following notation.
parameterName:parameterValue:parameterName:parameterValue:...
Keys are converted to strings.
ILine key = LineAppender.NonResolving.Type("MyController").Key("Success").Culture("en");
string str = LineFormat.Parameters.Print(key);
And strings parsed to keys.
string str = @"Culture:en:Type:MyController:Key:Ok";
ILine key = LineFormat.Parameters.Parse(str, null, LineAppender.NonResolving);
A specific root can be used from which the constructed key is appended from.
string str = @"Culture:en:Type:MyController:Key:Ok";
ILine root = new StringLocalizerRoot();
ILine key = LineFormat.Parameters.Parse(str, root);
Policy uses the following escape rules.
Sequence | Meaning |
---|---|
\: | Colon |
\t | Tab |
\r | Carriage return |
\n | New line |
\xhh | Unicode 8bit |
\uhhhh | Unicode 16bit (surrogate) |
\Uhhhhhhhh | Unicode 32bit |
Example of escaped key "Success\:Plural".
string str = @"Key:Success\:Plural";
ILine key = LineFormat.Parameters.Parse(str, null, LineAppender.NonResolving);
Instance | Description |
---|---|
LineFormat.Key | Prints and parses effective key of ILine. |
LineFormat.Line | Prints and parses whole ILine. |
LineFormat.Parameters | Prints and parses the parameters of ILine, excluding "String" parameter |
LineFormat.ParametersInclString | Prints and parses every parameter of ILine |
LinePattern
ILinePattern is interface for name patterns.
csharp
/// <summary>
/// A name pattern, akin to regular expression, that can be matched against filenames and <see cref="ILine"/> instances.
/// Is a sequence of parameter and text parts.
///
/// Parameter parts:
/// {Culture} - Matches to key.Culture("en")
/// {Assembly} - Matches to key.Assembly(asm).
/// {Resource} - Matches to key.Resource("xx").
/// {Type} - Matches to key.Type(type)
/// {Section} - Matches to key.Section("xx")
/// {Location} - Matches to key.Location("xx") and a physical folder, separator is '/'.
/// {anysection} - Matches to assembly, type and section.
/// {Key} - Matches to key key.Key("x")
///
/// Before and after the part pre- and postfix separator characters can be added:
/// {/Culture.}
///
/// Parts can be optional in curly braces {} and required in brackets [].
/// [Culture]
///
/// Part can be added multiple times
/// "{Location/}{Location/}{Location/}{Key}" - Matches to, from 0 to 3 occurances of Location(), e.g. key.Location("dir").Location("dir1");
///
/// If parts need to be matched out of order, then occurance index can be used "_number".
/// "{Location_2/}{Location_1/}{Location_0/}{Key}" - Matches to, from 0 to 3 occurances of Location, e.g. key.Location("dir").Location("dir1");
///
/// Suffix "_n" translates to five conscutive parts.
/// "[Location_n/]location.ini" translates to "[Location_0/]{Location_1/}{Location_2/}{Location_3/}{Location_4/}"
/// "[Location/]{Location_n/}location.ini" translates to "[Location_0/]{Location_1/}{Location_2/}{Location_3/}{Location_4/}{Location_5/}"
///
/// Regular expressions can be written between < and > characters to specify match criteria. \ escapes \, *, +, ?, |, {, [, (,), <, > ^, $,., #, and white space.
/// "{Section<[^:]*>.}"
///
/// Regular expressions can be used for greedy match when matching against filenames and embedded resources.
/// "{Assembly.}{Resource<.*>.}{Type.}{Section.}{Key}"
///
/// Examples:
/// "[Assembly.]Resources.localization{-Culture}.json"
/// "[Assembly.]Resources.{Type.}localization[-Culture].json"
/// "Assets/{Type/}localization{-Culture}.ini"
/// "Assets/{Assembly/}{Type/}{Section.}localization{-Culture}.ini"
/// "{Culture.}{Type.}{Section_0.}{Section_1.}{Section_2.}[Section_n]{.Key_0}{.Key_1}{.Key_n}"
///
/// </summary>
public interface ILinePattern : ILineFormat
{
/// <summary>
/// Pattern in string format
/// </summary>
string Pattern { get; }
/// <summary>
/// All parts of the pattern
/// </summary>
ILinePatternPart[] AllParts { get; }
/// <summary>
/// All parts that capture a part of string.
/// </summary>
ILinePatternPart[] CaptureParts { get; }
/// <summary>
/// Maps parts by identifier.
/// </summary>
IReadOnlyDictionary<string, ILinePatternPart> PartMap { get; }
/// <summary>
/// List of all parameter names
/// </summary>
string[] ParameterNames { get; }
/// <summary>
/// Maps parts by parameter identifier.
/// </summary>
IReadOnlyDictionary<string, ILinePatternPart[]> ParameterMap { get; }
/// <summary>
/// Match parameters from an object.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
ILinePatternMatch Match(ILine key);
/// <summary>
/// A regular expression pattern that captures same parts from a filename string.
/// </summary>
Regex Regex { get; }
}
/// <summary>
/// Part of a pattern.
/// </summary>
public interface ILinePatternPart
{
/// <summary>
/// Text that represents this part in pattern.
/// for "_n" part, the first part has "_n" in PatternText, and the rest have "".
/// </summary>
string PatternText { get; }
/// <summary>
/// Part identifier, unique in context of Pattern.CaptureParts.
/// The first occurance is the "ParameterName" as is, and succeeding have underscore and index "ParameterName_#" starting with index '1'.
/// </summary>
string Identifier { get; }
/// <summary>
/// Separator
/// </summary>
string PrefixSeparator { get; }
/// <summary>
/// Separator
/// </summary>
string PostfixSeparator { get; }
/// <summary>
/// Parameter identifier. Does not include occurance index, e.g. "_1".
/// </summary>
string ParameterName { get; }
/// <summary>
/// If set, then is non-matchable Text part.
/// </summary>
string Text { get; }
/// <summary>
/// Is part mandatory
/// </summary>
bool Required { get; }
/// <summary>
/// Index in <see cref="ILinePattern.AllParts"/>.
/// </summary>
int Index { get; }
/// <summary>
/// Index in <see cref="ILinePattern.CaptureParts"/>.
/// </summary>
int CaptureIndex { get; }
/// <summary>
/// The order of occurance to capture against.
///
/// As special case Int32.MaxValue means the last occurance "{.Section}"
///
/// For example "{.Section_0}" captures first occurance, and the part's OccuranceIndex = 0.
/// "{.Section}" captures the last occurance overriding possible ordered occurance if there is only one match.
/// </summary>
int OccuranceIndex { get; }
/// <summary>
/// Regex pattern for this part.
/// </summary>
Regex Regex { get; }
/// <summary>
/// Tests if text is match.
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
bool IsMatch(string text);
}
/// <summary>
/// Match result.
/// </summary>
public interface ILinePatternMatch : IReadOnlyDictionary<string, string>
{
/// <summary>
/// Associated patern.
/// </summary>
ILinePattern Pattern { get; }
/// <summary>
/// Resolved part values. Corresponds to <see cref="ILinePattern.CaptureParts"/>.
/// </summary>
string[] PartValues { get; }
/// <summary>
/// Part values by part index in <see cref="ILinePatternPart.CaptureIndex"/>.
/// </summary>
/// <param name="ix"></param>
/// <returns></returns>
string this[int ix] { get; }
/// <summary>
/// Get part value by part identifier.
/// </summary>
/// <param name="identifier">identifier, e.g. "Culture", "Type"</param>
/// <returns>value or null</returns>
new string this[string identifier] { get; }
/// <summary>
/// Where all required parts found.
/// </summary>
bool Success { get; }
}
LinePattern is a regular-expression like pattern to print and extract parameters from keys and strings.
csharp
// Let's create an example key
ILine key = LineAppender.NonResolving
.Location("Patches")
.Type("MyController")
.Section("Errors")
.Key("InvalidState")
.Culture("en");
csharp
// Create pattern
ILineFormat myPolicy = new LinePattern("{Culture/}{Location/}{Type/}{Section/}[Key].txt");
// "en/Patches/MyController/Errors/InvalidState.txt"
string str = myPolicy.Print(key);
Name pattern consists of parameters. They are written in format of "{prefix ParameterName suffix}".Braces "{parameter/}" make parameter optional, and brackets "[parameter/]" mandatory.
csharp
// Create pattern
ILineFormat myPolicy = new LinePattern("Patches/{Section}[-Key]{-Culture}.png");
Parameter can be added multiple times.
csharp
// Create pattern
ILineFormat myPolicy = new LinePattern("{Location/}{Location/}{Location/}{Section}{-Key}{-Culture}.png");
// Create key
ILine key2 = LineAppender.NonResolving
.Location("Patches").Location("20181130").Section("icons").Key("ok").Culture("de");
// Converts to "Patches/20181130/icons-ok-de.png"
string str = myPolicy.Print(key2);
A shorter way to add consecutive parameters is use suffix "n". It translates to the five following occurances.
If part is required, e.g. "[parametername_n]", then only first part is required and others optional.
csharp
// "[Location_n/]" translates to "[Location_0/]{Location_1/}{Location_2/}{Location_3/}{Location_4/}"
ILineFormat myPolicy = new LinePattern("[Location_n/]{Section}{-Key}{-Culture}.png");
// Create key
ILine key2 = LineAppender.NonResolving
.Location("Patches").Location("20181130").Section("icons").Key("ok").Culture("de");
// Converts to "Patches/20181130/icons-ok-de.png"
string str = myPolicy.Print(key2);
Parameters need to be added in non-consecutive order, then "#" can be used to represent the occurance index.
csharp
// Create pattern
ILineFormat myPolicy = new LinePattern("{Location_3}{Location_2/}{Location_1/}{Location/}{Section}{-Key}{-Culture}.png");
// Create key
ILine key2 = LineAppender.NonResolving
.Location("Patches").Location("20181130").Section("icons").Key("ok").Culture("de");
// Converts to "20181130/Patches/icons-ok-de.png"
string str = myPolicy.Print(key2);
Regular expression can be written inside angle brackets "{parameter<regexp>/}", which gives more control over matching.
csharp
// Create pattern with regular expression detail
ILinePattern myPolicy = new LinePattern("{Location<[^/]+>/}{Section}{-Key}{-Culture}.png");
// Use its regular expression
Match match = myPolicy.Regex.Match("patches/icons-ok-de.png");
## LineParameterPrinter
LineParameterPrinter is a generic class that prints key parts into strings by applying configured rules.
Let's create an example key.
csharp
// Let's create an example key
ILine key = LineAppender.NonResolving
.Location("Patches")
.Section("Controllers")
.Type("MyController")
.Section("Errors")
.Key("InvalidState")
.Culture("en");
And now, let's try out different policies to see how they look.
csharp
// "en:Patches:Controllers:MyController:Errors:InvalidState"
string str1 = LineParameterPrinter.Default.Print(key);
// "en.Patches.Controllers.MyController.Errors.InvalidState"
string str2 = LineParameterPrinter.Dot_Dot_Dot.Print(key);
// "Patches:Controllers:MyController:Errors:InvalidState"
string str3 = LineParameterPrinter.None_Colon_Colon.Print(key);
// "en:Patches.Controllers.MyController.Errors.InvalidState"
string str4 = LineParameterPrinter.Colon_Dot_Dot.Print(key);
// "en:Patches:Controllers:MyController:Errors.InvalidState"
string str5 = LineParameterPrinter.Colon_Colon_Dot.Print(key);
Policy is created by adding rules to LineParameterPrinter.
csharp
// Create a custom policy
ILineFormat myPolicy = new LineParameterPrinter()
// Enable non-canonical "Culture" parameter with "/" separator
.Rule("Culture", true, postfixSeparator: "/", order: ParameterInfos.Default.GetValue("Culture").Order)
// Disable other non-canonical parts
.NonCanonicalRule(false)
// Enable canonical all parts with "/" separator
.CanonicalRule(true, prefixSeparator: "/")
// Set "Key" parameter's prefix to "/"
.Rule("Key", true, prefixSeparator: "/", order: ParameterInfos.Default.GetValue("Key").Order);
// "en/Patches/MyController/Errors/InvalidState"
string str = myPolicy.Print(key);
## Links
* ILineFormat is the root interface for classes that formulate ILine into identity string.
* ILineFormatPrinter is a subinterface where Build() can be implemented directly.
* ILinePattern is a subinterface that formulates parametrization with a template string.
* LineParameterPrinter is implementation of IAssetNameProvider.
* LinePattern is the default implementation of ILinePattern.
* LineFormat is context-free string format.
# Plurality
Language strings with numeric arguments, for example "There are {0} cats.", can be customized for pluralized nouns.
Plural category is placed into argument placeholder, for example "There are {cardinal:0} cats.".
The available cases depend on the culture and the category.
The root culture "" has category "cardinal" and "ordinal", and the former has three possible cases "zero", "one" and "other".
See table of case for each culture and category.
Each case must be matched with a subkey N:case.
xml
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N"
xmlns="urn:lexical.fi"
PluralRules="Unicode.CLDR35">
<!-- Example: Plurality for one numeric argument {0} -->
<Key:Cats>
{cardinal:0} cat(s)
<N:zero>no cats</N:zero>
<N:one>a cat</N:one>
<N:other>{0} cats</N:other>
</Key:Cats>
</Localization>
csharp
IAsset asset = LineReaderMap.Default.FileAsset("PluralityExample0b.xml");
ILine key = new LineRoot(asset).Key("Cats");
for (int cats = 0; cats<=2; cats++)
Console.WriteLine(key.Value(cats));
The result
no cats a cat 2 cats
Translator adds localized strings for different cultures.
The decision whether to use pluralization is left for the translator.
IAsset asset = LineReaderMap.Default.FileAsset("PluralityExample0a.xml");
ILineRoot root = new LineRoot(asset);
ILine key = root.Key("Cats").Format("{0} cat(s)");
// Print with the default string (without culture policy)
for (int cats = 0; cats <= 2; cats++)
Console.WriteLine(key.Value(cats));
// Print Culture "en"
for (int cats = 0; cats <= 2; cats++)
Console.WriteLine(key.Culture("en").Value(cats));
// Print Culture "fi"
for (int cats = 0; cats <= 2; cats++)
Console.WriteLine(key.Culture("fi").Value(cats));
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N"
xmlns="urn:lexical.fi"
PluralRules="Unicode.CLDR35">
<!-- Fallback string, for "" culture -->
<Key:Cats>{0} cat(s)</Key:Cats>
<!-- Translator added strings for "en" -->
<Key:Cats Culture="en">
{cardinal:0} cat(s)
<N:zero>no cats</N:zero>
<N:one>a cat</N:one>
<N:other>{0} cats</N:other>
</Key:Cats>
<!-- Translator added strings for "fi" -->
<Key:Cats Culture="fi">
{cardinal:0} kissa(a)
<N:zero>ei kissoja</N:zero>
<N:one>yksi kissa</N:one>
<N:other>{0} kissaa</N:other>
</Key:Cats>
</Localization>
The result
0 cat(s) 1 cat(s) 2 cat(s) no cats a cat 2 cats ei kissoja yksi kissa 2 kissaa
Some cases are optional. For example for "en" culture and "cardinal" category, the case "zero" is optional. Translator can choose whether to supply a string for an optional case, such as "N:zero". If a string is not provided, then string resolver reverts to a string from next valid case "N:other". For value 0, the string "{0} cats" would be provided, which is just as valid, but not as humanized as "no cats".
xml
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N"
xmlns="urn:lexical.fi"
PluralRules="Unicode.CLDR35">
<!-- Example: One plurality case for one numeric argument {0} -->
<Key:Cats>
{cardinal:0} cats
<N:one>a cat</N:one>
<N:other>{0} cats</N:other>
</Key:Cats>
</Localization>
Even if a required case is missing, then StringResolver will revert to default string.
For example, only "N:one" is provided, and for values other than "1", the rules revert to default string "{0} cats".
xml
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N"
xmlns="urn:lexical.fi"
PluralRules="Unicode.CLDR35">
<!-- Example: One plurality case for one numeric argument {0} -->
<Key:Cats>
{cardinal:0} cats
<N:one>a cat</N:one>
</Key:Cats>
</Localization>
Inlined strings are picked up by inline scanner and placed to a localization file. Add sub-key with parameter name N for argument "{0}" and value for each of "zero", "one", "other".
csharp
ILineRoot root = new LineRoot();
ILine line = root.Key("Cats")
.PluralRules("Unicode.CLDR35")
.Format("{cardinal:0} cat(s)") // Default string
.Inline("N:zero", "no cats")
.Inline("N:one", "a cat")
.Inline("N:other", "{0} cats");
And inlining for specific cultures too with subkey "Culture:culture:N:case".
csharp
ILineRoot root = new LineRoot();
ILine line = root.Key("Cats")
.PluralRules("Unicode.CLDR35")
.Format("{0} cat(s)") // Default string
.Inline("Culture:en", "{cardinal:0} cat(s)")
.Inline("Culture:en:N:zero", "no cats")
.Inline("Culture:en:N:one", "a cat")
.Inline("Culture:en:N:other", "{0} cats")
.Inline("Culture:fi", "{cardinal:0} kissa(a)")
.Inline("Culture:fi:N:zero", "ei kissoja")
.Inline("Culture:fi:N:one", "yksi kissa")
.Inline("Culture:fi:N:other", "{0} kissaa");
for (int cats = 0; cats <= 2; cats++)
Console.WriteLine(line.Culture("en").Value(cats));
If translator wants to supply plurality for two numeric arguments, then all permutations of required cases (for example "zero", "one" and "other") for both arguments must be covered.
By default the maximum number of pluralized arguments is three arguments. This value can be modified, by creating a custom instance of StringResolver into ILineRoot.
xml
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N" xmlns:N1="urn:lexical.fi:N1"
xmlns="urn:lexical.fi"
PluralRules="Unicode.CLDR35">
<!-- Example: Plurality for two numeric arguments {0} and {1} -->
<Key:CatsDogs Culture="en">
{cardinal:0} cat(s) and {cardinal:1} dog(s)
<N:zero>
<N1:zero>no cats and no dogs</N1:zero>
<N1:one>no cats but one dog</N1:one>
<N1:other>no cats but {1} dogs</N1:other>
</N:zero>
<N:one>
<N1:zero>one cat but no dogs</N1:zero>
<N1:one>a cat and a dog</N1:one>
<N1:other>a cat and {1} dogs</N1:other>
</N:one>
<N:other>
<N1:zero>{0} cats but no dogs</N1:zero>
<N1:one>{0} cats and a dog</N1:one>
<N1:other>{0} cats and {1} dogs</N1:other>
</N:other>
</Key:CatsDogs>
</Localization>
csharp
IAsset asset = LineReaderMap.Default.FileAsset("PluralityExample2.xml");
ILineRoot root = new LineRoot(asset);
ILine key = root.Key("CatsDogs").Format("{0} cat(s) and {1} dog(s)");
for (int cats = 0; cats <= 2; cats++)
for (int dogs = 0; dogs <= 2; dogs++)
Console.WriteLine(key.Culture("en").Value(cats, dogs));
The result
no cats and no dogs no cats but one dog no cats but 2 dogs one cat but no dogs a cat and a dog a cat and 2 dogs 2 cats but no dogs 2 cats and a dog 2 cats and 2 dogs
Pluralization is applied only to the arguments that have "{category:arg}".
xml
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N" xmlns:N1="urn:lexical.fi:N1"
xmlns:N2="urn:lexical.fi:N2" xmlns:N3="urn:lexical.fi:N3"
xmlns="urn:lexical.fi"
PluralRules="Unicode.CLDR35">
<!-- Example: Plurality for one numeric argument {2} -->
<Key:CatsDogsPoniesHorses>
{0} cat(s), {1} dog(s), {cardinal:2} poni(es) and {3} horse(s)
<N2:zero>{0} cat(s), {1} dog(s), no ponies and {3} horse(s)</N2:zero>
<N2:one>{0} cat(s), {1} dog(s), a pony and {3} horse(s)</N2:one>
<N2:other>{0} cat(s), {1} dog(s), {2} ponies and {3} horse(s)</N2:other>
</Key:CatsDogsPoniesHorses>
</Localization>
csharp
IAsset asset = LineReaderMap.Default.FileAsset("PluralityExample4.xml");
ILine key = new LineRoot(asset).Key("CatsDogsPoniesHorses");
for (int cats = 0; cats <= 2; cats++)
for (int dogs = 0; dogs <= 2; dogs++)
for (int ponies = 0; ponies <= 2; ponies++)
for (int horses = 0; horses <= 2; horses++)
Console.WriteLine(key.Value(cats, dogs, ponies, horses));
The result
0 cat(s), 0 dog(s), no ponies and 0 horse(s) 0 cat(s), 0 dog(s), no ponies and 1 horse(s) 0 cat(s), 0 dog(s), no ponies and 2 horse(s) 0 cat(s), 0 dog(s), a pony and 0 horse(s) 0 cat(s), 0 dog(s), a pony and 1 horse(s) 0 cat(s), 0 dog(s), a pony and 2 horse(s) 0 cat(s), 0 dog(s), 2 ponies and 0 horse(s) 0 cat(s), 0 dog(s), 2 ponies and 1 horse(s) 0 cat(s), 0 dog(s), 2 ponies and 2 horse(s) 0 cat(s), 1 dog(s), no ponies and 0 horse(s) 0 cat(s), 1 dog(s), no ponies and 1 horse(s) 0 cat(s), 1 dog(s), no ponies and 2 horse(s) 0 cat(s), 1 dog(s), a pony and 0 horse(s) 0 cat(s), 1 dog(s), a pony and 1 horse(s) 0 cat(s), 1 dog(s), a pony and 2 horse(s) 0 cat(s), 1 dog(s), 2 ponies and 0 horse(s) 0 cat(s), 1 dog(s), 2 ponies and 1 horse(s) 0 cat(s), 1 dog(s), 2 ponies and 2 horse(s) 0 cat(s), 2 dog(s), no ponies and 0 horse(s) 0 cat(s), 2 dog(s), no ponies and 1 horse(s) 0 cat(s), 2 dog(s), no ponies and 2 horse(s) 0 cat(s), 2 dog(s), a pony and 0 horse(s) 0 cat(s), 2 dog(s), a pony and 1 horse(s) 0 cat(s), 2 dog(s), a pony and 2 horse(s) 0 cat(s), 2 dog(s), 2 ponies and 0 horse(s) 0 cat(s), 2 dog(s), 2 ponies and 1 horse(s) 0 cat(s), 2 dog(s), 2 ponies and 2 horse(s) 1 cat(s), 0 dog(s), no ponies and 0 horse(s) 1 cat(s), 0 dog(s), no ponies and 1 horse(s) 1 cat(s), 0 dog(s), no ponies and 2 horse(s) 1 cat(s), 0 dog(s), a pony and 0 horse(s) 1 cat(s), 0 dog(s), a pony and 1 horse(s) 1 cat(s), 0 dog(s), a pony and 2 horse(s) 1 cat(s), 0 dog(s), 2 ponies and 0 horse(s) 1 cat(s), 0 dog(s), 2 ponies and 1 horse(s) 1 cat(s), 0 dog(s), 2 ponies and 2 horse(s) 1 cat(s), 1 dog(s), no ponies and 0 horse(s) 1 cat(s), 1 dog(s), no ponies and 1 horse(s) 1 cat(s), 1 dog(s), no ponies and 2 horse(s) 1 cat(s), 1 dog(s), a pony and 0 horse(s) 1 cat(s), 1 dog(s), a pony and 1 horse(s) 1 cat(s), 1 dog(s), a pony and 2 horse(s) 1 cat(s), 1 dog(s), 2 ponies and 0 horse(s) 1 cat(s), 1 dog(s), 2 ponies and 1 horse(s) 1 cat(s), 1 dog(s), 2 ponies and 2 horse(s) 1 cat(s), 2 dog(s), no ponies and 0 horse(s) 1 cat(s), 2 dog(s), no ponies and 1 horse(s) 1 cat(s), 2 dog(s), no ponies and 2 horse(s) 1 cat(s), 2 dog(s), a pony and 0 horse(s) 1 cat(s), 2 dog(s), a pony and 1 horse(s) 1 cat(s), 2 dog(s), a pony and 2 horse(s) 1 cat(s), 2 dog(s), 2 ponies and 0 horse(s) 1 cat(s), 2 dog(s), 2 ponies and 1 horse(s) 1 cat(s), 2 dog(s), 2 ponies and 2 horse(s) 2 cat(s), 0 dog(s), no ponies and 0 horse(s) 2 cat(s), 0 dog(s), no ponies and 1 horse(s) 2 cat(s), 0 dog(s), no ponies and 2 horse(s) 2 cat(s), 0 dog(s), a pony and 0 horse(s) 2 cat(s), 0 dog(s), a pony and 1 horse(s) 2 cat(s), 0 dog(s), a pony and 2 horse(s) 2 cat(s), 0 dog(s), 2 ponies and 0 horse(s) 2 cat(s), 0 dog(s), 2 ponies and 1 horse(s) 2 cat(s), 0 dog(s), 2 ponies and 2 horse(s) 2 cat(s), 1 dog(s), no ponies and 0 horse(s) 2 cat(s), 1 dog(s), no ponies and 1 horse(s) 2 cat(s), 1 dog(s), no ponies and 2 horse(s) 2 cat(s), 1 dog(s), a pony and 0 horse(s) 2 cat(s), 1 dog(s), a pony and 1 horse(s) 2 cat(s), 1 dog(s), a pony and 2 horse(s) 2 cat(s), 1 dog(s), 2 ponies and 0 horse(s) 2 cat(s), 1 dog(s), 2 ponies and 1 horse(s) 2 cat(s), 1 dog(s), 2 ponies and 2 horse(s) 2 cat(s), 2 dog(s), no ponies and 0 horse(s) 2 cat(s), 2 dog(s), no ponies and 1 horse(s) 2 cat(s), 2 dog(s), no ponies and 2 horse(s) 2 cat(s), 2 dog(s), a pony and 0 horse(s) 2 cat(s), 2 dog(s), a pony and 1 horse(s) 2 cat(s), 2 dog(s), a pony and 2 horse(s) 2 cat(s), 2 dog(s), 2 ponies and 0 horse(s) 2 cat(s), 2 dog(s), 2 ponies and 1 horse(s) 2 cat(s), 2 dog(s), 2 ponies and 2 horse(s)
Plural Rules Table
PluralRules="Unicode.CLDR35" (click here)
Culture | Category | Case | Required | Rule | Samples |
---|---|---|---|---|---|
"" | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
af | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ak | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
am | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ar | cardinal | zero | ☑ | n=0 | @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
few | ☑ | n % 100=3..10 | @integer 3~10, 103~110, 1003, … @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 103.0, 1003.0, … | ||
many | ☑ | n % 100=11..99 | @integer 11~26, 111, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, … | ||
other | ☑ | @integer 100~102, 200~202, 300~302, 400~402, 500~502, 600, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ars | cardinal | zero | ☑ | n=0 | @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
few | ☑ | n % 100=3..10 | @integer 3~10, 103~110, 1003, … @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 103.0, 1003.0, … | ||
many | ☑ | n % 100=11..99 | @integer 11~26, 111, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, … | ||
other | ☑ | @integer 100~102, 200~202, 300~302, 400~402, 500~502, 600, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
as | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1,5,7,8,9,10 | @integer 1, 5, 7~10 | |
two | ☑ | n=2,3 | @integer 2, 3 | ||
few | ☑ | n=4 | @integer 4 | ||
many | ☑ | n=6 | @integer 6 | ||
other | ☑ | @integer 0, 11~25, 100, 1000, 10000, 100000, 1000000, … | |||
asa | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ast | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
az | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | i % 10=1,2,5,7,8 or i % 100=20,50,70,80 | @integer 1, 2, 5, 7, 8, 11, 12, 15, 17, 18, 20~22, 25, 101, 1001, … | |
few | ☑ | i % 10=3,4 or i % 1000=100,200,300,400,500,600,700,800,900 | @integer 3, 4, 13, 14, 23, 24, 33, 34, 43, 44, 53, 54, 63, 64, 73, 74, 100, 1003, … | ||
many | ☑ | i=0 or i % 10=6 or i % 100=40,60,90 | @integer 0, 6, 16, 26, 36, 40, 46, 56, 106, 1006, … | ||
other | ☑ | @integer 9, 10, 19, 29, 30, 39, 49, 59, 69, 79, 109, 1000, 10000, 100000, 1000000, … | |||
be | cardinal | zero | ☐ | n=0 | |
one | ☑ | n % 10=1 and n % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 101.0, 1001.0, … | ||
few | ☑ | n % 10=2..4 and n % 100!=12..14 | @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 2.0, 3.0, 4.0, 22.0, 23.0, 24.0, 32.0, 33.0, 102.0, 1002.0, … | ||
many | ☑ | n % 10=0 or n % 10=5..9 or n % 100=11..14 | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, … | |||
ordinal | one | ☐ | n=1 | ||
few | ☑ | n % 10=2,3 and n % 100!=12,13 | @integer 2, 3, 22, 23, 32, 33, 42, 43, 52, 53, 62, 63, 72, 73, 82, 83, 102, 1002, … | ||
other | ☑ | @integer 0, 1, 4~17, 100, 1000, 10000, 100000, 1000000, … | |||
bem | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
bez | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
bg | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
bh | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
bm | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
bn | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1,5,7,8,9,10 | @integer 1, 5, 7~10 | |
two | ☑ | n=2,3 | @integer 2, 3 | ||
few | ☑ | n=4 | @integer 4 | ||
many | ☑ | n=6 | @integer 6 | ||
other | ☑ | @integer 0, 11~25, 100, 1000, 10000, 100000, 1000000, … | |||
bo | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
br | cardinal | zero | ☐ | n=0 | |
one | ☑ | n % 10=1 and n % 100!=11,71,91 | @integer 1, 21, 31, 41, 51, 61, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 81.0, 101.0, 1001.0, … | ||
two | ☑ | n % 10=2 and n % 100!=12,72,92 | @integer 2, 22, 32, 42, 52, 62, 82, 102, 1002, … @decimal 2.0, 22.0, 32.0, 42.0, 52.0, 62.0, 82.0, 102.0, 1002.0, … | ||
few | ☑ | n % 10=3..4,9 and n % 100!=10..19,70..79,90..99 | @integer 3, 4, 9, 23, 24, 29, 33, 34, 39, 43, 44, 49, 103, 1003, … @decimal 3.0, 4.0, 9.0, 23.0, 24.0, 29.0, 33.0, 34.0, 103.0, 1003.0, … | ||
many | ☑ | n!=0 and n % 1000000=0 | @integer 1000000, … @decimal 1000000.0, 1000000.00, 1000000.000, … | ||
other | ☑ | @integer 0, 5~8, 10~20, 100, 1000, 10000, 100000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, … | |||
brx | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
bs | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 10=1 and i % 100!=11 or f % 10=1 and f % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
few | ☑ | v=0 and i % 10=2..4 and i % 100!=12..14 or f % 10=2..4 and f % 100!=12..14 | @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 0.2~0.4, 1.2~1.4, 2.2~2.4, 3.2~3.4, 4.2~4.4, 5.2, 10.2, 100.2, 1000.2, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ca | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1,3 | @integer 1, 3 | |
two | ☑ | n=2 | @integer 2 | ||
few | ☑ | n=4 | @integer 4 | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | |||
ce | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ceb | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i=1,2,3 or v=0 and i % 10!=4,6,9 or v!=0 and f % 10!=4,6,9 | @integer 0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.3, 0.5, 0.7, 0.8, 1.0~1.3, 1.5, 1.7, 1.8, 2.0, 2.1, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, … @decimal 0.4, 0.6, 0.9, 1.4, 1.6, 1.9, 2.4, 2.6, 10.4, 100.4, 1000.4, … | |||
cgg | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
chr | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ckb | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
cs | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
few | ☑ | i=2..4 and v=0 | @integer 2~4 | ||
many | ☑ | v!=0 | @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
cy | cardinal | zero | ☑ | n=0 | @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
few | ☑ | n=3 | @integer 3 @decimal 3.0, 3.00, 3.000, 3.0000 | ||
many | ☑ | n=6 | @integer 6 @decimal 6.0, 6.00, 6.000, 6.0000 | ||
other | ☑ | @integer 4, 5, 7~20, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | zero | ☑ | n=0,7,8,9 | @integer 0, 7~9 | |
one | ☑ | n=1 | @integer 1 | ||
two | ☑ | n=2 | @integer 2 | ||
few | ☑ | n=3,4 | @integer 3, 4 | ||
many | ☑ | n=5,6 | @integer 5, 6 | ||
other | ☑ | @integer 10~25, 100, 1000, 10000, 100000, 1000000, … | |||
da | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 or t!=0 and i=0,1 | @integer 1 @decimal 0.1~1.6 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 2.0~3.4, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
de | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
dsb | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 100=1 or f % 100=1 | @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
two | ☑ | v=0 and i % 100=2 or f % 100=2 | @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, … @decimal 0.2, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 10.2, 100.2, 1000.2, … | ||
few | ☑ | v=0 and i % 100=3..4 or f % 100=3..4 | @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.3, 0.4, 1.3, 1.4, 2.3, 2.4, 3.3, 3.4, 4.3, 4.4, 5.3, 5.4, 6.3, 6.4, 7.3, 7.4, 10.3, 100.3, 1000.3, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
dv | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
dz | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ee | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
el | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
en | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n % 10=1 and n % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … | |
two | ☑ | n % 10=2 and n % 100!=12 | @integer 2, 22, 32, 42, 52, 62, 72, 82, 102, 1002, … | ||
few | ☑ | n % 10=3 and n % 100!=13 | @integer 3, 23, 33, 43, 53, 63, 73, 83, 103, 1003, … | ||
other | ☑ | @integer 0, 4~18, 100, 1000, 10000, 100000, 1000000, … | |||
eo | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
es | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
et | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
eu | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
fa | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ff | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0,1 | @integer 0, 1 @decimal 0.0~1.5 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
fi | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
fil | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i=1,2,3 or v=0 and i % 10!=4,6,9 or v!=0 and f % 10!=4,6,9 | @integer 0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.3, 0.5, 0.7, 0.8, 1.0~1.3, 1.5, 1.7, 1.8, 2.0, 2.1, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, … @decimal 0.4, 0.6, 0.9, 1.4, 1.6, 1.9, 2.4, 2.6, 10.4, 100.4, 1000.4, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
fo | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
fr | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0,1 | @integer 0, 1 @decimal 0.0~1.5 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
fur | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
fy | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ga | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
few | ☑ | n=3..6 | @integer 3~6 @decimal 3.0, 4.0, 5.0, 6.0, 3.00, 4.00, 5.00, 6.00, 3.000, 4.000, 5.000, 6.000, 3.0000, 4.0000, 5.0000, 6.0000 | ||
many | ☑ | n=7..10 | @integer 7~10 @decimal 7.0, 8.0, 9.0, 10.0, 7.00, 8.00, 9.00, 10.00, 7.000, 8.000, 9.000, 10.000, 7.0000, 8.0000, 9.0000, 10.0000 | ||
other | ☑ | @integer 0, 11~25, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
gd | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1,11 | @integer 1, 11 @decimal 1.0, 11.0, 1.00, 11.00, 1.000, 11.000, 1.0000 | ||
two | ☑ | n=2,12 | @integer 2, 12 @decimal 2.0, 12.0, 2.00, 12.00, 2.000, 12.000, 2.0000 | ||
few | ☑ | n=3..10,13..19 | @integer 3~10, 13~19 @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 3.00 | ||
other | ☑ | @integer 0, 20~34, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1,11 | @integer 1, 11 | |
two | ☑ | n=2,12 | @integer 2, 12 | ||
few | ☑ | n=3,13 | @integer 3, 13 | ||
other | ☑ | @integer 0, 4~10, 14~21, 100, 1000, 10000, 100000, 1000000, … | |||
gl | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
gsw | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
gu | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
two | ☑ | n=2,3 | @integer 2, 3 | ||
few | ☑ | n=4 | @integer 4 | ||
many | ☑ | n=6 | @integer 6 | ||
other | ☑ | @integer 0, 5, 7~20, 100, 1000, 10000, 100000, 1000000, … | |||
guw | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
gv | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 10=1 | @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, … | ||
two | ☑ | v=0 and i % 10=2 | @integer 2, 12, 22, 32, 42, 52, 62, 72, 102, 1002, … | ||
few | ☑ | v=0 and i % 100=0,20,40,60,80 | @integer 0, 20, 40, 60, 80, 100, 120, 140, 1000, 10000, 100000, 1000000, … | ||
many | ☑ | v!=0 | @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 3~10, 13~19, 23, 103, 1003, … | |||
ha | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
haw | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
he | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
two | ☑ | i=2 and v=0 | @integer 2 | ||
many | ☑ | v=0 and n!=0..10 and n % 10=0 | @integer 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 10000, 100000, 1000000, … | ||
other | ☑ | @integer 0, 3~17, 101, 1001, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
hi | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
two | ☑ | n=2,3 | @integer 2, 3 | ||
few | ☑ | n=4 | @integer 4 | ||
many | ☑ | n=6 | @integer 6 | ||
other | ☑ | @integer 0, 5, 7~20, 100, 1000, 10000, 100000, 1000000, … | |||
hr | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 10=1 and i % 100!=11 or f % 10=1 and f % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
few | ☑ | v=0 and i % 10=2..4 and i % 100!=12..14 or f % 10=2..4 and f % 100!=12..14 | @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 0.2~0.4, 1.2~1.4, 2.2~2.4, 3.2~3.4, 4.2~4.4, 5.2, 10.2, 100.2, 1000.2, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
hsb | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 100=1 or f % 100=1 | @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
two | ☑ | v=0 and i % 100=2 or f % 100=2 | @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, … @decimal 0.2, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 10.2, 100.2, 1000.2, … | ||
few | ☑ | v=0 and i % 100=3..4 or f % 100=3..4 | @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.3, 0.4, 1.3, 1.4, 2.3, 2.4, 3.3, 3.4, 4.3, 4.4, 5.3, 5.4, 6.3, 6.4, 7.3, 7.4, 10.3, 100.3, 1000.3, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
hu | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1,5 | @integer 1, 5 | |
other | ☑ | @integer 0, 2~4, 6~17, 100, 1000, 10000, 100000, 1000000, … | |||
hy | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0,1 | @integer 0, 1 @decimal 0.0~1.5 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
ia | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
id | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ig | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ii | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
in | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
io | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
is | cardinal | zero | ☐ | n=0 | |
one | ☑ | t=0 and i % 10=1 and i % 100!=11 or t!=0 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1~1.6, 10.1, 100.1, 1000.1, … | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
it | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
many | ☑ | n=11,8,80,800 | @integer 8, 11, 80, 800 | ||
other | ☑ | @integer 0~7, 9, 10, 12~17, 100, 1000, 10000, 100000, 1000000, … | |||
iu | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
iw | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
two | ☑ | i=2 and v=0 | @integer 2 | ||
many | ☑ | v=0 and n!=0..10 and n % 10=0 | @integer 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 10000, 100000, 1000000, … | ||
other | ☑ | @integer 0, 3~17, 101, 1001, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ja | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
jbo | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
jgo | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ji | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
jmc | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
jv | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
jw | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ka | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | i=1 | @integer 1 | |
many | ☑ | i=0 or i % 100=2..20,40,60,80 | @integer 0, 2~16, 102, 1002, … | ||
other | ☑ | @integer 21~36, 100, 1000, 10000, 100000, 1000000, … | |||
kab | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0,1 | @integer 0, 1 @decimal 0.0~1.5 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
kaj | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
kcg | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
kde | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
kea | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
kk | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
many | ☑ | n % 10=6 or n % 10=9 or n % 10=0 and n!=0 | @integer 6, 9, 10, 16, 19, 20, 26, 29, 30, 36, 39, 40, 100, 1000, 10000, 100000, 1000000, … | ||
other | ☑ | @integer 0~5, 7, 8, 11~15, 17, 18, 21, 101, 1001, … | |||
kkj | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
kl | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
km | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
kn | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ko | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ks | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ksb | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ksh | cardinal | zero | ☑ | n=0 | @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ku | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
kw | cardinal | zero | ☑ | n=0 | @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n % 100=2,22,42,62,82 or n % 1000=0 and n % 100000=1000..20000,40000,60000,80000 or n!=0 and n % 1000000=100000 | @integer 2, 22, 42, 62, 82, 102, 122, 142, 1002, … @decimal 2.0, 22.0, 42.0, 62.0, 82.0, 102.0, 122.0, 142.0, 1002.0, … | ||
few | ☑ | n % 100=3,23,43,63,83 | @integer 3, 23, 43, 63, 83, 103, 123, 143, 1003, … @decimal 3.0, 23.0, 43.0, 63.0, 83.0, 103.0, 123.0, 143.0, 1003.0, … | ||
many | ☑ | n!=1 and n % 100=1,21,41,61,81 | @integer 21, 41, 61, 81, 101, 121, 141, 161, 1001, … @decimal 21.0, 41.0, 61.0, 81.0, 101.0, 121.0, 141.0, 161.0, 1001.0, … | ||
other | ☑ | @integer 4~19, 100, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1..4 or n % 100=1..4,21..24,41..44,61..64,81..84 | @integer 1~4, 21~24, 41~44, 61~64, 101, 1001, … | |
many | ☑ | n=5 or n % 100=5 | @integer 5, 105, 205, 305, 405, 505, 605, 705, 1005, … | ||
other | ☑ | @integer 0, 6~20, 100, 1000, 10000, 100000, 1000000, … | |||
ky | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
lag | cardinal | zero | ☑ | n=0 | @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000 |
one | ☑ | i=0,1 and n!=0 | @integer 1 @decimal 0.1~1.6 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
lb | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
lg | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
lkt | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ln | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
lo | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
lt | cardinal | zero | ☐ | n=0 | |
one | ☑ | n % 10=1 and n % 100!=11..19 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 101.0, 1001.0, … | ||
few | ☑ | n % 10=2..9 and n % 100!=11..19 | @integer 2~9, 22~29, 102, 1002, … @decimal 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 22.0, 102.0, 1002.0, … | ||
many | ☑ | f!=0 | @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, … | ||
other | ☑ | @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
lv | cardinal | zero | ☑ | n % 10=0 or n % 100=11..19 or v=2 and f % 100=11..19 | @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … |
one | ☑ | n % 10=1 and n % 100!=11 or v=2 and f % 10=1 and f % 100!=11 or v!=2 and f % 10=1 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.0, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
other | ☑ | @integer 2~9, 22~29, 102, 1002, … @decimal 0.2~0.9, 1.2~1.9, 10.2, 100.2, 1000.2, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
mas | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
mg | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
mgo | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
mk | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 10=1 and i % 100!=11 or f % 10=1 and f % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.2~1.0, 1.2~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | i % 10=1 and i % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … | |
two | ☑ | i % 10=2 and i % 100!=12 | @integer 2, 22, 32, 42, 52, 62, 72, 82, 102, 1002, … | ||
many | ☑ | i % 10=7,8 and i % 100!=17,18 | @integer 7, 8, 27, 28, 37, 38, 47, 48, 57, 58, 67, 68, 77, 78, 87, 88, 107, 1007, … | ||
other | ☑ | @integer 0, 3~6, 9~19, 100, 1000, 10000, 100000, 1000000, … | |||
ml | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
mn | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
mo | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
few | ☑ | v!=0 or n=0 or n % 100=2..19 | @integer 0, 2~16, 102, 1002, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 20~35, 100, 1000, 10000, 100000, 1000000, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
mr | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
two | ☑ | n=2,3 | @integer 2, 3 | ||
few | ☑ | n=4 | @integer 4 | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | |||
ms | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
mt | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
few | ☑ | n=0 or n % 100=2..10 | @integer 0, 2~10, 102~107, 1002, … @decimal 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0, 102.0, 1002.0, … | ||
many | ☑ | n % 100=11..19 | @integer 11~19, 111~117, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, … | ||
other | ☑ | @integer 20~35, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
my | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
nah | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
naq | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
nb | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
nd | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ne | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1..4 | @integer 1~4 | |
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | |||
nl | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
nn | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
nnh | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
no | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
nqo | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
nr | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
nso | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ny | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
nyn | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
om | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
or | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1,5,7..9 | @integer 1, 5, 7~9 | |
two | ☑ | n=2,3 | @integer 2, 3 | ||
few | ☑ | n=4 | @integer 4 | ||
many | ☑ | n=6 | @integer 6 | ||
other | ☑ | @integer 0, 10~24, 100, 1000, 10000, 100000, 1000000, … | |||
os | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
pa | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
pap | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
pl | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
few | ☑ | v=0 and i % 10=2..4 and i % 100!=12..14 | @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … | ||
many | ☑ | v=0 and i!=1 and i % 10=0..1 or v=0 and i % 10=5..9 or v=0 and i % 100=12..14 | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | ||
other | ☑ | @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
prg | cardinal | zero | ☑ | n % 10=0 or n % 100=11..19 or v=2 and f % 100=11..19 | @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … |
one | ☑ | n % 10=1 and n % 100!=11 or v=2 and f % 10=1 and f % 100!=11 or v!=2 and f % 10=1 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.0, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
other | ☑ | @integer 2~9, 22~29, 102, 1002, … @decimal 0.2~0.9, 1.2~1.9, 10.2, 100.2, 1000.2, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ps | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
pt | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0..1 | @integer 0, 1 @decimal 0.0~1.5 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
pt-PT | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
rm | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ro | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
few | ☑ | v!=0 or n=0 or n % 100=2..19 | @integer 0, 2~16, 102, 1002, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 20~35, 100, 1000, 10000, 100000, 1000000, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
rof | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ru | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 10=1 and i % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … | ||
few | ☑ | v=0 and i % 10=2..4 and i % 100!=12..14 | @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … | ||
many | ☑ | v=0 and i % 10=0 or v=0 and i % 10=5..9 or v=0 and i % 100=11..14 | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | ||
other | ☑ | @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
rwk | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
sah | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
saq | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
sc | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
many | ☑ | n=11,8,80,800 | @integer 8, 11, 80, 800 | ||
other | ☑ | @integer 0~7, 9, 10, 12~17, 100, 1000, 10000, 100000, 1000000, … | |||
scn | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
many | ☑ | n=11,8,80,800 | @integer 8, 11, 80, 800 | ||
other | ☑ | @integer 0~7, 9, 10, 12~17, 100, 1000, 10000, 100000, 1000000, … | |||
sd | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
sdh | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
se | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
seh | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ses | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
sg | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
sh | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 10=1 and i % 100!=11 or f % 10=1 and f % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
few | ☑ | v=0 and i % 10=2..4 and i % 100!=12..14 or f % 10=2..4 and f % 100!=12..14 | @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 0.2~0.4, 1.2~1.4, 2.2~2.4, 3.2~3.4, 4.2~4.4, 5.2, 10.2, 100.2, 1000.2, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
shi | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
few | ☑ | n=2..10 | @integer 2~10 @decimal 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00 | ||
other | ☑ | @integer 11~26, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~1.9, 2.1~2.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
si | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0,1 or i=0 and f=1 | @integer 0, 1 @decimal 0.0, 0.1, 1.0, 0.00, 0.01, 1.00, 0.000, 0.001, 1.000, 0.0000, 0.0001, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.2~0.9, 1.1~1.8, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
sk | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
few | ☑ | i=2..4 and v=0 | @integer 2~4 | ||
many | ☑ | v!=0 | @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
sl | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 100=1 | @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, … | ||
two | ☑ | v=0 and i % 100=2 | @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, … | ||
few | ☑ | v=0 and i % 100=3..4 or v!=0 | @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
sma | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
smi | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
smj | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
smn | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
sms | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
two | ☑ | n=2 | @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000 | ||
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
sn | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
so | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
sq | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
many | ☑ | n % 10=4 and n % 100!=14 | @integer 4, 24, 34, 44, 54, 64, 74, 84, 104, 1004, … | ||
other | ☑ | @integer 0, 2, 3, 5~17, 100, 1000, 10000, 100000, 1000000, … | |||
sr | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 10=1 and i % 100!=11 or f % 10=1 and f % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, … | ||
few | ☑ | v=0 and i % 10=2..4 and i % 100!=12..14 or f % 10=2..4 and f % 100!=12..14 | @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 0.2~0.4, 1.2~1.4, 2.2~2.4, 3.2~3.4, 4.2~4.4, 5.2, 10.2, 100.2, 1000.2, … | ||
other | ☑ | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ss | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ssy | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
st | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
sv | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n % 10=1,2 and n % 100!=11,12 | @integer 1, 2, 21, 22, 31, 32, 41, 42, 51, 52, 61, 62, 71, 72, 81, 82, 101, 1001, … | |
other | ☑ | @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … | |||
sw | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
syr | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ta | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
te | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
teo | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
th | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ti | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
tig | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
tk | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
few | ☑ | n % 10=6,9 or n=10 | @integer 6, 9, 10, 16, 19, 26, 29, 36, 39, 106, 1006, … | ||
other | ☑ | @integer 0~5, 7, 8, 11~15, 17, 18, 20, 100, 1000, 10000, 100000, 1000000, … | |||
tl | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i=1,2,3 or v=0 and i % 10!=4,6,9 or v!=0 and f % 10!=4,6,9 | @integer 0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.3, 0.5, 0.7, 0.8, 1.0~1.3, 1.5, 1.7, 1.8, 2.0, 2.1, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | ||
other | ☑ | @integer 4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, … @decimal 0.4, 0.6, 0.9, 1.4, 1.6, 1.9, 2.4, 2.6, 10.4, 100.4, 1000.4, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
tn | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
to | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
tr | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
ts | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
tzm | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 or n=11..99 | @integer 0, 1, 11~24 @decimal 0.0, 1.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0 | ||
other | ☑ | @integer 2~10, 100~106, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ug | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
uk | cardinal | zero | ☐ | n=0 | |
one | ☑ | v=0 and i % 10=1 and i % 100!=11 | @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … | ||
few | ☑ | v=0 and i % 10=2..4 and i % 100!=12..14 | @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … | ||
many | ☑ | v=0 and i % 10=0 or v=0 and i % 10=5..9 or v=0 and i % 100=11..14 | @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … | ||
other | ☑ | @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
few | ☑ | n % 10=3 and n % 100!=13 | @integer 3, 23, 33, 43, 53, 63, 73, 83, 103, 1003, … | ||
other | ☑ | @integer 0~2, 4~16, 100, 1000, 10000, 100000, 1000000, … | |||
ur | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
uz | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
wa | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=0..1 | @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
wae | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ve | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
vi | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☑ | n=1 | @integer 1 | |
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … | |||
vo | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
wo | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
vun | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
xh | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
xog | cardinal | zero | ☐ | n=0 | |
one | ☑ | n=1 | @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
yi | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=1 and v=0 | @integer 1 | ||
other | ☑ | @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
yo | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
yue | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
zh | cardinal | zero | ☐ | n=0 | |
one | ☐ | n=1 | |||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … | |||
zu | cardinal | zero | ☐ | n=0 | |
one | ☑ | i=0 or n=1 | @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04 | ||
other | ☑ | @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, … | |||
ordinal | one | ☐ | n=1 | ||
other | ☑ | @integer 0~15, 100, 1000, 10000, 100000, 1000000, … |
This table is derived from plurals.xml and ordinals.xml of Unicode CLDR, and licensed as "Data files". Unicode CLDR is copyright of Unicode, Inc.
unicode-license.txt
text
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
See Terms of Use for definitions of Unicode Inc.'s
Data Files and Software.
NOTICE TO USER: Carefully read the following legal agreement.
BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
TERMS AND CONDITIONS OF THIS AGREEMENT.
IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
THE DATA FILES OR SOFTWARE.
COPYRIGHT AND PERMISSION NOTICE
Copyright © 1991-2019 Unicode, Inc. All rights reserved.
Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Unicode data files and any associated documentation
(the "Data Files") or Unicode software and any associated documentation
(the "Software") to deal in the Data Files or Software
without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, and/or sell copies of
the Data Files or Software, and to permit persons to whom the Data Files
or Software are furnished to do so, provided that either
(a) this copyright and permission notice appear with all copies
of the Data Files or Software, or
(b) this copyright and permission notice appear in associated
Documentation.
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in these Data Files or Software without prior
written authorization of the copyright holder.
# PluralRules Parameter To use plurality, the key must have "PluralRules" parameter either in the ILine or in the localization file. There are five ways to configure the plurality rule: 1. Add class name of plural rules into the localization file (recommended way). The value "Unicode.CLDR35" uses Unicode CLDR35 plural rules.
PluralRules="Unicode.CLDR35"
xml
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N"
xmlns="urn:lexical.fi"
PluralRules="Unicode.CLDR35">
<!-- Fallback string, for "" culture -->
<Key:Cats>{0} cat(s)</Key:Cats>
<!-- Translator added strings for "en" -->
<Key:Cats Culture="en">
{cardinal:0} cat(s)
<N:zero>no cats</N:zero>
<N:one>a cat</N:one>
<N:other>{0} cats</N:other>
</Key:Cats>
<!-- Translator added strings for "fi" -->
<Key:Cats Culture="fi">
{cardinal:0} kissa(a)
<N:zero>ei kissoja</N:zero>
<N:one>yksi kissa</N:one>
<N:other>{0} kissaa</N:other>
</Key:Cats>
</Localization>
2. Add plural rules expression to localization file. See Unicode CLDR Plural Rule Syntax.
PluralRules="[Category=cardinal,Case=one]n=1[Category=cardinal,Case=other]true"
xml
<?xml version="1.0" encoding="UTF-8"?>
<Localization xmlns:Culture="urn:lexical.fi:Culture"
xmlns:Key="urn:lexical.fi:Key"
xmlns:N="urn:lexical.fi:N" xmlns:N1="urn:lexical.fi:N1"
xmlns:N2="urn:lexical.fi:N2" xmlns:N3="urn:lexical.fi:N3"
xmlns="urn:lexical.fi"
PluralRules="[Category=cardinal,Case=zero,Optional=1]n=0[Category=cardinal,Case=one]n=1[Category=cardinal,Case=other]true">
<!-- Example: Plurality expression in the localization file ^^^ -->
<Key:CatsDogs>
{cardinal:0} cat(s) and {cardinal:1} dog(s)
<N:zero>
<N1:zero>no cats and no dogs</N1:zero>
<N1:one>no cats but one dog</N1:one>
<N1:other>no cats but {1} dogs</N1:other>
</N:zero>
<N:one>
<N1:zero>one cat but no dogs</N1:zero>
<N1:one>a cat and a dog</N1:one>
<N1:other>a cat and {1} dogs</N1:other>
</N:one>
<N:other>
<N1:zero>{0} cats but no dogs</N1:zero>
<N1:one>{0} cats and a dog</N1:one>
<N1:other>{0} cats and {1} dogs</N1:other>
</N:other>
</Key:CatsDogs>
</Localization>
3. Add instance of IPluralRules to line.
csharp
IPluralRules rules = PluralRulesResolver.Default.Resolve("Unicode.CLDR35");
ILine root = LineRoot.Global.PluralRules(rules);
4. Add class name of IPluralRules to line.
csharp
ILine root = LineRoot.Global.PluralRules("Unicode.CLDR35");
5. Add unicode plural rules expression to line. (Unicode CLDR Plural Rule Syntax)
csharp
ILine root = LineRoot.Global.PluralRules("[Category=cardinal,Case=zero,Optional=1]n=0[Category=cardinal,Case=one]n=1[Category=cardinal,Case=other]true");
# ICulturePolicy
ICulturePolicy is an interface for controlling the active culture and the fallback culture(s).
csharp
/// <summary>
/// Interface for policy that returns active culture policy, and fallback cultures.
/// </summary>
public interface ICulturePolicy
{
/// <summary>
/// Array property returns the prefered culture as first element.
/// Other cultures are considered fallback cultures.
///
/// For example: "en-UK", "en", "".
/// </summary>
CultureInfo[] Cultures { get; }
}
ICulturePolicyAssignable is interface for modifiable culture policy.
/// <summary>
/// Interface for policy that returns active culture policy, and fallback cultures.
/// </summary>
public interface ICulturePolicy
{
/// <summary>
/// Array property returns the prefered culture as first element.
/// Other cultures are considered fallback cultures.
///
/// For example: "en-UK", "en", "".
/// </summary>
CultureInfo[] Cultures { get; }
}
The default implementation is CulturePolicy.
// Create policy
ICulturePolicyAssignable culturePolicy = new CulturePolicy();
ICulturePolicy is assigned to localization root from where if affects the constructed keys.
// Create localization source
var source = new Dictionary<string, string> {
{ "MyController:hello", "Hello World!" },
{ "en:MyController:hello", "Hello World!" },
{ "de:MyController:hello", "Hallo Welt!" }
};
// Create asset with culture policy
IAsset asset = new StringAsset(source, LineParameterPrinter.Default);
// Create root and assign culturePolicy
ILineRoot root = new LineRoot(asset, culturePolicy);
Direct way to use CulturePolicy is to assign prefered culture and fallback culture on the provider instance. Typical fallback culture is the root culture "".
// Set active culture and set fallback culture
ICulturePolicy cultureArray_ =
new CulturePolicy().SetCultures(
CultureInfo.GetCultureInfo("en-US"),
CultureInfo.GetCultureInfo("en"),
CultureInfo.GetCultureInfo("")
);
They can also be assigned as strings.
// Create policy from array of cultures
ICulturePolicy culturePolicy = new CulturePolicy().SetCultures("en-US", "en", "");
.SetCultureWithFallbackCultures() assigns culture and its default fallback cultures.
// Create policy from culture, adds fallback cultures "en" and "".
ICulturePolicy culturePolicy = new CulturePolicy().SetCultureWithFallbackCultures("en-US");
Culture policy can be configured to use CultureInfo.CurrentCulture. Active culture can be controlled from that field.
// Set to use CultureInfo.CurrentCulture
ICulturePolicy culturePolicy = new CulturePolicy().SetToCurrentCulture();
// Change current culture
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en");
And CultureInfo.CurrentUICulture.
// Set to use CultureInfo.CurrentCulture
ICulturePolicy culturePolicy = new CulturePolicy().SetToCurrentUICulture();
// Change current culture
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en");
And also current thread's culture.
// Set to use CultureInfo.CurrentCulture
ICulturePolicy culturePolicy = new CulturePolicy().SetToCurrentThreadCulture();
// Change current thread's culture
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en");
// Set to use CultureInfo.CurrentCulture
ICulturePolicy culturePolicy = new CulturePolicy().SetToCurrentThreadUICulture();
// Change current thread's culture
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en");
.SetFunc() assigns a delegate that uses the returned CultureInfo.
// Assign delegate
ICulturePolicy culturePolicy = new CulturePolicy().SetFunc(() => CultureInfo.GetCultureInfo("fi"));
.SetSourceFunc() assigns a delegate that uses the returned ICulturePolicy.
// Assign delegate
ICulturePolicy source = new CulturePolicy().SetToCurrentUICulture();
ICulturePolicy culturePolicy = new CulturePolicy().SetSourceFunc(() => source);
.ToSnapshot() takes an array snapshot of the source, fixing its value. .AsReadonly() creates a new policy where the enumerable cannot be changed. Together these two make an immutable policy.
// Freeze current culture
ICulturePolicy culturePolicy = new CulturePolicy()
.SetToCurrentCulture()
.ToSnapshot()
.AsReadonly();
Resolve Examples
LineRoot.Global has a default CulturePolicy that uses the current thread's culture.
// Default CulturePolicy
Console.WriteLine(LineRoot.Global.Format("It is now {0:d} at {0:t}").Value(DateTime.Now));
This is similiar to C#'s String.Format.
// C#'s String.Format uses Thread.CurrentCulture
Console.WriteLine(String.Format("It is now {0:d} at {0:t}", DateTime.Now));
When explicit culture is appended to the ILine, then it overrides the culture in the ICulturePolicy.
// Format uses explicit CultureInfo "fi"
Console.WriteLine(LineRoot.Global.Format("It is now {0:d} at {0:t}").Value(DateTime.Now).Culture("fi"));
// Format uses explicit CultureInfo "sv"
Console.WriteLine(LineRoot.Global.Format("It is now {0:d} at {0:t}").Value(DateTime.Now).Culture("sv"));
// Format uses explicit CultureInfo "en"
Console.WriteLine(LineRoot.Global.Format("It is now {0:d} at {0:t}").Value(DateTime.Now).Culture("en"));
Links
IStringFormat
IStringFormat is interface for printers and parsers of string formats.
/// <summary>
/// String format of string value.
///
/// For example C# format that uses numbered arguments "{0[,parameters]}" that are written inside braces and have
/// parameters after number.
///
/// It has following sub-interfaces:
/// <list type="bullet">
/// <item><see cref="IStringFormatParser"/></item>
/// </list>
/// </summary>
public interface IStringFormat
{
/// <summary>
/// Name of the format name, e.g. "csharp", "c", or "lexical"
/// </summary>
string Name { get; }
}
/// <summary>
/// Parses arguments from format strings. Handles escaping.
///
/// For example "You received {caridnal:0} coin(s)." is a format string
/// that parsed into argument and non-argument sections.
/// </summary>
public interface IStringFormatParser : IStringFormat
{
/// <summary>
/// Parse format string into an <see cref="IString"/>.
///
/// If parse fails this method should return an instance where state is <see cref="LineStatus.StringFormatErrorMalformed"/>.
/// If parse succeeds, the returned instance has state <see cref="LineStatus.StringFormatOkString"/> or some other format state.
/// If <paramref name="str"/> is null then stat is <see cref="LineStatus.StringFormatFailedNull"/>.
/// </summary>
/// <param name="str"></param>
/// <returns>format string</returns>
IString Parse(string str);
}
/// <summary>
/// Prints <see cref="IString"/> into the format.
/// </summary>
public interface IStringFormatPrinter : IStringFormat
{
/// <summary>
/// Print <paramref name="str"/> into string that represents the notation of this <see cref="IStringFormat"/>.
///
/// If print fails status is:
/// <list type="bullet">
/// <item><see cref="LineStatus.StringFormatErrorPrintNoCapabilityPluralCategory"/></item>
/// <item><see cref="LineStatus.StringFormatErrorPrintNoCapabilityPlaceholder"/></item>
/// <item><see cref="LineStatus.StringFormatErrorPrintUnsupportedExpression"/></item>
/// <item><see cref="LineStatus.StringFormatFailed"/></item>
/// </list>
///
/// If formulated ok, status is <see cref="LineStatus.StringFormatOkString"/>.
/// </summary>
/// <param name="str"></param>
/// <returns>format string</returns>
LineString Print(IString str);
}
Implementations
Class | Description | Extension Method |
---|---|---|
CSharpFormat | Uses C# String.Format() notation. | ILine.Format(string) |
TextFormat | Uses plain text notation. | ILine.String(string) |
CSharpFormat
CSharpFormat.Default represents a string format that is similar to String.Format.
CSharpFormat.Default.Parse(string) parses placeholders from a string.
IStringFormat stringFormat = CSharpFormat.Default;
IString str = stringFormat.Parse("Hello, {0}.");
Extension method .Format(string) appends CSharpFormat string to ILine as "String" parameter.
ILine line = LineRoot.Global.Key("").Format("Hello, {0}.");
CSharpFormat uses following format. "Text {[pluralCategory:]argumentIndex:[,alignment][:format]} text".
It uses the following rules:
- Placeholders are inside braces and contain numbered arguments: "Hello {0} and {1}"
- Braces are escaped. "Control characters are \{\}."
- "format"-specifier is after : colon. "Hex value {0:X4}."
- PluralCategory is before : colon.
TextFormat
TextFormat.Default is a string format that contains plain text without placeholders. It doesn't need or use escaping.
IStringFormat stringFormat = TextFormat.Default;
IString str = stringFormat.Parse("{in braces}");
Extension method .Text(string) appends TextFormat string to ILine as "String" parameter.
ILine line = LineRoot.Global.Key("").Text("{in braces}");
Escaping
Two IStringFormats can be used for escaping and unescaping.
// Convert unescaped string "{not placeholder}" to IString
IString ss = TextFormat.Default.Parse("{not placeholder}");
// Escape with CSharpFormat to "\{not placeholder\}"
string str = CSharpFormat.Default.Print(ss);
// Convert escaped string back to IString
IString cs = CSharpFormat.Default.Parse(str);
// Unescape IString back to "{not placeholder}"
string tt = TextFormat.Default.Print(cs);
Resolving string
String is parsed into IString that contains placeholders and texts.
IStringFormat stringFormat = CSharpFormat.Default;
IString str = stringFormat.Parse("Hello, {0}.");
.String(string) extension method appends IString to ILine.
ILine line = LineRoot.Global.Key("Hello").String(str);
An argument is applied to placeholder {0} and resolved string is returned in a LineString record.
LineString lineString = line.Value("Corellia Melody").ResolveString();
If it resolved to an OK or non-Failed result, then the .Value can be used.
if (!lineString.Failed) Console.WriteLine(lineString.Value);