📜 ⬆️ ⬇️

C # implementation, Javascript: formatting function for convenient localization of strings

Habrayuzer afan in its topic Idea: the formatting function for the convenient localization of lines offered an interesting concept. What actually I decided to use in my engine.

So,

Of course, as an honest person, I read all the comments of this topic and found this list of formulas . To add support for the desired language, simply copy the formula from the list.
')
Then I decided to look for ready-made solutions. Found a solution from PawnHunter [C #] IFormatProvider for countable nouns . It is interesting plus there is a function of writing numbers in words. But the lack of complexity of adding languages. The author was originally attached to Russian and is looking for three forms of number according to the rule of Russian. He was lucky with English, because the first 2 forms are the same, and the third is not needed. Any other language with a great formula and number of forms will crash.

I did not look further, because there was enough material for my decision: an idea, formulas and a ready-made example.

The syntax of use.
C #:
NumeralsFormatter formatter = new NumeralsFormatter ( ) ; //
formatter. CultureInfo = new CultureInfo ( "ru-RU" ) ; //
Int32 files = 0 , folders = 5 ;
String exResult = String . Format ( formatter, "{0:W| |1 |% |% } {1:W|0 |1 |% |% }." , files, folders ) ; //
String shortResult = String . Format ( formatter, "{0:W|% (,,) (,,)} {1:W|% (,,}." , files, folders ) ; //



Javascript
// CultureInfo.name
var files = 0 , folders = 5 ;
var exResult = String. wformat ( "{0:W| |1 |% |% } {1:W|0 |1 |% |% }." , files , folders ) ; //
var shortResult = String. wformat ( "{0:W|% (,,) (,,)} {1:W|% (,,}." , files , folders ) ; //



As you can see, the syntax is taken from the original article, only the formatting is tailored to String.Format. Plus an abbreviated version borrowed from PawnHunter.
The% symbol is responsible for the substitution of a numeric value.

Pay attention to the following. In the extended version, word forms are passed one more for the zero value, which comes first. In the abbreviated form, there is no zero form; for it, the form is calculated by the formula.

To use special characters, such as | % they need to be duplicated || %%. For abbreviated form plus ((and)).

And in the end I give source codes.
using System ;
using System.Text ;
using System.Globalization ;

public class NumeralsFormatter : IFormatProvider, ICustomFormatter
{
public CultureInfo CultureInfo ;

public NumeralsFormatter ( ) : this ( System. Threading . Thread . CurrentThread . CurrentCulture ) { }
public NumeralsFormatter ( CultureInfo cultureInfo )
{
this . CultureInfo = cultureInfo ;
}
public Object GetFormat ( Type formatType )
{
return formatType == typeof ( ICustomFormatter ) ? this : CultureInfo. GetFormat ( formatType ) ;
}

private String FormatUnknown ( String format, Object arg, IFormatProvider formatProvider )
{
IFormattable formattable = arg as IFormattable ;
if ( formattable == null ) return arg. ToString ( ) ;
return formattable. ToString ( format, formatProvider ) ;
}

public Boolean IsNumeralType ( Type type )
{
return type == typeof ( Int32 )
|| type == typeof ( UInt32 )
|| type == typeof ( Double )
|| type == typeof ( Single )
|| type == typeof ( Decimal )
|| type == typeof ( Int64 )
|| type == typeof ( UInt64 )
|| type == typeof ( Int16 )
|| type == typeof ( UInt16 )
|| type == typeof ( Byte )
|| type == typeof ( SByte )
|| type == typeof ( Char ) ;
}

public String Format ( String format, Object arg, IFormatProvider formatProvider )
{
if ( format == null || ! IsNumeralType ( arg. GetType ( ) ) )
return FormatUnknown ( format, arg, formatProvider ) ;

String [ ] forms = format. Replace ( "||" , " \u fffc" ) . Split ( '|' ) ;
if ( forms [ 0 ] . ToUpper ( ) == "W" )
{
Int32 idxForm = - 1 ;
Double n = Math. Abs ( Convert. ToDouble ( arg ) ) ;

// translate.sourceforge.net/wiki/l10n/pluralforms
switch ( CultureInfo. Parent . Name )
{
case "en" : idxForm = ( n != 1 ? 1 : 0 ) ; break ;
case "ru" : idxForm = ( n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && ( n % 100 < 10 || n % 100 >= 20 ) ? 1 : 2 ) ; break ;
}

String form = null ;
if ( idxForm != - 1 )
{
if ( forms. Length > 2 ) // extended form
{
idxForm = n == 0 ? 1 : idxForm + 2 ;
form = forms [ idxForm ] . Replace ( ' \u fffc' , '|' ) ;
}
else if ( forms. Length > 1 )
{
StringBuilder sb = new StringBuilder ( ) ;
forms = forms [ 1 ] . Replace ( ' \u fffc' , '|' ) . Replace ( "((" , " \u fd3e" ) . Replace ( "))" , " \u fd3f" ) . Split ( '(' ) ;
int i = 0 ;
for ( ; i < forms. Length - 1 ; ++ i )
{
sb. Append ( forms [ i ] ) ;
Int32 rp = forms [ i + 1 ] . IndexOf ( ')' ) ;
if ( rp != - 1 )
{
sb. Append ( forms [ i + 1 ] . Substring ( 0 , rp ) . Split ( ',' ) [ idxForm ] ) ;
forms [ i + 1 ] = forms [ i + 1 ] . Substring ( rp + 1 ) ;
}
}
sb. Append ( forms [ i ] ) ;
form = sb. Replace ( ' \u fd3e' , '(' ) . Replace ( ' \u fd3f' , ')' ) . ToString ( ) ;
}
}
if ( form != null )
return form. Replace ( "%%" , " \u fffc" ) . Replace ( "%" , ( ( IFormattable ) arg ) . ToString ( null , CultureInfo ) ) . Replace ( ' \u fffc' , '%' ) ;
}
return FormatUnknown ( format, arg, formatProvider ) ;
}
}



String. wformat = function ( f )
{
var a = arguments ; return f. replace ( /{(\d+)(.*?)}/ig , function ( $ 0 , $ 1 , $ 2 )
{
var arg = a [ Number ( $ 1 ) + 1 ] ;
var n = Math. abs ( arg ) ;
if ( $ 2 && ! isNaN ( n ) )
{
var forms = $2. replace ( /\|\|/gm , ' \u fffc' ) . split ( '|' ) ;
if ( forms [ 0 ] . toUpperCase ( ) == ":W" )
{
var idxForm = - 1 ;
switch ( CultureInfo. name . split ( '-' ) [ 0 ] )
{
case "en" : idxForm = ( n != 1 ? 1 : 0 ) ; break ;
case "ru" : idxForm = ( n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && ( n % 100 < 10 || n % 100 >= 20 ) ? 1 : 2 ) ; break ;
}

var form = null ;
if ( idxForm != - 1 )
{
if ( forms. length > 2 ) // extended form
{
idxForm = n == 0 ? 1 : idxForm + 2 ;
form = forms [ idxForm ] . replace ( /\ufffc/gm , '|' ) ;
}
else if ( forms. length > 1 )
{
var sb = [ ] ;
forms = forms [ 1 ] . replace ( /\ufffc/gm , '|' ) . replace ( /\(\(/gm , ' \u fd3e' ) . replace ( /\)\)/gm , ' \u fd3f' ) . split ( '(' ) ;
var i = 0 ;
for ( ; i < forms. length - 1 ; ++ i )
{
sb. push ( forms [ i ] ) ;
var rp = forms [ i + 1 ] . indexOf ( ')' ) ;
if ( rp != - 1 )
{
sb. push ( forms [ i + 1 ] . substring ( 0 , rp ) . split ( ',' ) [ idxForm ] ) ;
forms [ i + 1 ] = forms [ i + 1 ] . substring ( rp + 1 ) ;
}
}
sb. push ( forms [ i ] ) ;
form = sb. join ( '' ) . replace ( /\ufd3e/gm , '(' ) . replace ( /\ufd3f/gm , ')' ) ;
}
}
if ( form != null )
return form. replace ( /%%/gm , ' \u fffc' ) . replace ( /%/gm , arg ) . replace ( /\ufffc/gm , '%' ) ;
}
}
return arg ;
} ) ;
}



______________________
The text was prepared in the Habr Editor from © SoftCoder.ru

Source: https://habr.com/ru/post/55742/


All Articles